返回 DeepSeek-Reasonix
session_reader_test.go
根目录 / internal / session / session_reader_test.go
1 package session
2
3 import (
4 "context"
5 "encoding/json"
6 "os"
7 "path/filepath"
8 "strings"
9 "testing"
10
11 "reasonix/internal/provider"
12 )
13
14 func TestOpenSessionUsesRecentBaselineWithoutQueryIndexes(t *testing.T) {
15 root := filepath.Join(t.TempDir(), "sessions-v4")
16 service, err := NewService("local", NewFilesystemPersistence(root))
17 if err != nil {
18 t.Fatal(err)
19 }
20 t.Cleanup(func() { _ = service.CloseAll(context.Background()) })
21 runtime, err := service.Create(t.Context(), CreateOptions{SessionID: "open-view"})
22 if err != nil {
23 t.Fatal(err)
24 }
25 appendRecoveryTestMessage(t, runtime.Session(), "message", strings.Repeat("recent", 12_000))
26 if _, err := runtime.Session().Flush(t.Context()); err != nil {
27 t.Fatal(err)
28 }
29 recentInfo, err := os.Stat(filepath.Join(recoveryCacheDir(filepath.Join(root, "open-view")), recentSnapshotName))
30 if err != nil {
31 t.Fatal(err)
32 }
33 if recentInfo.Size() > recentResponseBytes+(64<<10) {
34 t.Fatalf("recent snapshot size=%d", recentInfo.Size())
35 }
36 ref := runtime.Ref()
37 if err := service.Close(t.Context(), ref); err != nil {
38 t.Fatal(err)
39 }
40 if err := os.RemoveAll(filepath.Join(root, ".query-cache", ref.SessionID)); err != nil {
41 t.Fatal(err)
42 }
43
44 view, err := service.OpenSession(t.Context(), ref)
45 if err != nil {
46 t.Fatal(err)
47 }
48 if view.Recovery != PreparationPreparing || view.CanExecute || view.StorageGeneration == "" || len(view.Recent.Entries) != 1 {
49 t.Fatalf("cold open view = %+v", view)
50 }
51 refContent := view.Recent.Entries[0].ContentRef
52 if refContent == nil {
53 t.Fatal("large recent message was not replaced with a content reference")
54 }
55 var preview provider.Message
56 if err := json.Unmarshal(view.Recent.Entries[0].Inline, &preview); err != nil {
57 t.Fatalf("decode recent preview: %v", err)
58 }
59 if preview.Content == "" || len(preview.Content) >= len(strings.Repeat("recent", 12_000)) {
60 t.Fatalf("recent preview content length=%d", len(preview.Content))
61 }
62 data, err := service.Query().ReadContent(t.Context(), ref, *refContent, 0, 32)
63 if err != nil || len(data) != 32 {
64 t.Fatalf("read recent content without indexes: bytes=%d err=%v", len(data), err)
65 }
66 inspection, err := service.Query().InspectSession(t.Context(), ref)
67 if err != nil || inspection.Commits != 1 || inspection.Events != 1 || inspection.DurableSequence == 0 || inspection.StorageGeneration != view.StorageGeneration {
68 t.Fatalf("inspection = %+v, %v", inspection, err)
69 }
70 binding, err := service.EnsureExecution(t.Context(), ref)
71 if err != nil {
72 t.Fatal(err)
73 }
74 defer binding.Release(context.Background())
75 live, err := service.OpenSession(t.Context(), ref)
76 if err != nil {
77 t.Fatal(err)
78 }
79 if live.Recovery != PreparationReady || !live.CanExecute || len(live.Recent.Entries) != 1 {
80 t.Fatalf("live open view = %+v", live)
81 }
82 }
83
84 func TestOpenSessionRejectsRecentSnapshotAfterPhysicalLogReplacement(t *testing.T) {
85 root := filepath.Join(t.TempDir(), "sessions-v4")
86 service, err := NewService("local", NewFilesystemPersistence(root))
87 if err != nil {
88 t.Fatal(err)
89 }
90 t.Cleanup(func() { _ = service.CloseAll(context.Background()) })
91 runtime, err := service.Create(t.Context(), CreateOptions{SessionID: "replaced"})
92 if err != nil {
93 t.Fatal(err)
94 }
95 appendRecoveryTestMessage(t, runtime.Session(), "message", "recent")
96 if _, err := runtime.Session().Flush(t.Context()); err != nil {
97 t.Fatal(err)
98 }
99 ref := runtime.Ref()
100 if err := service.Close(t.Context(), ref); err != nil {
101 t.Fatal(err)
102 }
103 dir := filepath.Join(root, ref.SessionID)
104 manifest, err := readStoredManifest(filepath.Join(dir, "manifest.json"))
105 if err != nil {
106 t.Fatal(err)
107 }
108 log, err := os.OpenFile(logPathForManifest(dir, manifest), os.O_WRONLY, 0)
109 if err != nil {
110 t.Fatal(err)
111 }
112 if _, err := log.WriteAt([]byte("X"), 0); err != nil {
113 _ = log.Close()
114 t.Fatal(err)
115 }
116 _ = log.Close()
117 view, err := service.OpenSession(t.Context(), ref)
118 if err != nil {
119 t.Fatal(err)
120 }
121 if view.Recovery != PreparationPreparing || len(view.Recent.Entries) != 0 {
122 t.Fatalf("replaced log exposed stale recent snapshot: %+v", view)
123 }
124 }
125
125 lines GO