238 lines
7.7 KiB
Go
238 lines
7.7 KiB
Go
package services_test
|
|
|
|
import (
|
|
"regexp"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/DATA-DOG/go-sqlmock"
|
|
"github.com/rede5/gohorsejobs/backend/internal/dto"
|
|
"github.com/rede5/gohorsejobs/backend/internal/services"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestCreateJob(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
service := services.NewJobService(db)
|
|
|
|
tests := []struct {
|
|
name string
|
|
req dto.CreateJobRequest
|
|
mockRun func()
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "Success",
|
|
req: dto.CreateJobRequest{
|
|
CompanyID: "1",
|
|
Title: "Go Developer",
|
|
Status: "published",
|
|
},
|
|
mockRun: func() {
|
|
mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO jobs`)).
|
|
WithArgs("1", "user-123", "Go Developer", sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), "published", sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg()).
|
|
WillReturnRows(sqlmock.NewRows([]string{"id", "date_posted", "created_at", "updated_at"}).AddRow("100", time.Now(), time.Now(), time.Now()))
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "DB Error",
|
|
req: dto.CreateJobRequest{
|
|
CompanyID: "1",
|
|
Title: "Go Developer",
|
|
},
|
|
mockRun: func() {
|
|
mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO jobs`)).
|
|
WillReturnError(assert.AnError)
|
|
},
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.mockRun()
|
|
got, err := service.CreateJob(tt.req, "user-123")
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("JobService.CreateJob() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !tt.wantErr {
|
|
assert.Equal(t, "100", got.ID)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetJobs(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
service := services.NewJobService(db)
|
|
|
|
tests := []struct {
|
|
name string
|
|
filter dto.JobFilterQuery
|
|
mockRun func()
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "List All",
|
|
filter: dto.JobFilterQuery{
|
|
PaginationQuery: dto.PaginationQuery{Page: 1, Limit: 10},
|
|
},
|
|
mockRun: func() {
|
|
// List query
|
|
mock.ExpectQuery(regexp.QuoteMeta(`SELECT
|
|
j.id, j.company_id, j.title, j.description, j.salary_min, j.salary_max, j.salary_type,
|
|
j.employment_type, j.work_mode, j.working_hours, j.location, j.status, j.salary_negotiable, j.is_featured, COALESCE(j.date_posted, j.created_at) AS date_posted, j.created_at, j.updated_at,
|
|
CASE
|
|
WHEN c.type = 'CANDIDATE_WORKSPACE' OR c.name LIKE 'Candidate - %' THEN ''
|
|
ELSE COALESCE(c.name, '')
|
|
END as company_name, c.logo_url as company_logo_url,
|
|
r.name as region_name, ci.name as city_name,
|
|
j.view_count, j.featured_until,
|
|
(SELECT COUNT(*) FROM applications a WHERE a.job_id = j.id) as applications_count
|
|
FROM jobs j
|
|
LEFT JOIN companies c ON j.company_id = c.id
|
|
LEFT JOIN states r ON j.region_id = r.id
|
|
LEFT JOIN cities ci ON j.city_id = ci.id
|
|
WHERE 1=1`)).
|
|
WillReturnRows(sqlmock.NewRows([]string{
|
|
"id", "company_id", "title", "description", "salary_min", "salary_max", "salary_type",
|
|
"employment_type", "work_mode", "working_hours", "location", "status", "salary_negotiable", "is_featured", "date_posted", "created_at", "updated_at",
|
|
"company_name", "company_logo_url", "region_name", "city_name", "view_count", "featured_until", "applications_count",
|
|
}).AddRow(
|
|
"1", "10", "Dev", "Desc", 100, 200, "m", "ft", "Remote", "40h", "Remote", "open", true, false, time.Now(), time.Now(), time.Now(),
|
|
"Acme", "url", "Region", "City", 0, nil, 0,
|
|
))
|
|
|
|
// Count query
|
|
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM jobs j WHERE 1=1`)).
|
|
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(2))
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.mockRun()
|
|
_, _, err := service.GetJobs(tt.filter)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("JobService.GetJobs() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
})
|
|
}
|
|
}
|
|
func TestGetJobByID(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
service := services.NewJobService(db)
|
|
|
|
jobID := "100"
|
|
|
|
rows := sqlmock.NewRows([]string{
|
|
"id", "company_id", "title", "description", "salary_min", "salary_max", "salary_type",
|
|
"employment_type", "working_hours", "location", "region_id", "city_id",
|
|
"requirements", "benefits", "visa_support", "language_level", "status", "is_featured", "featured_until", "view_count", "date_posted", "created_at", "updated_at",
|
|
"salary_negotiable", "currency", "work_mode",
|
|
}).AddRow(
|
|
jobID, 1, "Title", "Desc", 100, 200, "m",
|
|
"ft", "40h", "Remote", 0, 0,
|
|
nil, nil, false, "N2", "open", false, nil, 0, time.Now(), time.Now(), time.Now(),
|
|
false, "USD", "remote",
|
|
)
|
|
|
|
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, company_id`)).
|
|
WithArgs(jobID).
|
|
WillReturnRows(rows)
|
|
|
|
job, err := service.GetJobByID(jobID)
|
|
if err != nil {
|
|
t.Errorf("GetJobByID() error = %v", err)
|
|
return
|
|
}
|
|
if job == nil || job.ID != jobID {
|
|
t.Errorf("GetJobByID() got = %v, want ID %s", job, jobID)
|
|
}
|
|
}
|
|
|
|
func TestUpdateJob(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
service := services.NewJobService(db)
|
|
jobID := "100"
|
|
newTitle := "New Title"
|
|
|
|
req := dto.UpdateJobRequest{
|
|
Title: &newTitle,
|
|
}
|
|
|
|
// Expect UPDATE with RETURNING
|
|
mock.ExpectQuery(regexp.QuoteMeta(`UPDATE jobs SET title = $1, updated_at = NOW() WHERE id = $2 RETURNING id, updated_at`)).
|
|
WithArgs(newTitle, jobID).
|
|
WillReturnRows(sqlmock.NewRows([]string{"id", "updated_at"}).AddRow(jobID, time.Now()))
|
|
|
|
rows := sqlmock.NewRows([]string{
|
|
"id", "company_id", "title", "description", "salary_min", "salary_max", "salary_type",
|
|
"employment_type", "working_hours", "location", "region_id", "city_id",
|
|
"requirements", "benefits", "visa_support", "language_level", "status", "is_featured", "featured_until", "view_count", "date_posted", "created_at", "updated_at",
|
|
"salary_negotiable", "currency", "work_mode",
|
|
}).AddRow(
|
|
jobID, 1, newTitle, "Desc", 100, 200, "m",
|
|
"ft", "40h", "Remote", 0, 0,
|
|
nil, nil, false, "N2", "open", false, nil, 0, time.Now(), time.Now(), time.Now(),
|
|
false, "USD", "remote",
|
|
)
|
|
|
|
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, company_id`)).
|
|
WithArgs(jobID).
|
|
WillReturnRows(rows)
|
|
|
|
job, err := service.UpdateJob(jobID, req)
|
|
if err != nil {
|
|
t.Errorf("UpdateJob() error = %v", err)
|
|
return
|
|
}
|
|
if job.Title != newTitle {
|
|
t.Errorf("UpdateJob() title = %s, want %s", job.Title, newTitle)
|
|
}
|
|
}
|
|
|
|
func TestDeleteJob(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
service := services.NewJobService(db)
|
|
jobID := "100"
|
|
|
|
mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM jobs WHERE id = $1`)).
|
|
WithArgs(jobID).
|
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
|
|
|
err = service.DeleteJob(jobID)
|
|
if err != nil {
|
|
t.Errorf("DeleteJob() error = %v", err)
|
|
}
|
|
}
|