diff --git a/coverage-badge.svg b/coverage-badge.svg index 3138aa8..1dac990 100644 --- a/coverage-badge.svg +++ b/coverage-badge.svg @@ -2,5 +2,5 @@ coverage - 29.0% + 38.6% diff --git a/internal/controllers/taskcontroller/controller.go b/internal/controllers/taskcontroller/controller.go index 4428976..bc5eee3 100644 --- a/internal/controllers/taskcontroller/controller.go +++ b/internal/controllers/taskcontroller/controller.go @@ -1,14 +1,20 @@ package taskcontroller import ( + "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/models" "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/services/taskservice" ) -type TaskController struct { - taskService *taskservice.Service +type TaskService interface { + Create(repo string) (*models.Task, error) + Upload(input *taskservice.TaskUploadInput) error } -func New(taskService *taskservice.Service) *TaskController { +type TaskController struct { + taskService TaskService +} + +func New(taskService TaskService) *TaskController { return &TaskController{ taskService: taskService, } diff --git a/internal/controllers/taskcontroller/controller_test.go b/internal/controllers/taskcontroller/controller_test.go new file mode 100644 index 0000000..f00b9a7 --- /dev/null +++ b/internal/controllers/taskcontroller/controller_test.go @@ -0,0 +1,27 @@ +package taskcontroller_test + +import ( + "errors" + + "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/models" + "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/services/taskservice" +) + +type TaskServiceMock struct { + CreateFunc func(string) (*models.Task, error) + UploadFunc func(*taskservice.TaskUploadInput) error +} + +func (s *TaskServiceMock) Create(repo string) (*models.Task, error) { + if s.CreateFunc != nil { + return s.CreateFunc(repo) + } + return nil, errors.New("not implemented") +} + +func (s *TaskServiceMock) Upload(input *taskservice.TaskUploadInput) error { + if s.UploadFunc != nil { + return s.UploadFunc(input) + } + return errors.New("not implemented") +} diff --git a/internal/controllers/taskcontroller/create_test.go b/internal/controllers/taskcontroller/create_test.go new file mode 100644 index 0000000..464290e --- /dev/null +++ b/internal/controllers/taskcontroller/create_test.go @@ -0,0 +1,84 @@ +package taskcontroller_test + +import ( + "bytes" + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "testing" + + "gorm.io/gorm" + + "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/controllers/taskcontroller" + "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/models" +) + +func TestCreate(t *testing.T) { + tests := []struct { + name string + inputBody interface{} + mockService *TaskServiceMock + expectedStatus int + }{ + { + name: "Valid request", + inputBody: map[string]string{ + "repo": "example-foo", + }, + mockService: &TaskServiceMock{ + CreateFunc: func(repo string) (*models.Task, error) { + return &models.Task{ + Model: gorm.Model{ + ID: 1, + }, + Status: models.StatusInProgress, + }, nil + }, + }, + expectedStatus: http.StatusOK, + }, + { + name: "Invalid JSON", + inputBody: "invalid-json", + mockService: &TaskServiceMock{}, + expectedStatus: http.StatusBadRequest, + }, + { + name: "Service error", + inputBody: map[string]string{ + "repo": "example-foo", + }, + mockService: &TaskServiceMock{ + CreateFunc: func(repo string) (*models.Task, error) { + return nil, errors.New("internal error") + }, + }, + expectedStatus: http.StatusInternalServerError, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + controller := taskcontroller.New(tt.mockService) + + var body []byte + if tt.inputBody != nil { + body, _ = json.Marshal(tt.inputBody) + } + + req, err := http.NewRequest(http.MethodPost, "/", bytes.NewBuffer(body)) + if err != nil { + t.Fatalf("Failed to create request: %v", err) + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(controller.Create) + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != tt.expectedStatus { + t.Errorf("handler returned wrong status code: got %v want %v", status, tt.expectedStatus) + } + }) + } +} diff --git a/internal/controllers/taskcontroller/upload_test.go b/internal/controllers/taskcontroller/upload_test.go new file mode 100644 index 0000000..87a5030 --- /dev/null +++ b/internal/controllers/taskcontroller/upload_test.go @@ -0,0 +1,107 @@ +package taskcontroller_test + +import ( + "bytes" + "errors" + "mime/multipart" + "net/http" + "net/http/httptest" + "testing" + + "github.com/go-chi/chi/v5" + + "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/controllers/taskcontroller" + "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/services/taskservice" +) + +func TestUpload(t *testing.T) { + tests := []struct { + name string + taskID string + files []byte + mockService *TaskServiceMock + expectedStatus int + }{ + { + name: "Valid upload", + taskID: "1", + files: []byte("test file content"), // можно заменить на реальный файл, если нужно + mockService: &TaskServiceMock{ + UploadFunc: func(input *taskservice.TaskUploadInput) error { + return nil + }, + }, + expectedStatus: http.StatusOK, + }, + { + name: "Invalid taskID", + taskID: "", + files: []byte("test file content"), + mockService: &TaskServiceMock{}, + expectedStatus: http.StatusBadRequest, + }, + /* + TODO: + + { + name: "File too large", + taskID: "1", + files: []byte("test file content"), + mockService: &TaskServiceMock{ + UploadFunc: func(input *taskservice.TaskUploadInput) error { + return nil + }, + }, + expectedStatus: http.StatusBadRequest, + }, + */ + { + name: "Error during file upload", + taskID: "1", + files: []byte("test file content"), + mockService: &TaskServiceMock{ + UploadFunc: func(input *taskservice.TaskUploadInput) error { + return errors.New("internal upload error") + }, + }, + expectedStatus: http.StatusInternalServerError, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + controller := taskcontroller.New(tt.mockService) + + r := chi.NewRouter() + r.Post("/tasks/{taskID}/upload", controller.Upload) + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + part, err := writer.CreateFormFile("files", "file.txt") + if err != nil { + t.Fatalf("Failed to create form file: %v", err) + } + part.Write(tt.files) + writer.Close() + + ts := httptest.NewServer(r) + defer ts.Close() + + req, err := http.NewRequest(http.MethodPost, ts.URL+"/tasks/"+tt.taskID+"/upload", body) + if err != nil { + t.Fatalf("Failed to create request: %v", err) + } + req.Header.Set("Content-Type", writer.FormDataContentType()) + + resp, err := ts.Client().Do(req) + if err != nil { + t.Fatalf("Failed to execute request: %v", err) + } + defer resp.Body.Close() + + if status := resp.StatusCode; status != tt.expectedStatus { + t.Errorf("handler returned wrong status code: got %v want %v", status, tt.expectedStatus) + } + }) + } +}