X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/6d96a69d33eb634f61f809001aca19ae57113180..b473b56ebf00e6b4d6cf16664f93e1958fbe2080:/turn_test.go diff --git a/turn_test.go b/turn_test.go index 69c9236..949c0b8 100644 --- a/turn_test.go +++ b/turn_test.go @@ -3,7 +3,6 @@ package main import ( "context" "encoding/json" - "errors" "net/http" "path/filepath" "strings" @@ -61,6 +60,7 @@ func TestTurnRunsToolsUntilTheFinalAnswer(t *testing.T) { require.Equal(t, []string{"user", "busy", "tool", "echo", "reply", "idle"}, test.events.Kinds()) var turns []string + for _, record := range modelReadUsage(t, test.usagePath) { turns = append(turns, record.Turn) } @@ -106,11 +106,13 @@ func TestMessageDuringATurnJoinsTheNextRequest(t *testing.T) { require.NoError(t, err) <-arrived + _, err = test.loop.Submit(terminalSource, "second, during the turn") require.NoError(t, err) close(release) test.events.WaitFor(t, "idle", 1) + input := server.Call(1).body["input"].([]any) require.Equal(t, map[string]any{ "role": "user", @@ -140,6 +142,7 @@ func TestMessageDuringTheFinalRequestStartsANewTurn(t *testing.T) { require.NoError(t, err) <-arrived + _, err = test.loop.Submit(terminalSource, "second") require.NoError(t, err) close(release) @@ -170,7 +173,7 @@ func TestTurnWaitsForTheSummaries(t *testing.T) { close(summarizer.gate) test.events.WaitFor(t, "idle", 1) require.Equal(t, 1, server.Calls()) - require.NotContains(t, turnInputTexts(t, server.Call(0))[0], pending) + require.NotContains(t, turnInputTexts(t, server.Call(0))[0], viewPending) } func TestInterruptEndsTheTurn(t *testing.T) { @@ -203,11 +206,12 @@ func TestInterruptEndsTheTurn(t *testing.T) { require.NoError(t, err) test.events.WaitFor(t, "idle", 2) require.Equal(t, "reply: answer", test.Log(t)[2]) + require.Empty(t, test.logs.String()) } func TestFailedCallEndsTheTurnWithoutARetry(t *testing.T) { server := newModelFake(t) - server.reply = func(w http.ResponseWriter, call ModelFakeCall) { + server.reply = func(w http.ResponseWriter, _ ModelFakeCall) { http.Error(w, "busy", http.StatusServiceUnavailable) } @@ -219,6 +223,10 @@ func TestFailedCallEndsTheTurnWithoutARetry(t *testing.T) { time.Sleep(50 * time.Millisecond) require.Equal(t, 1, server.Calls()) require.Contains(t, test.events.Last("error"), "HTTP 503") + require.Equal(t, 1, strings.Count(test.logs.String(), "\n")) + require.Contains(t, test.logs.String(), "<3>turn failed: ") + require.Contains(t, test.logs.String(), "HTTP 503") + require.NotContains(t, test.logs.String(), "hello") } func TestViewMessagesOnlyGrowBetweenTurns(t *testing.T) { @@ -232,6 +240,7 @@ func TestViewMessagesOnlyGrowBetweenTurns(t *testing.T) { first := server.Call(1).body["input"].([]any) second := server.Call(2).body["input"].([]any) + require.Len(t, first, 4) require.Len(t, second, 5) require.Equal(t, first[:2], second[:2]) @@ -250,6 +259,7 @@ type TurnTestLoop struct { memory *Memory loop *TurnLoop events *TurnEventRecorder + logs *SyncBuffer usagePath string } @@ -258,6 +268,7 @@ func (l *TurnTestLoop) Log(t *testing.T) []string { t.Helper() var lines []string + for id := range l.memory.Len() { message, err := l.memory.Message(id) require.NoError(t, err) @@ -308,16 +319,21 @@ func (r *TurnEventRecorder) Count(kind string) int { // Last returns the text of the last event of kind. func (r *TurnEventRecorder) Last(kind string) string { + return r.LastEvent(kind).Text +} + +// LastEvent returns the last event of kind. +func (r *TurnEventRecorder) LastEvent(kind string) Event { r.mutex.Lock() defer r.mutex.Unlock() for n := len(r.events) - 1; n >= 0; n-- { if r.events[n].Kind == kind { - return r.events[n].Text + return r.events[n] } } - return "" + return Event{} } func (r *TurnEventRecorder) Add(event Event) { @@ -349,12 +365,14 @@ func turnInputTexts(t *testing.T, call ModelFakeCall) []string { require.NoError(t, json.Unmarshal(call.raw, &body)) var texts []string + for _, item := range body.Input { if item.Role != "user" { continue } var text strings.Builder + for _, part := range item.Content { text.WriteString(part.Text) } @@ -375,19 +393,22 @@ func newTestTurnLoopWith(t *testing.T, server *ModelFake, summarizer Summarizer) agent.config.Workdir = t.TempDir() clock := newTestClock() - memory, err := openMemory(t.Context(), t.TempDir(), clock.Now, summarizer) + memory, err := openMemory(t.Context(), t.TempDir(), clock.Now, summarizer, discardLog()) require.NoError(t, err) test := &TurnTestLoop{ agent: agent, memory: memory, events: &TurnEventRecorder{}, + logs: &SyncBuffer{}, usagePath: filepath.Join(t.TempDir(), "usage.jsonl"), } client := newModelClient(server.URL, ModelAPIKey(modelTestKey), agent.CacheKey(), test.usagePath) - test.loop, err = newTurnLoop(agent, memory, client, clock.Now, test.events.Add) + whatsapp, _, _ := whatsappStartTest(t, t.TempDir(), clock) + test.loop, err = newTurnLoop(agent, memory, newTestSubagents(t), whatsapp, newTestSchedules(t, clock.Now), client, clock.Now, daemonTestLogger(test.logs), test.events.Add) require.NoError(t, err) + ctx, cancel := context.WithCancel(t.Context()) done := make(chan error) go func() { @@ -396,7 +417,7 @@ func newTestTurnLoopWith(t *testing.T, server *ModelFake, summarizer Summarizer) t.Cleanup(func() { cancel() - require.True(t, errors.Is(<-done, context.Canceled)) + require.ErrorIs(t, <-done, context.Canceled) require.NoError(t, memory.Close()) })