(t *testing.T)
| 480 | } |
| 481 | |
| 482 | func Test_ErrorRemovesPartialMessage(t *testing.T) { |
| 483 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) |
| 484 | defer cancel() |
| 485 | |
| 486 | mClock := quartz.NewMock(t) |
| 487 | mock := newMockAgentIO() |
| 488 | emitter := newMockEmitter() |
| 489 | // Block the write so we can simulate partial content before error |
| 490 | started, done := mock.BlockWrite() |
| 491 | |
| 492 | conv := acpio.NewACPConversation(ctx, mock, nil, nil, emitter, mClock) |
| 493 | conv.Start(ctx) |
| 494 | |
| 495 | // Send blocks, so run in a goroutine |
| 496 | errCh := make(chan error, 1) |
| 497 | go func() { errCh <- conv.Send(screentracker.MessagePartText{Content: "test"}) }() |
| 498 | |
| 499 | // Wait for write to start |
| 500 | <-started |
| 501 | |
| 502 | // Should have user message + placeholder agent message |
| 503 | messages := conv.Messages() |
| 504 | require.Len(t, messages, 2) |
| 505 | assert.Equal(t, screentracker.ConversationRoleUser, messages[0].Role) |
| 506 | assert.Equal(t, screentracker.ConversationRoleAgent, messages[1].Role) |
| 507 | |
| 508 | // Simulate the agent streaming partial content before the error |
| 509 | mock.SimulateChunks("partial ", "response ", "content") |
| 510 | |
| 511 | // Verify partial content is in the agent message |
| 512 | messages = conv.Messages() |
| 513 | require.Len(t, messages, 2) |
| 514 | assert.Equal(t, "partial response content", messages[1].Message) |
| 515 | |
| 516 | // Now configure the mock to return an error and unblock |
| 517 | mock.mu.Lock() |
| 518 | mock.writeErr = assert.AnError |
| 519 | mock.mu.Unlock() |
| 520 | close(done) |
| 521 | |
| 522 | // Send should return the error |
| 523 | require.ErrorIs(t, <-errCh, assert.AnError) |
| 524 | |
| 525 | // The partial agent message should be removed on error. |
| 526 | // Only the user message should remain. |
| 527 | messages = conv.Messages() |
| 528 | require.Len(t, messages, 1, "partial agent message should be removed on error") |
| 529 | assert.Equal(t, screentracker.ConversationRoleUser, messages[0].Role) |
| 530 | assert.Equal(t, "test", messages[0].Message) |
| 531 | |
| 532 | // First exchange allocated IDs 0 (user) and 1 (agent, now removed). |
| 533 | assert.Equal(t, 0, messages[0].Id) |
| 534 | |
| 535 | // Send a second message — IDs must not reuse the removed agent message's ID (1). |
| 536 | mock.mu.Lock() |
| 537 | mock.writeErr = nil |
| 538 | mock.mu.Unlock() |
| 539 | started2, done2 := mock.BlockWrite() |
nothing calls this directly
no test coverage detected