fix(coderd): stabilize TestPatchChatMessage/ChangesModel flaky test (#25306)

Fixes coder/internal#1535

## Problem

`TestPatchChatMessage/ChangesModel` is flaky because it races with the
chat daemon's background processing.

`CreateChat` sets the chat to `pending` and the daemon picks it up
asynchronously. The test immediately calls `EditChatMessage` (which
changes the model to an override) while the first processing round is
still running. The `InsertChatMessages` SQL CTE unconditionally updates
`chats.last_model_config_id` to the model of the last inserted message.
When the daemon's in-flight message insertions commit after the edit
transaction, they overwrite `last_model_config_id` back to the default
model.

Similarly, after the edit sets the chat back to `pending`, the daemon
re-processes it. The test's `GetChat` call could race with this second
round.

## Fix

Poll for the chat to reach `waiting` (or `error`) status:
1. **Before editing**: wait for the initial processing round to complete
2. **After editing**: wait for the second processing round (triggered by
the edit) to complete

Then assert `last_model_config_id`, which is now stable.

> Generated with [Coder Agents](https://coder.com/agents) by @kylecarbs
This commit is contained in:
Kyle Carberry
2026-05-15 09:33:54 -04:00
committed by GitHub
parent aa87d55a6d
commit 9f99a7bc0b
+27
View File
@@ -7792,6 +7792,20 @@ func TestPatchChatMessage(t *testing.T) {
require.Equal(t, defaultModel.ID, chat.LastModelConfigID,
"chat starts on the default model")
// Wait for the initial chat processing to complete before
// editing. CreateChat sets the chat to pending and the daemon
// processes it asynchronously; editing while that first round
// is still running can race with message insertions that
// overwrite last_model_config_id.
testutil.Eventually(ctx, t, func(ctx context.Context) bool {
c, getErr := client.GetChat(ctx, chat.ID)
if getErr != nil {
return false
}
return c.Status != codersdk.ChatStatusPending &&
c.Status != codersdk.ChatStatusRunning
}, testutil.IntervalFast, "initial chat processing did not finish")
messagesResult, err := client.GetChatMessages(ctx, chat.ID, nil)
require.NoError(t, err)
var userMessageID int64
@@ -7816,6 +7830,19 @@ func TestPatchChatMessage(t *testing.T) {
require.Equal(t, overrideModel.ID, *edited.Message.ModelConfigID,
"replacement message must use the requested model")
// Wait for the second round of processing (triggered by the
// edit) to complete, then verify last_model_config_id.
// Reading immediately after EditChatMessage can race with the
// daemon re-processing the now-pending chat.
testutil.Eventually(ctx, t, func(ctx context.Context) bool {
c, getErr := client.GetChat(ctx, chat.ID)
if getErr != nil {
return false
}
return c.Status != codersdk.ChatStatusPending &&
c.Status != codersdk.ChatStatusRunning
}, testutil.IntervalFast, "post-edit chat processing did not finish")
updatedChat, err := client.GetChat(ctx, chat.ID)
require.NoError(t, err)
require.Equal(t, overrideModel.ID, updatedChat.LastModelConfigID,