From 0f5ab7a2c98bae5552b8b41417e443468b93e356 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Wed, 15 Apr 2026 09:35:08 -0700 Subject: [PATCH] fix(tests): add EXISTS probe mock to 4 WorkspaceUpdate tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #125 added a SELECT EXISTS guard before WorkspaceHandler.Update applies any UPDATE so nonexistent workspace IDs return 404 instead of silent zero-row successes. The 4 existing WorkspaceUpdate_* sqlmock tests didn't mock the probe, so they broke on main. This was not caught because CI is blocked by the Actions billing cap. Adds ExpectQuery for the EXISTS probe to: - TestWorkspaceUpdate_ParentID - TestWorkspaceUpdate_NameOnly - TestWorkspaceUpdate_MultipleFields - TestWorkspaceUpdate_RuntimeField TestWorkspaceUpdate_BadJSON doesn't need the fix — it aborts on c.ShouldBindJSON before reaching the guard. Co-Authored-By: Claude Opus 4.6 (1M context) --- platform/internal/handlers/handlers_additional_test.go | 8 ++++++++ platform/internal/handlers/workspace_test.go | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/platform/internal/handlers/handlers_additional_test.go b/platform/internal/handlers/handlers_additional_test.go index 7d2942ba..edc6513e 100644 --- a/platform/internal/handlers/handlers_additional_test.go +++ b/platform/internal/handlers/handlers_additional_test.go @@ -115,6 +115,11 @@ func TestWorkspaceUpdate_ParentID(t *testing.T) { broadcaster := newTestBroadcaster() handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir()) + // #125 guard: handler now verifies the workspace exists before applying + // the UPDATE. Each PATCH test must mock the EXISTS probe first. + mock.ExpectQuery("SELECT EXISTS.*workspaces WHERE id"). + WithArgs("ws-child"). + WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(true)) mock.ExpectExec("UPDATE workspaces SET parent_id"). WithArgs("ws-child", "ws-parent"). WillReturnResult(sqlmock.NewResult(0, 1)) @@ -144,6 +149,9 @@ func TestWorkspaceUpdate_NameOnly(t *testing.T) { broadcaster := newTestBroadcaster() handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir()) + mock.ExpectQuery("SELECT EXISTS.*workspaces WHERE id"). + WithArgs("ws-rename"). + WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(true)) mock.ExpectExec("UPDATE workspaces SET name"). WithArgs("ws-rename", "New Name"). WillReturnResult(sqlmock.NewResult(0, 1)) diff --git a/platform/internal/handlers/workspace_test.go b/platform/internal/handlers/workspace_test.go index fb7f5579..97f68830 100644 --- a/platform/internal/handlers/workspace_test.go +++ b/platform/internal/handlers/workspace_test.go @@ -304,6 +304,10 @@ func TestWorkspaceUpdate_MultipleFields(t *testing.T) { broadcaster := newTestBroadcaster() handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir()) + // #125: existence probe fires once before any field update. + mock.ExpectQuery("SELECT EXISTS.*workspaces WHERE id"). + WithArgs("ws-multi"). + WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(true)) // Expect name, role, and tier updates mock.ExpectExec("UPDATE workspaces SET name"). WithArgs("ws-multi", "Updated Agent"). @@ -348,6 +352,9 @@ func TestWorkspaceUpdate_RuntimeField(t *testing.T) { broadcaster := newTestBroadcaster() handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir()) + mock.ExpectQuery("SELECT EXISTS.*workspaces WHERE id"). + WithArgs("ws-rt"). + WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(true)) mock.ExpectExec("UPDATE workspaces SET runtime"). WithArgs("ws-rt", "claude-code"). WillReturnResult(sqlmock.NewResult(0, 1))