From 60779ad2ecc5a840869860d4bf68bcec489ebce8 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Mon, 11 May 2026 19:46:59 +0200 Subject: [PATCH] test(coderd/x/chatd): stop waking acquireLoop in TestResolveExploreToolSnapshot (#25129) Fixes [CODAGT-367](https://linear.app/codercom/issue/CODAGT-367). `TestResolveExploreToolSnapshot/*` flaked on CI (Linux and Windows) with `context deadline exceeded` on the `GetMCPServerConfigsByIDs` call inside `resolveExploreToolSnapshot`. Each test setup called `server.CreateChat` twice with `MCPServerIDs` set to fake `.example.com` URLs. `CreateChat` marks the chat pending and calls `signalWake`, which causes the chatd background `acquireLoop` to pick the chat up. That goroutine then dialed the fake MCP URLs (NXDOMAIN, slower on Windows) and made an OpenAI request with the dbgen default test key (401). Under CI load, that activity racing the 4 parallel subtests' `GetMCPServerConfigsByIDs` calls was enough to exceed the 25s test context deadline. The failure logs in the issue showed both side effects firing in the same job. `resolveExploreToolSnapshot` only reads `ID`, `MCPServerIDs`, `PlanMode`, `ParentChatID`, and `Mode` off the parent argument, so the chats do not need to be persisted. Build them as in-memory `database.Chat` values instead. The MCP server configs remain in the DB because the function still queries them via `GetMCPServerConfigsByIDs`. Verified locally with `go test ./coderd/x/chatd -run TestResolveExploreToolSnapshot -count=100 -race` (passes, ~5s total) and the surrounding `TestResolve*` / `TestCreateChildSubagentChat*` / `TestSpawnAgent_Explore*` tests. --- _Made by Coder Agents on behalf of @ibetitsmike. [Linear session](https://linear.app/codercom/issue/CODAGT-367/flake-testresolveexploretoolsnapshot#agent-session-0730f3fe)._ --- coderd/x/chatd/subagent_internal_test.go | 46 ++++++++++-------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/coderd/x/chatd/subagent_internal_test.go b/coderd/x/chatd/subagent_internal_test.go index 427c6a2a82..d66f2dedb0 100644 --- a/coderd/x/chatd/subagent_internal_test.go +++ b/coderd/x/chatd/subagent_internal_test.go @@ -1429,8 +1429,7 @@ func TestResolveExploreToolSnapshot(t *testing.T) { db, ps := dbtestutil.NewDB(t) server := newInternalTestServer(t, db, ps, chatprovider.ProviderAPIKeys{}) - ctx := chatdTestContext(t) - user, org, model := seedInternalChatDeps(t, db) + user, _, _ := seedInternalChatDeps(t, db) approvedMCP := insertInternalMCPServerConfig( t, db, user.ID, "approved-"+uuid.NewString(), true, ) @@ -1438,42 +1437,33 @@ func TestResolveExploreToolSnapshot(t *testing.T) { t, db, user.ID, "blocked-"+uuid.NewString(), false, ) - askParentRef, err := server.CreateChat(ctx, CreateOptions{ - OrganizationID: org.ID, - OwnerID: user.ID, - Title: "ask-parent", - ModelConfigID: model.ID, - MCPServerIDs: []uuid.UUID{approvedMCP.ID, blockedMCP.ID}, - InitialUserContent: []codersdk.ChatMessagePart{ - codersdk.ChatMessageText("hello"), - }, - }) - require.NoError(t, err) - askParent, err := db.GetChatByID(ctx, askParentRef.ID) - require.NoError(t, err) - - planParentRef, err := server.CreateChat(ctx, CreateOptions{ - OrganizationID: org.ID, - OwnerID: user.ID, - Title: "plan-parent", - ModelConfigID: model.ID, + // Build parent chats in memory rather than via server.CreateChat. + // resolveExploreToolSnapshot only reads ID, MCPServerIDs, PlanMode, + // ParentChatID, and Mode from its parent argument, so persisting + // the chats is unnecessary. Skipping CreateChat avoids waking the + // background acquireLoop, which would otherwise try to dial the + // fake MCP URLs and call OpenAI with the dbgen test API key. Those + // side effects were the root cause of the flake tracked in + // CODAGT-367. + askParent := database.Chat{ + ID: uuid.New(), + MCPServerIDs: []uuid.UUID{approvedMCP.ID, blockedMCP.ID}, + } + planParent := database.Chat{ + ID: uuid.New(), PlanMode: database.NullChatPlanMode{ ChatPlanMode: database.ChatPlanModePlan, Valid: true, }, MCPServerIDs: []uuid.UUID{approvedMCP.ID, blockedMCP.ID}, - InitialUserContent: []codersdk.ChatMessagePart{ - codersdk.ChatMessageText("hello"), - }, - }) - require.NoError(t, err) - planParent, err := db.GetChatByID(ctx, planParentRef.ID) - require.NoError(t, err) + } subagentPlanParent := planParent + subagentPlanParent.ID = uuid.New() subagentPlanParent.ParentChatID = uuid.NullUUID{UUID: uuid.New(), Valid: true} exploreParent := askParent + exploreParent.ID = uuid.New() exploreParent.Mode = database.NullChatMode{ChatMode: database.ChatModeExplore, Valid: true} exploreParent.ParentChatID = uuid.NullUUID{UUID: uuid.New(), Valid: true} exploreParent.MCPServerIDs = []uuid.UUID{approvedMCP.ID}