| 1 | package serve |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "encoding/json" |
| 6 | "net/http" |
| 7 | "net/http/httptest" |
| 8 | "os" |
| 9 | "path/filepath" |
| 10 | "testing" |
| 11 | |
| 12 | "reasonix/internal/agent" |
| 13 | "reasonix/internal/config" |
| 14 | "reasonix/internal/control" |
| 15 | "reasonix/internal/event" |
| 16 | "reasonix/internal/session" |
| 17 | ) |
| 18 | |
| 19 | // TestSessionsFoldsEngineMirrorOfLegacyTranscript pins the listing fold: the |
| 20 | // engine mirrors an in-flight legacy transcript into a final-format event log |
| 21 | // keyed by the legacy branch id; the /sessions view must keep one row for that |
| 22 | // conversation instead of a transcript row plus its mirror. |
| 23 | func TestSessionsFoldsEngineMirrorOfLegacyTranscript(t *testing.T) { |
| 24 | legacyDir := t.TempDir() |
| 25 | legacy := filepath.Join(legacyDir, "mirror-me.jsonl") |
| 26 | if err := os.WriteFile(legacy, []byte(`{"role":"user","content":"hi"}`+"\n"), 0o600); err != nil { |
| 27 | t.Fatal(err) |
| 28 | } |
| 29 | v4Root := filepath.Join(t.TempDir(), "sessions-v4") |
| 30 | persistence := session.NewFilesystemPersistence(v4Root) |
| 31 | mirror, err := persistence.Create(session.CreateOptions{SessionID: "mirror-me"}) |
| 32 | if err != nil { |
| 33 | t.Fatal(err) |
| 34 | } |
| 35 | if err := mirror.Close(t.Context()); err != nil { |
| 36 | t.Fatal(err) |
| 37 | } |
| 38 | service, err := session.NewService("serve-test", persistence) |
| 39 | if err != nil { |
| 40 | t.Fatal(err) |
| 41 | } |
| 42 | t.Cleanup(func() { |
| 43 | if err := service.Shutdown(context.Background()); err != nil { |
| 44 | t.Errorf("shutdown session service: %v", err) |
| 45 | } |
| 46 | }) |
| 47 | exec := agent.New(nil, nil, agent.NewSession("system"), agent.Options{}, event.Discard) |
| 48 | ctrl := control.New(control.Options{Executor: exec, SessionDir: legacyDir, SessionService: service, ExclusiveSession: true}) |
| 49 | if _, err := ctrl.BindFreshSession(t.Context(), "foreground"); err != nil { |
| 50 | t.Fatal(err) |
| 51 | } |
| 52 | t.Cleanup(ctrl.Close) |
| 53 | srv := newLifecycleTestServer(t, ctrl, NewBroadcaster(), config.ServeConfig{}) |
| 54 | recorder := httptest.NewRecorder() |
| 55 | srv.sessions(recorder, httptest.NewRequest(http.MethodGet, "/sessions", nil)) |
| 56 | var rows []sessionListEntry |
| 57 | if err := json.Unmarshal(recorder.Body.Bytes(), &rows); err != nil { |
| 58 | t.Fatal(err) |
| 59 | } |
| 60 | legacyKey := agent.CanonicalSessionPath(legacy) |
| 61 | sawLegacy, sawMirror := false, false |
| 62 | for _, row := range rows { |
| 63 | if agent.CanonicalSessionPath(row.Path) == legacyKey { |
| 64 | sawLegacy = true |
| 65 | } |
| 66 | if row.SessionID == "mirror-me" { |
| 67 | sawMirror = true |
| 68 | } |
| 69 | } |
| 70 | if !sawLegacy { |
| 71 | t.Fatalf("legacy row missing from listing: %+v", rows) |
| 72 | } |
| 73 | if sawMirror { |
| 74 | t.Fatalf("engine mirror listed beside its transcript: %+v", rows) |
| 75 | } |
| 76 | retireExclusiveForeground(t, ctrl, service) |
| 77 | } |
| 78 |