252 lines
6.7 KiB
Go
252 lines
6.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/rede5/gohorsejobs/backend/internal/api/middleware"
|
|
"github.com/rede5/gohorsejobs/backend/internal/dto"
|
|
"github.com/rede5/gohorsejobs/backend/internal/models"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// mockJobService is a mock implementation of the job service for testing
|
|
type mockJobService struct {
|
|
getJobsFunc func(filter dto.JobFilterQuery) ([]models.JobWithCompany, int, error)
|
|
createJobFunc func(req dto.CreateJobRequest, createdBy string) (*models.Job, error)
|
|
getJobByIDFunc func(id string) (*models.Job, error)
|
|
updateJobFunc func(id string, req dto.UpdateJobRequest) (*models.Job, error)
|
|
deleteJobFunc func(id string) error
|
|
}
|
|
|
|
func (m *mockJobService) GetJobs(filter dto.JobFilterQuery) ([]models.JobWithCompany, int, error) {
|
|
if m.getJobsFunc != nil {
|
|
return m.getJobsFunc(filter)
|
|
}
|
|
return nil, 0, nil
|
|
}
|
|
|
|
func (m *mockJobService) CreateJob(req dto.CreateJobRequest, createdBy string) (*models.Job, error) {
|
|
if m.createJobFunc != nil {
|
|
return m.createJobFunc(req, createdBy)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockJobService) GetJobByID(id string) (*models.Job, error) {
|
|
if m.getJobByIDFunc != nil {
|
|
return m.getJobByIDFunc(id)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockJobService) UpdateJob(id string, req dto.UpdateJobRequest) (*models.Job, error) {
|
|
if m.updateJobFunc != nil {
|
|
return m.updateJobFunc(id, req)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockJobService) DeleteJob(id string) error {
|
|
if m.deleteJobFunc != nil {
|
|
return m.deleteJobFunc(id)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func TestGetJobs_Success(t *testing.T) {
|
|
mockService := &mockJobService{
|
|
getJobsFunc: func(filter dto.JobFilterQuery) ([]models.JobWithCompany, int, error) {
|
|
return []models.JobWithCompany{
|
|
{
|
|
Job: models.Job{ID: "1", Title: "Software Engineer", Status: "open"},
|
|
CompanyName: "TestCorp",
|
|
},
|
|
{
|
|
Job: models.Job{ID: "2", Title: "DevOps", Status: "open"},
|
|
CompanyName: "TestCorp",
|
|
},
|
|
}, 2, nil
|
|
},
|
|
}
|
|
|
|
handler := NewJobHandler(mockService)
|
|
req := httptest.NewRequest("GET", "/jobs", nil)
|
|
rr := httptest.NewRecorder()
|
|
|
|
handler.GetJobs(rr, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rr.Code)
|
|
|
|
var response dto.PaginatedResponse
|
|
err := json.Unmarshal(rr.Body.Bytes(), &response)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, response.Pagination.Total)
|
|
}
|
|
|
|
func TestGetJobs_ParsesCareerjetAliases(t *testing.T) {
|
|
mockService := &mockJobService{
|
|
getJobsFunc: func(filter dto.JobFilterQuery) ([]models.JobWithCompany, int, error) {
|
|
if assert.NotNil(t, filter.Search) {
|
|
assert.Equal(t, "software engineer", *filter.Search)
|
|
}
|
|
if assert.NotNil(t, filter.Location) {
|
|
assert.Equal(t, "Sao Paulo", *filter.Location)
|
|
}
|
|
if assert.NotNil(t, filter.LocationSearch) {
|
|
assert.Equal(t, "Sao Paulo", *filter.LocationSearch)
|
|
}
|
|
return []models.JobWithCompany{}, 0, nil
|
|
},
|
|
}
|
|
|
|
handler := NewJobHandler(mockService)
|
|
req := httptest.NewRequest("GET", "/jobs?s=software+engineer&l=Sao+Paulo", nil)
|
|
rr := httptest.NewRecorder()
|
|
|
|
handler.GetJobs(rr, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestCreateJob_Success(t *testing.T) {
|
|
mockService := &mockJobService{
|
|
createJobFunc: func(req dto.CreateJobRequest, createdBy string) (*models.Job, error) {
|
|
assert.Equal(t, "user-123", createdBy)
|
|
if assert.NotNil(t, req.WorkMode) {
|
|
assert.Equal(t, "remote", *req.WorkMode)
|
|
}
|
|
return &models.Job{
|
|
ID: "1",
|
|
Title: req.Title,
|
|
Status: "open",
|
|
WorkMode: req.WorkMode,
|
|
}, nil
|
|
},
|
|
}
|
|
|
|
handler := NewJobHandler(mockService)
|
|
|
|
jobReq := dto.CreateJobRequest{
|
|
CompanyID: "1",
|
|
Title: "Backend Developer",
|
|
Description: "Build awesome APIs",
|
|
Status: "open",
|
|
WorkMode: func() *string { s := "remote"; return &s }(),
|
|
}
|
|
body, _ := json.Marshal(jobReq)
|
|
|
|
req := httptest.NewRequest("POST", "/jobs", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
// Inject Context
|
|
ctx := context.WithValue(req.Context(), middleware.ContextUserID, "user-123")
|
|
req = req.WithContext(ctx)
|
|
|
|
rr := httptest.NewRecorder()
|
|
|
|
handler.CreateJob(rr, req)
|
|
|
|
assert.Equal(t, http.StatusCreated, rr.Code)
|
|
|
|
var job models.Job
|
|
err := json.Unmarshal(rr.Body.Bytes(), &job)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "Backend Developer", job.Title)
|
|
if assert.NotNil(t, job.WorkMode) {
|
|
assert.Equal(t, "remote", *job.WorkMode)
|
|
}
|
|
}
|
|
|
|
func TestCreateJob_ServiceError(t *testing.T) {
|
|
mockService := &mockJobService{
|
|
createJobFunc: func(req dto.CreateJobRequest, createdBy string) (*models.Job, error) {
|
|
return nil, errors.New("db error")
|
|
},
|
|
}
|
|
|
|
handler := NewJobHandler(mockService)
|
|
|
|
jobReq := dto.CreateJobRequest{
|
|
Title: "Failing Job",
|
|
}
|
|
body, _ := json.Marshal(jobReq)
|
|
|
|
req := httptest.NewRequest("POST", "/jobs", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
ctx := context.WithValue(req.Context(), middleware.ContextUserID, "user-123")
|
|
req = req.WithContext(ctx)
|
|
|
|
rr := httptest.NewRecorder()
|
|
|
|
handler.CreateJob(rr, req)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, rr.Code)
|
|
}
|
|
|
|
func TestGetJobByID_Success(t *testing.T) {
|
|
mockService := &mockJobService{
|
|
getJobByIDFunc: func(id string) (*models.Job, error) {
|
|
return &models.Job{ID: id, Title: "Software Engineer"}, nil
|
|
},
|
|
}
|
|
|
|
handler := NewJobHandler(mockService)
|
|
|
|
req := httptest.NewRequest("GET", "/jobs/1", nil)
|
|
req.SetPathValue("id", "1")
|
|
rr := httptest.NewRecorder()
|
|
|
|
handler.GetJobByID(rr, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rr.Code)
|
|
}
|
|
|
|
func TestDeleteJob_Success(t *testing.T) {
|
|
mockService := &mockJobService{
|
|
deleteJobFunc: func(id string) error {
|
|
return nil
|
|
},
|
|
}
|
|
|
|
handler := NewJobHandler(mockService)
|
|
|
|
req := httptest.NewRequest("DELETE", "/jobs/1", nil)
|
|
req.SetPathValue("id", "1")
|
|
rr := httptest.NewRecorder()
|
|
|
|
handler.DeleteJob(rr, req)
|
|
|
|
assert.Equal(t, http.StatusNoContent, rr.Code)
|
|
}
|
|
|
|
func TestUpdateJob_Success(t *testing.T) {
|
|
workMode := "hybrid"
|
|
mockService := &mockJobService{
|
|
updateJobFunc: func(id string, req dto.UpdateJobRequest) (*models.Job, error) {
|
|
if assert.NotNil(t, req.WorkMode) {
|
|
assert.Equal(t, workMode, *req.WorkMode)
|
|
}
|
|
return &models.Job{ID: id, Title: "Updated"}, nil
|
|
},
|
|
}
|
|
handler := NewJobHandler(mockService)
|
|
|
|
reqBody, _ := json.Marshal(dto.UpdateJobRequest{Title: func() *string { s := "Updated"; return &s }()}) // Inline pointer helper not clean but works or define var
|
|
|
|
// Cleaner
|
|
title := "Updated"
|
|
reqBody, _ = json.Marshal(dto.UpdateJobRequest{Title: &title, WorkMode: &workMode})
|
|
|
|
req := httptest.NewRequest("PUT", "/jobs/1", bytes.NewReader(reqBody))
|
|
req.SetPathValue("id", "1")
|
|
rr := httptest.NewRecorder()
|
|
|
|
handler.UpdateJob(rr, req)
|
|
assert.Equal(t, http.StatusOK, rr.Code)
|
|
}
|