返回 DeepSeek-Reasonix
topic_archive_migrated_test.go
根目录 / desktop / topic_archive_migrated_test.go
1 package main
2
3 import (
4 "errors"
5 "os"
6 "path/filepath"
7 "testing"
8 "time"
9
10 "reasonix/internal/agent"
11 "reasonix/internal/config"
12 "reasonix/internal/control"
13 "reasonix/internal/event"
14 )
15
16 func TestMigratedTopicArchiveOwnershipRollback(t *testing.T) {
17 path := filepath.Join(t.TempDir(), "legacy.jsonl")
18 tab := &WorkspaceTab{ID: "migrated", SessionID: "canonical-session"}
19 if err := tab.ensureSessionLease(path); err != nil {
20 t.Fatal(err)
21 }
22 defer tab.releaseSessionLease()
23 targets := []topicTrashTarget{{dir: filepath.Dir(path), sessionPath: path, key: filepath.Base(path)}}
24 batch, err := acquireTopicArchiveOwnership(targets, []removedSessionRuntime{{tab: tab}})
25 if err != nil {
26 t.Fatal(err)
27 }
28 defer batch.rollback()
29 assertOwned := func() {
30 t.Helper()
31 lease, err := agent.TryAcquireSessionLease(path)
32 if lease != nil {
33 lease.Release()
34 }
35 if !errors.Is(err, agent.ErrSessionLeaseHeld) {
36 t.Fatalf("competing writer acquired the legacy lease: %v", err)
37 }
38 }
39 assertOwned()
40 batch.rollback()
41 if tab.sessionLeaseRuntimeKey() != sessionRuntimeKey(path) || tab.SessionID != "canonical-session" || tab.SessionPath != "" {
42 t.Fatal("rollback did not preserve canonical identity and legacy ownership")
43 }
44 assertOwned()
45 }
46
47 func TestArchiveWithMigratedLeaseOwner(t *testing.T) {
48 for _, operation := range []string{"topic", "session"} {
49 t.Run(operation, func(t *testing.T) {
50 for _, detached := range []bool{false, true} {
51 name := "visible"
52 if detached {
53 name = "detached"
54 }
55 t.Run(name, func(t *testing.T) {
56 isolateDesktopUserDirs(t)
57 root := canonicalRuntimeRoot(t.TempDir())
58 topicID := "topic_migrated_lease"
59 if err := addProject(root, ""); err != nil {
60 t.Fatal(err)
61 }
62 if err := setTopicTitle(root, topicID, "Migrated session"); err != nil {
63 t.Fatal(err)
64 }
65 dir := config.SessionDir()
66 if err := os.MkdirAll(dir, 0o755); err != nil {
67 t.Fatal(err)
68 }
69 path := writeTopicSessionWithPrompt(t, dir, "migrated.jsonl", topicID, "Migrated session", root, "keep history", time.Now())
70 // Canonical identity publication clears the legacy path while the
71 // tab can still own the imported file's compatibility lease.
72 app := NewApp()
73 pinDesktopSessionRoot(t, app)
74 ctrl := control.New(control.Options{
75 SessionDir: dir, WorkspaceRoot: root,
76 Executor: agent.New(nil, nil, agent.NewSession("test"), agent.Options{}, event.Discard),
77 SessionService: app.desktopSessionService(dir), ExclusiveSession: true,
78 })
79 defer ctrl.Close()
80 ref, err := ctrl.ContinueLegacySessionWithOptions(t.Context(), path, "", desktopLegacyImportOptions(root))
81 if err != nil {
82 t.Fatal(err)
83 }
84 workspaceID, err := app.attachDesktopSession(t.Context(), "project", root, ref)
85 if err != nil {
86 t.Fatal(err)
87 }
88 tab := &WorkspaceTab{ID: "migrated", Scope: "project", WorkspaceRoot: root,
89 TopicID: topicID, SessionID: ref.SessionID, Ctrl: ctrl, Ready: true}
90 tab.SessionWorkspace.ID = workspaceID
91 if err := tab.ensureSessionLease(path); err != nil {
92 t.Fatal(err)
93 }
94 defer tab.releaseSessionLease()
95 keep := &WorkspaceTab{ID: "keep", Scope: "project", WorkspaceRoot: root, TopicID: "keep", Ready: true}
96 app.tabs, app.tabOrder, app.activeTabID = map[string]*WorkspaceTab{keep.ID: keep}, []string{keep.ID}, keep.ID
97 if detached {
98 app.detachedSessions = map[string]*WorkspaceTab{tab.currentSessionIdentity(): tab}
99 } else {
100 app.tabs[tab.ID] = tab
101 app.tabOrder = append(app.tabOrder, tab.ID)
102 app.activeTabID = tab.ID
103 }
104 if !app.sessionOpen(dir, path) {
105 t.Fatal("migrated compatibility lease must still mark its legacy file as open")
106 }
107 var archiveErr error
108 if operation == "topic" {
109 archiveErr = app.TrashTopic(topicID)
110 } else {
111 archiveErr = app.DeleteSession(path)
112 }
113 if err := archiveErr; err != nil {
114 t.Fatalf("archive migrated owner: %v", err)
115 }
116 if !tab.removed || tab.sessionLeaseRuntimeKey() != "" {
117 t.Fatal("archive retained the migrated runtime or its lease")
118 }
119 if _, err := os.Stat(path); err != nil {
120 t.Fatalf("legacy source was not preserved: %v", err)
121 }
122 page, err := app.ListWorkspaceSessions(workspaceID, "", "", 10, true)
123 if err != nil || len(page.Sessions) != 1 || !page.Sessions[0].Archived {
124 t.Fatalf("archive state missing: %+v, %v", page, err)
125 }
126 })
127 }
128 })
129 }
130 }
131
131 lines GO