返回 DeepSeek-Reasonix
historical_conversion_identity_test.go
根目录 / desktop / historical_conversion_identity_test.go
1 package main
2
3 import (
4 "os"
5 "path/filepath"
6 "reflect"
7 "testing"
8
9 "reasonix/desktop/internal/workspacestate"
10 "reasonix/internal/config"
11 "reasonix/internal/session"
12 )
13
14 // Lineage migration carries a legacy head into the receipt for its converted
15 // single-session directory. Discovery addresses that directory without a head.
16 func TestHistoricalConvertedHeadKeepsLifecycleAfterRestart(t *testing.T) {
17 for _, lifecycle := range []string{workspacestate.Active, workspacestate.Archived, workspacestate.Deleted} {
18 t.Run(lifecycle, func(t *testing.T) {
19 isolateDesktopUserDirs(t)
20 const id = "converted-head"
21 root := config.SessionStoreDir()
22 old := coldV4MigrationFixture(t, root, id)
23 before := migrationSourceSnapshot(t, canonicalMigrationSourceFiles(root, id))
24 app := newHistoricalLifecycleApp(t)
25 source := desktopMigrationSource{root: root, scope: "global", headID: "main"}
26 if err := app.migrateCanonicalSession(t.Context(), old, source, "", id); err != nil {
27 t.Fatal(err)
28 }
29 original, err := app.workspaceRegistry().Load(t.Context())
30 if err != nil {
31 t.Fatal(err)
32 }
33 ref := session.SessionRef{HostID: localDesktopHostID, SessionID: id}
34 if lifecycle != workspacestate.Active {
35 if err := app.ArchiveCanonicalSession(ref); err != nil {
36 t.Fatal(err)
37 }
38 }
39 if lifecycle == workspacestate.Deleted {
40 if err := app.PurgeCanonicalSession(ref); err != nil {
41 t.Fatal(err)
42 }
43 // Older builds retained some purged sources. Recreate that disk
44 // layout without changing the durable deletion receipt.
45 for path, body := range before {
46 if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
47 t.Fatal(err)
48 }
49 if err := os.WriteFile(path, body, 0600); err != nil {
50 t.Fatal(err)
51 }
52 }
53 }
54 app.stopHistoricalImports()
55 app.closeSessionServices()
56 app = newHistoricalLifecycleApp(t)
57 if _, err := app.ListHistoricalSessions(); err != nil {
58 t.Fatal(err)
59 }
60 page, err := app.ListProjectTopics(ProjectTopicPageRequest{Scope: "global", Limit: 50})
61 want := 0
62 if lifecycle == workspacestate.Active {
63 want = 1
64 }
65 if lifecycle == workspacestate.Deleted {
66 // Recreating the retained directory above changes its filesystem
67 // revision. Metadata-only discovery cannot certify it unchanged;
68 // explicit archive verifies the original fingerprint once.
69 if _, err := app.ArchiveSessionTarget(SessionSelector{Source: &SessionSourceRef{Path: filepath.Join(root, id), SourceKey: desktopSourceKey(filepath.Join(root, id), "")}}); err != nil {
70 t.Fatal(err)
71 }
72 if _, err := app.ListHistoricalSessions(); err != nil {
73 t.Fatal(err)
74 }
75 page, err = app.ListProjectTopics(ProjectTopicPageRequest{Scope: "global", Limit: 50})
76 }
77 if err != nil || len(page.Items) != want {
78 t.Fatalf("converted source reappeared as a new sidebar row: got %d, want %d: %v", len(page.Items), want, err)
79 }
80 key := desktopSourceKey(filepath.Join(root, id), "")
81 result, err := app.ImportHistoricalSession(key)
82 if lifecycle == workspacestate.Active {
83 if err != nil || result.Session != ref {
84 t.Fatalf("directory selector lost existing target: %+v %v", result, err)
85 }
86 archived, err := app.ArchiveSessionTarget(SessionSelector{Source: &SessionSourceRef{Path: filepath.Join(root, id), SourceKey: key}})
87 if err != nil || !archived.Committed {
88 t.Fatalf("archive through directory selector: %+v %v", archived, err)
89 }
90 if err := app.RestoreCanonicalSession(ref); err != nil {
91 t.Fatal(err)
92 }
93 } else if err == nil {
94 t.Fatal("directory selector revived a retired conversion")
95 }
96 state, err := app.workspaceRegistry().Load(t.Context())
97 if err != nil || state.SessionStates[id].Lifecycle != lifecycle || !reflect.DeepEqual(state.SourceMappings, original.SourceMappings) {
98 t.Fatalf("conversion receipt changed: %v", err)
99 }
100 assertMigrationSourceSnapshot(t, before)
101 })
102 }
103 }
104
104 lines GO