test(coderd): centralize chat test harness and stabilize flakes (#25171)

Chat tests previously constructed a real `openai` provider with a fake
API key and no `BaseURL`, so background title generation hit
`api.openai.com` and timed out under `-race`. The same root cause
produced several distinct flakes: title regeneration races with
synchronous `UpdateChat`/`ProposeChatTitle`, and pagination races
against `updated_at` bumps from real-network processing.

This moves the fake OpenAI-compatible provider and the chat-settle wait
into first-class `coderdtest` capabilities.
`coderd.Options.ChatProviderAPIKeys` is the new seam tests use to
redirect chat traffic to a local `httptest.Server`.
`coderdtest.WaitForChatSettled` replaces per-test waiters and drains
tracked chat-daemon work after the chat row leaves `pending`/`running`.
The `newChatClient*` constructors funnel through one options builder
that installs the fake provider before the coderd test server so cleanup
ordering is deterministic.

Closes https://github.com/coder/internal/issues/1528 & Closes ENG-2659
Closes https://github.com/coder/internal/issues/1480 & Closes CODAGT-359
Closes https://github.com/coder/internal/issues/1507 & Closes CODAGT-368
Relates to https://github.com/coder/internal/issues/1397 & Relates to
CODAGT-374
This commit is contained in:
Ethan
2026-05-12 22:13:55 +10:00
committed by GitHub
parent 8ba24e0e54
commit 4e08543ace
8 changed files with 271 additions and 133 deletions
+10 -1
View File
@@ -95,6 +95,7 @@ import (
"github.com/coder/coder/v2/coderd/workspacestats"
"github.com/coder/coder/v2/coderd/wsbuilder"
"github.com/coder/coder/v2/coderd/x/chatd"
"github.com/coder/coder/v2/coderd/x/chatd/chatprovider"
"github.com/coder/coder/v2/coderd/x/chatd/mcpclient"
"github.com/coder/coder/v2/coderd/x/gitsync"
"github.com/coder/coder/v2/codersdk"
@@ -248,6 +249,9 @@ type Options struct {
// ChatSubscribeFn provides cross-replica subscription merging.
// Set by enterprise for HA deployments. Nil in AGPL single-replica.
ChatSubscribeFn chatd.SubscribeFn
// ChatProviderAPIKeys overrides deployment-derived provider keys.
// Test harnesses use this to route chat models to local providers.
ChatProviderAPIKeys *chatprovider.ProviderAPIKeys
UpdateAgentMetrics func(ctx context.Context, labels prometheusmetrics.AgentMetricLabels, metrics []*agentproto.Stats_Metric)
StatsBatcher workspacestats.Batcher
@@ -792,13 +796,18 @@ func New(options *Options) *API {
options.Logger.Named("mcp-user-oidc"),
)
}
providerAPIKeys := ChatProviderAPIKeysFromDeploymentValues(options.DeploymentValues)
if options.ChatProviderAPIKeys != nil {
providerAPIKeys = *options.ChatProviderAPIKeys
}
api.chatDaemon = chatd.New(chatd.Config{
Logger: options.Logger.Named("chatd"),
Database: options.Database,
ReplicaID: api.ID,
SubscribeFn: options.ChatSubscribeFn,
MaxChatsPerAcquire: int32(maxChatsPerAcquire), //nolint:gosec // maxChatsPerAcquire is clamped to int32 range above.
ProviderAPIKeys: ChatProviderAPIKeysFromDeploymentValues(options.DeploymentValues),
ProviderAPIKeys: providerAPIKeys,
AlwaysEnableDebugLogs: options.DeploymentValues.AI.Chat.DebugLoggingEnabled.Value(),
AgentConn: api.agentProvider.AgentConn,
AgentInactiveDisconnectTimeout: api.AgentInactiveDisconnectTimeout,