summaryrefslogtreecommitdiff
path: root/internal/handlers/widget_test.go
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-07-12 05:36:32 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-07-12 05:36:32 +0000
commit9a87f9db5af943ea253b814d4196020341e3c2ba (patch)
treeacaeb91e0fad131b15d4d6d41c5d0ea0254c2966 /internal/handlers/widget_test.go
parent73fbd05a1230552bcef9834d3ee999ef19957693 (diff)
fix(widget): surface unmatched task IDs instead of silently no-opping
CompleteNativeTask/UncompleteNativeTask/RescheduleNativeTask ran a plain UPDATE ... WHERE id = ? and returned whatever error Exec gave back -- which is nil even when 0 rows match, since that's not a SQL error. A stale or wrong id from the widget looked identical to a real completion: HTTP 200, nothing changed in the database. Real incident: 1 of 3 widget completeTask taps silently no-opped this way. Now checks RowsAffected() and returns ErrNativeTaskNotFound (mirrors the existing pattern in sqlite.go's ApproveAgentSession/DenyAgentSession). HandleWidgetComplete and HandleWidgetReschedule surface this as 404 instead of a fake 200, so the widget can tell 'nothing changed' apart from 'it worked.'
Diffstat (limited to 'internal/handlers/widget_test.go')
-rw-r--r--internal/handlers/widget_test.go20
1 files changed, 20 insertions, 0 deletions
diff --git a/internal/handlers/widget_test.go b/internal/handlers/widget_test.go
index f56fe07..850dc07 100644
--- a/internal/handlers/widget_test.go
+++ b/internal/handlers/widget_test.go
@@ -121,6 +121,26 @@ func TestHandleWidgetComplete_NonCompletable(t *testing.T) {
}
}
+// TestHandleWidgetComplete_UnknownID_Returns404 proves the 2026-07-12 fix at
+// the handler layer: a "doot" completion for an id that doesn't exist must
+// surface as 404, not the previous silent 200 (see
+// store.ErrNativeTaskNotFound's doc comment for the underlying bug this
+// closes -- a real production incident where the widget's completeTask tap
+// intermittently looked like it worked but changed nothing).
+func TestHandleWidgetComplete_UnknownID_Returns404(t *testing.T) {
+ s, cleanup := setupTestDB(t)
+ defer cleanup()
+ h := &Handler{store: s}
+ body := `{"id":"does-not-exist","source":"doot"}`
+ req := httptest.NewRequest("POST", "/api/widget/complete", strings.NewReader(body))
+ w := httptest.NewRecorder()
+ http.HandlerFunc(h.HandleWidgetComplete).ServeHTTP(w, req)
+
+ if w.Code != http.StatusNotFound {
+ t.Fatalf("expected 404, got %d", w.Code)
+ }
+}
+
func TestWidgetAuthMiddleware_EmptyToken(t *testing.T) {
inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
h := WidgetAuthMiddleware("", inner)