返回 DeepSeek-Reasonix
session_activity_baseline_test.go
根目录 / desktop / session_activity_baseline_test.go
1 package main
2
3 import (
4 "encoding/json"
5 "os"
6 "path/filepath"
7 "strconv"
8 "testing"
9
10 "reasonix/desktop/internal/workspacestate"
11 "reasonix/internal/provider"
12 "reasonix/internal/session"
13 )
14
15 func TestSessionActivityBaselineColdPendingMetadataIsNotComplete(t *testing.T) {
16 app, ref := activityBaselineFixture(t, "cold-baseline")
17 service := app.desktopSessionService("")
18 if err := service.SetTitle(t.Context(), ref, "Cold session"); err != nil {
19 t.Fatal(err)
20 }
21 if err := service.Close(t.Context(), ref); err != nil {
22 t.Fatal(err)
23 }
24 // Freeze only the disposable-cache rebuild scheduler to make a missing cold
25 // cache deterministic. Stat remains a header-only read on this service.
26 service.Query().Close()
27 metadataPath := filepath.Join(app.desktopSessions.root, ".query-cache", ref.SessionID, "catalog-metadata.json")
28 if err := os.Remove(metadataPath); err != nil {
29 t.Fatal(err)
30 }
31 baseline, err := app.GetSessionActivityBaseline(SessionSelector{Ref: &ref})
32 if err != nil {
33 t.Fatal(err)
34 }
35 if baseline.Complete {
36 t.Fatalf("missing cold metadata produced a complete baseline: %+v", baseline)
37 }
38 if baseline.Ref != ref || baseline.LifecycleGeneration == 0 {
39 t.Fatalf("pending observation lost its explicit identity: %+v", baseline)
40 }
41 }
42
43 func TestSessionActivityBaselineUsesLiveResultSequenceAndEventVersion(t *testing.T) {
44 app, ref := activityBaselineFixture(t, "live-baseline")
45 service := app.desktopSessionService("")
46 runtime, ok := service.Runtime(ref)
47 if !ok {
48 t.Fatal("fixture runtime missing")
49 }
50 payload, err := json.Marshal(map[string]any{"message": provider.Message{ID: "answer", Role: provider.RoleAssistant, Content: "Completed result"}})
51 if err != nil {
52 t.Fatal(err)
53 }
54 commit, err := runtime.Session().Append(t.Context(), session.Batch{OperationID: "turn", TurnID: "turn", Events: []session.Event{
55 {Kind: "turn/start"},
56 {Kind: "message/complete", Payload: payload},
57 {Kind: "turn/end", Payload: json.RawMessage(`{"status":"completed"}`)},
58 }})
59 if err != nil {
60 t.Fatal(err)
61 }
62 resultSequence := commit.FirstSequence + uint64(commit.EventCount) - 1
63 // A title event advances the owner event version without creating a result.
64 if err := service.SetTitle(t.Context(), ref, "A later title"); err != nil {
65 t.Fatal(err)
66 }
67 baseline, err := app.GetSessionActivityBaseline(SessionSelector{Ref: &ref})
68 if err != nil {
69 t.Fatal(err)
70 }
71 if !baseline.Complete || baseline.Ref != ref || baseline.ResultSequence != resultSequence {
72 t.Fatalf("live baseline = %+v, want result sequence %d", baseline, resultSequence)
73 }
74 eventSequence, err := strconv.ParseUint(baseline.EventVersion, 10, 64)
75 if err != nil || eventSequence <= baseline.ResultSequence {
76 t.Fatalf("event version %q does not distinguish the later title from result %d", baseline.EventVersion, baseline.ResultSequence)
77 }
78 if baseline.LifecycleGeneration == 0 {
79 t.Fatal("live observation omitted lifecycle evidence")
80 }
81 }
82
83 func activityBaselineFixture(t *testing.T, id string) (*App, session.SessionRef) {
84 t.Helper()
85 isolateDesktopUserDirs(t)
86 root := t.TempDir()
87 app := NewApp()
88 t.Cleanup(app.closeSessionServices)
89 app.ctx = t.Context()
90 app.desktopSessions.root = filepath.Join(root, "by-id")
91 app.desktopSessions.workspaceState = workspacestate.NewStore(filepath.Join(root, "workspace-state.json"))
92 workspaceID, err := app.ensureDesktopWorkspace(t.Context(), "project", root)
93 if err != nil {
94 t.Fatal(err)
95 }
96 runtime, err := app.desktopSessionService("").Create(t.Context(), session.CreateOptions{SessionID: id, CWD: root, Origin: session.SessionOriginNew})
97 if err != nil {
98 t.Fatal(err)
99 }
100 if err := app.workspaceRegistry().AttachSession(t.Context(), "", workspaceID, id, ""); err != nil {
101 t.Fatal(err)
102 }
103 return app, runtime.Ref()
104 }
105
105 lines GO