nomadcode/services/core/internal/http/handlers_test.go

119 lines
3.5 KiB
Go

package http
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/nomadcode/nomadcode-core/internal/storage"
"github.com/nomadcode/nomadcode-core/internal/workitem"
"github.com/nomadcode/nomadcode-core/internal/workitempipeline"
)
type fakeWorkItemTaskCreator struct {
task storage.Task
err error
calledWith *workitempipeline.CreateTaskInput
}
func (f *fakeWorkItemTaskCreator) CreateTaskFromWorkItem(_ context.Context, input workitempipeline.CreateTaskInput) (storage.Task, error) {
f.calledWith = &input
return f.task, f.err
}
func TestPlaneTaskRequestBuildsProviderNeutralRef(t *testing.T) {
req := createPlaneTaskRequest{
WorkspaceSlug: " acme ",
ProjectID: " proj-1 ",
WorkItemID: " work-1 ",
ExternalURL: " https://plane.example/work-1 ",
}
ref, err := req.workItemRef()
if err != nil {
t.Fatalf("workItemRef returned error: %v", err)
}
if ref.Provider != workitem.ProviderID("plane") {
t.Errorf("provider: got %q", ref.Provider)
}
if ref.Tenant != "acme" {
t.Errorf("tenant: got %q", ref.Tenant)
}
if ref.Project != "proj-1" {
t.Errorf("project: got %q", ref.Project)
}
if ref.ID != "work-1" {
t.Errorf("id: got %q", ref.ID)
}
if ref.URL != "https://plane.example/work-1" {
t.Errorf("url: got %q", ref.URL)
}
}
func TestCreatePlaneTaskDelegatesToWorkItemPipeline(t *testing.T) {
creator := &fakeWorkItemTaskCreator{
task: storage.Task{ID: "task-123", Status: "pending"},
}
h := &Handler{workItemTasks: creator}
body := `{"workspace_slug":"acme","project_id":"proj-1","work_item_id":"work-1","state_id":"state-1","comment":"my note"}`
req := httptest.NewRequest(http.MethodPost, "/api/integrations/plane/tasks", strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()
h.CreatePlaneTask(rec, req)
if rec.Code != http.StatusCreated {
t.Fatalf("expected %d, got %d: %s", http.StatusCreated, rec.Code, rec.Body.String())
}
if creator.calledWith == nil {
t.Fatal("CreateTaskFromWorkItem was not called")
}
if creator.calledWith.Ref.Provider != "plane" {
t.Errorf("ref.provider: got %q", creator.calledWith.Ref.Provider)
}
if creator.calledWith.Ref.Tenant != "acme" {
t.Errorf("ref.tenant: got %q", creator.calledWith.Ref.Tenant)
}
if creator.calledWith.Ref.Project != "proj-1" {
t.Errorf("ref.project: got %q", creator.calledWith.Ref.Project)
}
if creator.calledWith.Ref.ID != "work-1" {
t.Errorf("ref.id: got %q", creator.calledWith.Ref.ID)
}
if creator.calledWith.StateID != "state-1" {
t.Errorf("state_id: got %q", creator.calledWith.StateID)
}
if creator.calledWith.Comment != "my note" {
t.Errorf("comment: got %q", creator.calledWith.Comment)
}
var resp map[string]string
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
t.Fatalf("decode response: %v", err)
}
if resp["id"] != "task-123" || resp["status"] != "pending" {
t.Errorf("response: %v", resp)
}
}
func TestCreatePlaneTaskReturns503WhenPipelineNotConfigured(t *testing.T) {
h := &Handler{}
req := httptest.NewRequest(http.MethodPost, "/api/integrations/plane/tasks", strings.NewReader(`{}`))
rec := httptest.NewRecorder()
h.CreatePlaneTask(rec, req)
if rec.Code != http.StatusServiceUnavailable {
t.Fatalf("expected 503, got %d", rec.Code)
}
var resp map[string]string
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
t.Fatalf("decode response: %v", err)
}
if resp["error"] != "plane client is not configured" {
t.Errorf("error message: got %q", resp["error"])
}
}