diff --git a/coderd/x/chatd/chatd_test.go b/coderd/x/chatd/chatd_test.go index 99856f2822..d8302ab793 100644 --- a/coderd/x/chatd/chatd_test.go +++ b/coderd/x/chatd/chatd_test.go @@ -1291,13 +1291,15 @@ func TestSendMessageInterruptBehaviorQueuesAndInterruptsWhenBusy(t *testing.T) { require.NoError(t, err) require.Len(t, queued, 1) - // Only the initial user message should be in chat_messages. + // Only messages from the initial processing round should be in + // chat_messages (user + assistant). The "interrupt" message must + // be in the queue, not inserted directly. messages, err := db.GetChatMessagesByChatID(ctx, database.GetChatMessagesByChatIDParams{ ChatID: chat.ID, AfterID: 0, }) require.NoError(t, err) - require.Len(t, messages, 1) + require.Len(t, messages, 2) } func TestEditMessageUpdatesAndTruncatesAndClearsQueue(t *testing.T) { @@ -1685,8 +1687,8 @@ func TestPromoteQueuedAllowsAlreadyQueuedMessageWhenUsageLimitReached(t *testing AfterID: 0, }) require.NoError(t, err) - require.Len(t, messages, 3) - require.Equal(t, database.ChatMessageRoleUser, messages[2].Role) + require.Len(t, messages, 4) + require.Equal(t, database.ChatMessageRoleUser, messages[3].Role) } func TestInterruptAutoPromotionIgnoresLaterUsageLimitIncrease(t *testing.T) { @@ -4476,7 +4478,8 @@ func seedChatDependencies( db database.Store, ) (database.User, database.Organization, database.ChatModelConfig) { t.Helper() - return seedChatDependenciesWithProvider(ctx, t, db, "openai", "") + openAIURL := chattest.OpenAI(t) + return seedChatDependenciesWithProvider(ctx, t, db, "openai", openAIURL) } // seedChatDependenciesWithProvider creates a user, organization, diff --git a/coderd/x/chatd/chattest/openai.go b/coderd/x/chatd/chattest/openai.go index 0e89417724..b3a3bb2330 100644 --- a/coderd/x/chatd/chattest/openai.go +++ b/coderd/x/chatd/chattest/openai.go @@ -139,6 +139,26 @@ type openAIServer struct { request *OpenAIRequest } +// OpenAI creates a fake OpenAI-compatible test server with a +// sensible default handler and returns its base URL. It handles +// both the Responses API (/responses) and the Chat Completions +// API (/chat/completions). +// +// Non-streaming requests (e.g. structured-output title generation) +// receive a JSON payload satisfying the generatedTitle schema. +// Streaming requests (e.g. the main chat loop) receive a single +// text chunk. Use NewOpenAI when a test needs control over the +// response. +func OpenAI(t testing.TB) string { + t.Helper() + return NewOpenAI(t, func(req *OpenAIRequest) OpenAIResponse { + if req.Stream { + return OpenAIStreamingResponse(OpenAITextChunks("Hello from test server.")...) + } + return OpenAINonStreamingResponse(`{"title": "Test Chat"}`) + }) +} + // NewOpenAI creates a new OpenAI test server with a handler function. // The handler is called for each request and should return either a streaming // response (via channel) or a non-streaming response.