返回 DeepSeek-Reasonix
header_test.go
根目录 / internal / session / header_test.go
1 package session
2
3 import (
4 "encoding/json"
5 "errors"
6 "os"
7 "path/filepath"
8 goruntime "runtime"
9 "testing"
10 )
11
12 func TestFilesystemPersistenceCreatesImmutableSessionHeader(t *testing.T) {
13 root := t.TempDir()
14 persistence := NewFilesystemPersistence(root)
15 session, err := persistence.Create(CreateOptions{
16 SessionID: "child-session",
17 CWD: filepath.Join(root, "workspace"),
18 ParentSessionID: "parent-session",
19 Origin: SessionOriginFork,
20 })
21 if err != nil {
22 t.Fatalf("Create: %v", err)
23 }
24 if err := session.Close(t.Context()); err != nil {
25 t.Fatalf("Close: %v", err)
26 }
27
28 headerPath := filepath.Join(root, "child-session", sessionHeaderName)
29 body, err := os.ReadFile(headerPath)
30 if err != nil {
31 t.Fatalf("ReadFile(%s): %v", headerPath, err)
32 }
33 var header SessionHeader
34 if err := json.Unmarshal(body, &header); err != nil {
35 t.Fatalf("Unmarshal: %v", err)
36 }
37 if header.SchemaVersion != SessionHeaderSchemaVersion || header.SessionID != "child-session" ||
38 header.CWD != filepath.Join(root, "workspace") || header.ParentSessionID != "parent-session" ||
39 header.Origin != SessionOriginFork || header.CreatedAt.IsZero() {
40 t.Fatalf("header = %#v", header)
41 }
42 // Windows has no POSIX permission bits and always reports 0666 for a
43 // regular file, so assert the owner-only mode only where the OS can carry it.
44 if info, err := os.Stat(headerPath); err != nil {
45 t.Fatalf("Stat: %v", err)
46 } else if goruntime.GOOS != "windows" && info.Mode().Perm() != 0o600 {
47 t.Fatalf("header mode = %o, want 600", info.Mode().Perm())
48 }
49
50 info, err := persistence.Stat(t.Context(), "child-session")
51 if err != nil {
52 t.Fatalf("Stat session: %v", err)
53 }
54 if info.CWD != header.CWD || info.ParentSessionID != header.ParentSessionID || info.Origin != header.Origin {
55 t.Fatalf("SessionInfo = %#v", info)
56 }
57 }
58
59 func TestFilesystemPersistenceRejectsUnknownSessionHeaderVersion(t *testing.T) {
60 root := t.TempDir()
61 persistence := NewFilesystemPersistence(root)
62 session, err := persistence.Create(CreateOptions{SessionID: "future", CWD: root, Origin: SessionOriginNew})
63 if err != nil {
64 t.Fatalf("Create: %v", err)
65 }
66 if err := session.Close(t.Context()); err != nil {
67 t.Fatalf("Close: %v", err)
68 }
69 headerPath := filepath.Join(root, "future", sessionHeaderName)
70 if err := os.WriteFile(headerPath, []byte(`{"schemaVersion":99,"sessionId":"future"}`), 0o600); err != nil {
71 t.Fatalf("WriteFile: %v", err)
72 }
73
74 if _, err := persistence.Stat(t.Context(), "future"); !errors.Is(err, ErrUnsupportedVersion) {
75 t.Fatalf("Stat err = %v, want ErrUnsupportedVersion", err)
76 }
77 if _, err := persistence.Open("future", ReadOnly); !errors.Is(err, ErrUnsupportedVersion) {
78 t.Fatalf("Open err = %v, want ErrUnsupportedVersion", err)
79 }
80 }
81
82 func TestLegacySessionWithoutHeaderRemainsReadable(t *testing.T) {
83 root := t.TempDir()
84 persistence := NewFilesystemPersistence(root)
85 session, err := persistence.Create(CreateOptions{SessionID: "legacy-compatible"})
86 if err != nil {
87 t.Fatalf("Create: %v", err)
88 }
89 if err := session.Close(t.Context()); err != nil {
90 t.Fatalf("Close: %v", err)
91 }
92 if _, err := os.Stat(filepath.Join(root, "legacy-compatible", sessionHeaderName)); !os.IsNotExist(err) {
93 t.Fatalf("legacy header stat err = %v, want not exist", err)
94 }
95 if _, err := persistence.Open("legacy-compatible", ReadOnly); err != nil {
96 t.Fatalf("Open legacy-compatible: %v", err)
97 }
98 }
99
99 lines GO