package main import ( "context" "net/http/httptest" "os" "path/filepath" "strings" "testing" "time" ) // newLiveNestServer builds the server over the real brain from env (NewBrain) // instead of the mock. Requires an API key; callers must skip first. func newLiveNestServer(t *testing.T) (*Server, string) { t.Helper() dir := t.TempDir() ledger, _ := LoadLedger(filepath.Join(dir, "ledger.json")) flog, err := OpenFlightLog(filepath.Join(dir, "flight.jsonl")) if err != nil { t.Fatal(err) } t.Cleanup(func() { flog.Close() }) nests, _ := LoadNests(filepath.Join(dir, "nests.json")) msgs, _ := LoadMessageStore(filepath.Join(dir, "messages")) ctx, cancel := context.WithCancel(context.Background()) approver := NewWebApprover(time.Minute) p := &Pipeline{Flock: NewFlock(NewBrain(), DefaultGuardrails(), flog), Ledger: ledger, Log: flog, G: DefaultGuardrails(), Approver: approver} s := NewServer(ctx, p, approver, nests).WithMessages(msgs) ts := httptest.NewServer(s.Handler()) t.Cleanup(func() { cancel(); ts.Close() }) return s, filepath.Join(dir, "flight.jsonl") } func TestLiveCrowDeliversInNest(t *testing.T) { if os.Getenv("OPENROUTER_API_KEY") == "" && os.Getenv("ANTHROPIC_API_KEY") == "" { t.Skip("no model key") } s, logPath := newLiveNestServer(t) nest, err := s.nests.Create("Live Lab", []string{"Hugin"}) if err != nil { t.Fatal(err) } req, err := s.msgs.Append(Message{NestID: nest.ID, Kind: "request", Author: "owner", To: "Hugin", Text: "What is the plural of crow?", Timestamp: time.Now().UTC().Format(time.RFC3339)}) if err != nil { t.Fatal(err) } // Synchronous call, like the endpoint's goroutine would. s.respondToRequest(nest, req) msgs := s.msgs.All(nest.ID) var reply *Message for i := range msgs { if msgs[i].Author == "Hugin" { reply = &msgs[i] } } events, err := ReadEvents(logPath) if err != nil { t.Fatal(err) } if reply == nil { // No crow message at all: either a flight failure (429/timeout: the // known free-model instability -> skip) or nothing was even attempted. flightFailed := false for _, e := range events { if e.Kind == "flight" && e.Error != "" { flightFailed = true } } if flightFailed { t.Skip("upstream model failed (known free-model instability); the flag path is covered by #11") } t.Fatalf("no Hugin reply after a request, log: %+v", msgs) } kind := reply.Kind if kind != "deliver" && kind != "claim" && kind != "decline" { t.Fatalf("live crow reply must be responsive, got %q (%s)", kind, reply.Text) } if reply.To != "owner" { t.Fatalf("deliver must answer the requester, got to=%q", reply.To) } if reply.RefersTo != req.MsgID() { t.Fatalf("reply must point at the request, got %q", reply.RefersTo) } // The call went through Flock.ask, so the flight log has Hugin's flight. flights := 0 for _, e := range events { if e.Crow == "Hugin" && e.Model != "" && !strings.Contains(strings.ToLower(e.Model), "mock") { flights++ } } if flights == 0 { t.Fatalf("want a logged non-mock Hugin flight, events: %+v", events) } }