summaryrefslogtreecommitdiff
path: root/internal/api/server_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/api/server_test.go')
-rw-r--r--internal/api/server_test.go182
1 files changed, 182 insertions, 0 deletions
diff --git a/internal/api/server_test.go b/internal/api/server_test.go
index 2325b0b..e012bc1 100644
--- a/internal/api/server_test.go
+++ b/internal/api/server_test.go
@@ -463,6 +463,73 @@ func TestHandleStartNextTask_NoTask(t *testing.T) {
}
}
+func TestResumeTimedOut_NoTask_Returns404(t *testing.T) {
+ srv, _ := testServer(t)
+
+ req := httptest.NewRequest("POST", "/api/tasks/nonexistent/resume", nil)
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+
+ if w.Code != http.StatusNotFound {
+ t.Errorf("status: want 404, got %d; body: %s", w.Code, w.Body.String())
+ }
+}
+
+func TestResumeTimedOut_TaskNotTimedOut_Returns409(t *testing.T) {
+ srv, store := testServer(t)
+ createTaskWithState(t, store, "resume-task-1", task.StatePending)
+
+ req := httptest.NewRequest("POST", "/api/tasks/resume-task-1/resume", nil)
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+
+ if w.Code != http.StatusConflict {
+ t.Errorf("status: want 409, got %d; body: %s", w.Code, w.Body.String())
+ }
+}
+
+func TestResumeTimedOut_NoSession_Returns500(t *testing.T) {
+ srv, store := testServer(t)
+ createTaskWithState(t, store, "resume-task-2", task.StateTimedOut)
+
+ // No execution created — so no session ID.
+ req := httptest.NewRequest("POST", "/api/tasks/resume-task-2/resume", nil)
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+
+ if w.Code != http.StatusInternalServerError {
+ t.Errorf("status: want 500, got %d; body: %s", w.Code, w.Body.String())
+ }
+}
+
+func TestResumeTimedOut_Success_Returns202(t *testing.T) {
+ srv, store := testServer(t)
+ createTaskWithState(t, store, "resume-task-3", task.StateTimedOut)
+
+ exec := &storage.Execution{
+ ID: "exec-timedout-1",
+ TaskID: "resume-task-3",
+ SessionID: "550e8400-e29b-41d4-a716-446655440002",
+ Status: "TIMED_OUT",
+ }
+ if err := store.CreateExecution(exec); err != nil {
+ t.Fatalf("create execution: %v", err)
+ }
+
+ req := httptest.NewRequest("POST", "/api/tasks/resume-task-3/resume", nil)
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+
+ if w.Code != http.StatusAccepted {
+ t.Errorf("status: want 202, got %d; body: %s", w.Code, w.Body.String())
+ }
+
+ got, _ := store.GetTask("resume-task-3")
+ if got.State != task.StateQueued && got.State != task.StateRunning && got.State != task.StateReady {
+ t.Errorf("task state: want QUEUED/RUNNING/READY after resume, got %v", got.State)
+ }
+}
+
func TestHandleStartNextTask_ScriptNotFound(t *testing.T) {
srv, _ := testServer(t)
srv.startNextTaskScript = "/nonexistent/start-next-task"
@@ -475,3 +542,118 @@ func TestHandleStartNextTask_ScriptNotFound(t *testing.T) {
t.Errorf("want 500, got %d; body: %s", w.Code, w.Body.String())
}
}
+
+func TestDeleteTask_Success(t *testing.T) {
+ srv, store := testServer(t)
+
+ // Create a task to delete.
+ created := createTestTask(t, srv, `{"name":"Delete Me","claude":{"instructions":"x","model":"sonnet"}}`)
+
+ req := httptest.NewRequest("DELETE", "/api/tasks/"+created.ID, nil)
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+
+ if w.Code != http.StatusNoContent {
+ t.Fatalf("want 204, got %d; body: %s", w.Code, w.Body.String())
+ }
+
+ _, err := store.GetTask(created.ID)
+ if err == nil {
+ t.Error("task should be deleted from store")
+ }
+}
+
+func TestDeleteTask_NotFound(t *testing.T) {
+ srv, _ := testServer(t)
+
+ req := httptest.NewRequest("DELETE", "/api/tasks/does-not-exist", nil)
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+
+ if w.Code != http.StatusNotFound {
+ t.Errorf("want 404, got %d", w.Code)
+ }
+}
+
+func TestDeleteTask_RunningTaskRejected(t *testing.T) {
+ srv, store := testServer(t)
+
+ created := createTestTask(t, srv, `{"name":"Running Task","claude":{"instructions":"x","model":"sonnet"}}`)
+ store.UpdateTaskState(created.ID, "RUNNING")
+
+ req := httptest.NewRequest("DELETE", "/api/tasks/"+created.ID, nil)
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+
+ if w.Code != http.StatusConflict {
+ t.Errorf("want 409 for running task, got %d", w.Code)
+ }
+}
+
+// createTestTask is a helper that POSTs a task and returns the parsed Task.
+func createTestTask(t *testing.T, srv *Server, payload string) task.Task {
+ t.Helper()
+ req := httptest.NewRequest("POST", "/api/tasks", bytes.NewBufferString(payload))
+ req.Header.Set("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+ if w.Code != http.StatusCreated {
+ t.Fatalf("createTestTask: want 201, got %d; body: %s", w.Code, w.Body.String())
+ }
+ var tk task.Task
+ json.NewDecoder(w.Body).Decode(&tk)
+ return tk
+}
+
+func TestServer_CancelTask_Pending_TransitionsToCancelled(t *testing.T) {
+ srv, store := testServer(t)
+ createTaskWithState(t, store, "cancel-pending-1", task.StatePending)
+
+ req := httptest.NewRequest("POST", "/api/tasks/cancel-pending-1/cancel", nil)
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+
+ if w.Code != http.StatusOK {
+ t.Fatalf("status: want 200, got %d; body: %s", w.Code, w.Body.String())
+ }
+ updated, err := store.GetTask("cancel-pending-1")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if updated.State != task.StateCancelled {
+ t.Errorf("state: want CANCELLED, got %s", updated.State)
+ }
+}
+
+func TestServer_CancelTask_Queued_TransitionsToCancelled(t *testing.T) {
+ srv, store := testServer(t)
+ createTaskWithState(t, store, "cancel-queued-1", task.StateQueued)
+
+ req := httptest.NewRequest("POST", "/api/tasks/cancel-queued-1/cancel", nil)
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+
+ if w.Code != http.StatusOK {
+ t.Fatalf("status: want 200, got %d; body: %s", w.Code, w.Body.String())
+ }
+ updated, err := store.GetTask("cancel-queued-1")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if updated.State != task.StateCancelled {
+ t.Errorf("state: want CANCELLED, got %s", updated.State)
+ }
+}
+
+func TestServer_CancelTask_Completed_Returns409(t *testing.T) {
+ srv, store := testServer(t)
+ createTaskWithState(t, store, "cancel-completed-1", task.StateCompleted)
+
+ req := httptest.NewRequest("POST", "/api/tasks/cancel-completed-1/cancel", nil)
+ w := httptest.NewRecorder()
+ srv.Handler().ServeHTTP(w, req)
+
+ if w.Code != http.StatusConflict {
+ t.Errorf("status: want 409, got %d; body: %s", w.Code, w.Body.String())
+ }
+}