package service import ( "context" "testing" "github.com/orchard9/rdev/internal/domain" ) func newTestWorkService() (*WorkService, *mockWorkQueue) { q := newMockWorkQueue() svc := NewWorkService(q) return svc, q } func TestWorkService_EnqueueTask(t *testing.T) { t.Run("success", func(t *testing.T) { svc, q := newTestWorkService() result, err := svc.EnqueueTask(context.Background(), EnqueueTaskRequest{ ProjectID: "myapp", Type: domain.WorkTaskTypeBuild, Priority: 1, Spec: map[string]any{"branch": "main"}, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if result.TaskID == "" { t.Error("task ID should not be empty") } if result.StatusURL == "" { t.Error("status URL should not be empty") } if len(q.tasks) != 1 { t.Errorf("tasks in queue = %d, want 1", len(q.tasks)) } }) t.Run("default max retries", func(t *testing.T) { svc, q := newTestWorkService() _, err := svc.EnqueueTask(context.Background(), EnqueueTaskRequest{ ProjectID: "myapp", Type: domain.WorkTaskTypeBuild, }) if err != nil { t.Fatalf("unexpected error: %v", err) } for _, task := range q.tasks { if task.MaxRetries != 3 { t.Errorf("max retries = %d, want 3 (default)", task.MaxRetries) } } }) t.Run("missing project id", func(t *testing.T) { svc, _ := newTestWorkService() _, err := svc.EnqueueTask(context.Background(), EnqueueTaskRequest{ Type: domain.WorkTaskTypeBuild, }) if err == nil { t.Error("expected error for missing project_id") } }) t.Run("missing type", func(t *testing.T) { svc, _ := newTestWorkService() _, err := svc.EnqueueTask(context.Background(), EnqueueTaskRequest{ ProjectID: "myapp", }) if err == nil { t.Error("expected error for missing type") } }) } func TestWorkService_DequeueTask(t *testing.T) { t.Run("success", func(t *testing.T) { svc, q := newTestWorkService() // Enqueue a task first q.tasks["task-1"] = &domain.WorkTask{ ID: "task-1", ProjectID: "myapp", Type: domain.WorkTaskTypeBuild, Status: domain.WorkTaskStatusPending, } task, err := svc.DequeueTask(context.Background(), "worker-1") if err != nil { t.Fatalf("unexpected error: %v", err) } if task == nil { t.Fatal("expected a task, got nil") } if task.ID != "task-1" { t.Errorf("task ID = %q, want %q", task.ID, "task-1") } if task.Status != domain.WorkTaskStatusRunning { t.Errorf("task status = %q, want %q", task.Status, domain.WorkTaskStatusRunning) } }) t.Run("empty queue", func(t *testing.T) { svc, _ := newTestWorkService() task, err := svc.DequeueTask(context.Background(), "worker-1") if err != nil { t.Fatalf("unexpected error: %v", err) } if task != nil { t.Error("expected nil task for empty queue") } }) t.Run("missing worker id", func(t *testing.T) { svc, _ := newTestWorkService() _, err := svc.DequeueTask(context.Background(), "") if err == nil { t.Error("expected error for missing worker_id") } }) } func TestWorkService_CompleteTask(t *testing.T) { t.Run("success", func(t *testing.T) { svc, q := newTestWorkService() q.tasks["task-1"] = &domain.WorkTask{ ID: "task-1", ProjectID: "myapp", Type: domain.WorkTaskTypeBuild, Status: domain.WorkTaskStatusRunning, } result := &domain.WorkResult{Output: "ok"} err := svc.CompleteTask(context.Background(), "task-1", result) if err != nil { t.Fatalf("unexpected error: %v", err) } task := q.tasks["task-1"] if task.Status != domain.WorkTaskStatusCompleted { t.Errorf("status = %q, want %q", task.Status, domain.WorkTaskStatusCompleted) } }) t.Run("task not found", func(t *testing.T) { svc, _ := newTestWorkService() err := svc.CompleteTask(context.Background(), "nonexistent", nil) if err == nil { t.Error("expected error for nonexistent task") } }) } func TestWorkService_GetTask(t *testing.T) { t.Run("found", func(t *testing.T) { svc, q := newTestWorkService() q.tasks["task-1"] = &domain.WorkTask{ ID: "task-1", ProjectID: "myapp", } task, err := svc.GetTask(context.Background(), "task-1") if err != nil { t.Fatalf("unexpected error: %v", err) } if task.ID != "task-1" { t.Errorf("task ID = %q, want %q", task.ID, "task-1") } }) t.Run("not found", func(t *testing.T) { svc, _ := newTestWorkService() _, err := svc.GetTask(context.Background(), "missing") if err == nil { t.Error("expected error for missing task") } }) } func TestWorkService_GetStats(t *testing.T) { svc, _ := newTestWorkService() stats, err := svc.GetStats(context.Background()) if err != nil { t.Fatalf("unexpected error: %v", err) } if stats == nil { t.Error("stats should not be nil") } } func TestWorkService_CancelTask(t *testing.T) { svc, q := newTestWorkService() q.tasks["task-1"] = &domain.WorkTask{ ID: "task-1", ProjectID: "myapp", Status: domain.WorkTaskStatusPending, } err := svc.CancelTask(context.Background(), "task-1") if err != nil { t.Fatalf("unexpected error: %v", err) } }