返回 DeepSeek-Reasonix
historical_archive_versions_test.go
根目录 / desktop / historical_archive_versions_test.go
1 package main
2
3 import (
4 "os"
5 "path/filepath"
6 "testing"
7
8 "reasonix/desktop/internal/workspacestate"
9 "reasonix/internal/agent"
10 "reasonix/internal/provider"
11 )
12
13 // Every rewind keeps the head it left as a version, and the sidebar lists each
14 // version of a legacy transcript as its own row with the same title. Archiving
15 // one of them archives the conversation, once, however often it is repeated.
16 func TestArchivingLegacyVersionRowArchivesEveryVersionOnce(t *testing.T) {
17 isolateDesktopUserDirs(t)
18 path, legacy, mainHead := migrationSingleDAGFixture(t)
19 legacy.Add(provider.Message{ID: "answer", Role: provider.RoleAssistant, Content: "first answer"})
20 if err := legacy.Save(path); err != nil {
21 t.Fatal(err)
22 }
23 versions := []string{mainHead}
24 for _, retry := range []string{"second answer", "third answer", "fourth answer"} {
25 head, err := legacy.ForkHead(path, "question", agent.HeadKindRewind, "")
26 if err != nil {
27 t.Fatal(err)
28 }
29 legacy.Add(provider.Message{Role: provider.RoleAssistant, Content: retry})
30 if err := legacy.Save(path); err != nil {
31 t.Fatal(err)
32 }
33 versions = append(versions, head)
34 }
35 fork, err := legacy.ForkHead(path, "question", agent.HeadKindFork, "separate idea")
36 if err != nil {
37 t.Fatal(err)
38 }
39 legacy.Add(provider.Message{Role: provider.RoleAssistant, Content: "forked answer"})
40 if err := legacy.Save(path); err != nil {
41 t.Fatal(err)
42 }
43 before, err := desktopSourceFingerprint(path)
44 if err != nil {
45 t.Fatal(err)
46 }
47
48 app := NewApp()
49 app.ctx = t.Context()
50 root := pinDesktopSessionRoot(t, app)
51 installNoopRuntimeEvents(app)
52 t.Cleanup(app.closeSessionServices)
53 installSessionCatalogForTest(t, app, filepath.Dir(path), "global", "")
54 rowHeads := func() map[string]bool {
55 t.Helper()
56 page, err := app.ListProjectTopics(ProjectTopicPageRequest{Scope: "global", Limit: 50})
57 if err != nil {
58 t.Fatal(err)
59 }
60 heads := map[string]bool{}
61 for _, row := range page.Items {
62 if row.Source == nil {
63 t.Fatalf("unexpected materialized row: %+v", row)
64 }
65 heads[row.Source.HeadID] = true
66 }
67 return heads
68 }
69 if got := rowHeads(); len(got) != len(versions)+1 || !got[fork] {
70 t.Fatalf("fixture rows = %v; want %d versions and the fork", got, len(versions))
71 }
72
73 selector := SessionSelector{Source: &SessionSourceRef{HostID: localDesktopHostID, Path: path, HeadID: versions[2]}}
74 var dirs int
75 for attempt := range 3 {
76 result, err := app.ArchiveSessionTarget(selector)
77 if err != nil || !result.Committed {
78 t.Fatalf("archive %d = %+v, %v", attempt, result, err)
79 }
80 if got := rowHeads(); len(got) != 1 || !got[fork] {
81 t.Fatalf("archive %d left rows %v; want only the fork", attempt, got)
82 }
83 state, err := app.workspaceRegistry().Load(t.Context())
84 if err != nil {
85 t.Fatal(err)
86 }
87 if len(state.SourceMappings) != len(versions) || len(state.SessionStates) != len(versions) {
88 t.Fatalf("archive %d: %d mappings, %d sessions; want one per version (%d)",
89 attempt, len(state.SourceMappings), len(state.SessionStates), len(versions))
90 }
91 mapped := map[string]string{}
92 for _, mapping := range state.SourceMappings {
93 if !sameDesktopPath(mapping.Path, path) {
94 t.Fatalf("mapping for another source: %+v", mapping)
95 }
96 if previous, dup := mapped[mapping.HeadID]; dup {
97 t.Fatalf("head %s materialized twice: %s and %s", mapping.HeadID, previous, mapping.SessionID)
98 }
99 mapped[mapping.HeadID] = mapping.SessionID
100 if lifecycle := state.SessionStates[mapping.SessionID].Lifecycle; lifecycle != workspacestate.Archived {
101 t.Fatalf("version %s is %v, not archived", mapping.HeadID, lifecycle)
102 }
103 }
104 for _, head := range versions {
105 if _, ok := mapped[head]; !ok {
106 t.Fatalf("version %s was not archived: %v", head, mapped)
107 }
108 }
109 entries, err := os.ReadDir(root)
110 if err != nil {
111 t.Fatal(err)
112 }
113 if attempt == 0 {
114 dirs = len(entries)
115 } else if len(entries) != dirs {
116 t.Fatalf("archive %d wrote new session storage: %d entries, was %d", attempt, len(entries), dirs)
117 }
118 }
119 if after, err := desktopSourceFingerprint(path); err != nil || after != before {
120 t.Fatalf("archive changed the legacy source: %v", err)
121 }
122 }
123
123 lines GO