X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/98d137c3e945a09f76e85bd18238558c668fdca4..HEAD:/notify_test.go?ds=sidebyside diff --git a/notify_test.go b/notify_test.go index c0a565d..0f60ad5 100644 --- a/notify_test.go +++ b/notify_test.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "net" + "net/http" "os" "path/filepath" "strings" @@ -49,10 +50,96 @@ func TestNotifyCLIReachesOnlyTheRootThroughTheDaemon(t *testing.T) { require.Equal(t, receipt.ID, duplicate.ID) require.Equal(t, "duplicate", duplicate.Status) + root, err := openAgent(filepath.Join(filepath.Dir(socket), daemonAgentDirName)) + require.NoError(t, err) + out.Reset() + require.NoError(t, notify(t.Context(), append([]string{"--agent-id", root.config.ID}, args...), &out)) + require.NoError(t, json.Unmarshal(out.Bytes(), &duplicate)) + require.Equal(t, receipt.ID, duplicate.ID) + require.Equal(t, "duplicate", duplicate.Status) + args[len(args)-1] = "Changed result." require.ErrorContains(t, notify(t.Context(), args, &out), "conflicts") } +func TestNotifyCLISelectsOnlyThePermanentChildByID(t *testing.T) { + directory := daemonTestSocketDir(t) + daemonChildConfig(t, directory, "Garden") + daemonChildConfig(t, directory, "Library") + + server := newModelFake(t) + server.reply = func(w http.ResponseWriter, _ ModelFakeCall) { + modelWriteEvents(w, modelCompletedEvent([]any{modelMessageItem("")}, 100, 0, 5)) + } + + agents, err := openDaemonAgents(t.Context(), directory, server.URL, ModelAPIKey(modelTestKey), defaultConfig().Compactor, newTestClock().Now, discardLog()) + require.NoError(t, err) + + whatsapp, _, _ := whatsappStartTest(t, directory, newTestClock()) + listener, err := daemonListenSocket(filepath.Join(directory, socketFileName)) + require.NoError(t, err) + + ctx, cancel := context.WithCancel(t.Context()) + defer cancel() + + done := make(chan error, 1) + go func() { + done <- daemonServe(ctx, listener, nil, whatsapp, agents[0].schedules, func(events func(Event)) (*TurnLoop, error) { + return agents[0].Loop(whatsapp, events) + }, agents[1:]...) + }() + + t.Cleanup(func() { + cancel() + require.NoError(t, <-done) + require.NoError(t, agents.Close()) + }) + + t.Setenv("ONECHAT_DIR", directory) + + var out bytes.Buffer + + args := []string{"--agent-id", agents[1].agent.config.ID, "--source", "check", "--id", "child-1", "--text", "A result for only the child."} + require.NoError(t, notify(t.Context(), args, &out)) + + var accepted Event + + require.NoError(t, json.Unmarshal(out.Bytes(), &accepted)) + require.Equal(t, "accepted", accepted.Status) + require.Eventually(t, func() bool { + data, err := os.ReadFile(filepath.Join(agents[0].agent.dir, "messages.json")) + if err != nil { + return false + } + + var queue DaemonMessageFile + + err = json.Unmarshal(data, &queue) + + return err == nil && len(queue.Pending) == 0 + }, 10*time.Second, time.Millisecond) + require.Equal(t, 1, server.Calls()) + require.Equal(t, "gpt-test-garden", server.Call(0).body["model"]) + require.Zero(t, agents[0].memory.Len()) + require.Zero(t, agents[2].memory.Len()) + + out.Reset() + require.NoError(t, notify(t.Context(), args, &out)) + + var duplicate Event + + require.NoError(t, json.Unmarshal(out.Bytes(), &duplicate)) + require.Equal(t, "duplicate", duplicate.Status) + require.Equal(t, accepted.ID, duplicate.ID) + + args[1] = agents[2].agent.config.ID + require.ErrorContains(t, notify(t.Context(), args, &out), "conflicts") + + args[1] = strings.Repeat("f", 2*agentIDBytes) + require.ErrorContains(t, notify(t.Context(), args, &out), "identity is unknown") + require.Equal(t, 1, server.Calls()) +} + func TestNotifyFlagsValidateBeforeConnecting(t *testing.T) { testCases := []struct { name string @@ -67,9 +154,21 @@ func TestNotifyFlagsValidateBeforeConnecting(t *testing.T) { args: []string{"-source", "check", "--id", "1", "--text", "data"}, }, { - name: "rejects child targets in the root-only slice", + name: "rejects name selectors", args: []string{"--agent", "Garden", "--source", "check", "--id", "1", "--text", "data"}, }, + { + name: "rejects an empty explicit agent ID", + args: []string{"--agent-id=", "--source", "check", "--id", "1", "--text", "data"}, + }, + { + name: "rejects malformed agent IDs", + args: []string{"--agent-id=Garden", "--source", "check", "--id", "1", "--text", "data"}, + }, + { + name: "rejects repeated agent IDs", + args: []string{"--agent-id", strings.Repeat("a", 2*agentIDBytes), "--agent-id", strings.Repeat("a", 2*agentIDBytes), "--source", "check", "--id", "1", "--text", "data"}, + }, { name: "rejects a flag without a value", args: []string{"--source"}, @@ -99,10 +198,11 @@ func TestNotifyFlagsValidateBeforeConnecting(t *testing.T) { }) } - input, err := notifyParse([]string{"--source=check", "--id=event.1", "--text=Ol\u00e1"}) + input, err := notifyParse([]string{"--agent-id=" + strings.Repeat("a", 2*agentIDBytes), "--source=check", "--id=event.1", "--text=Ol\u00e1"}) require.NoError(t, err) require.Equal(t, "check", input.Source) require.Equal(t, "event.1", input.ID) + require.Equal(t, strings.Repeat("a", 2*agentIDBytes), input.AgentID) } func TestNotifyHelpAndOfflineDaemon(t *testing.T) {