返回 DeepSeek-Reasonix
windows_upgrade_fixture_test.go
根目录 / desktop / windows_upgrade_fixture_test.go
1 package main
2
3 import (
4 "encoding/json"
5 "os"
6 "path/filepath"
7 "sync"
8 "testing"
9
10 "reasonix/desktop/internal/upgradefixture"
11 "reasonix/internal/agent"
12 "reasonix/internal/config"
13 "reasonix/internal/session"
14 )
15
16 func TestWindowsUpgradeFixtureMigratesLegacyAndRestarts(t *testing.T) {
17 isolateDesktopUserDirs(t)
18 home := filepath.Join(t.TempDir(), "home # %20 中文")
19 t.Setenv("REASONIX_HOME", home)
20 t.Setenv("REASONIX_STATE_HOME", home)
21 t.Setenv("REASONIX_CACHE_HOME", filepath.Join(home, "cache"))
22 reportPath := filepath.Join(t.TempDir(), "fixture.json")
23 if err := upgradefixture.Run("create", home, reportPath, ""); err != nil {
24 t.Fatal(err)
25 }
26 // Reports and runtime manifests may spell the same file differently.
27 // Windows runtime paths fold drive case; dot segments exercise the same
28 // identity requirement on every platform without rewriting real history.
29 var report map[string]json.RawMessage
30 body, err := os.ReadFile(reportPath)
31 if err != nil {
32 t.Fatal(err)
33 }
34 if err := json.Unmarshal(body, &report); err != nil {
35 t.Fatal(err)
36 }
37 var legacyPath string
38 if err := json.Unmarshal(report["legacyPath"], &legacyPath); err != nil {
39 t.Fatal(err)
40 }
41 legacyPath = agent.CanonicalSessionPath(legacyPath)
42 report["legacyPath"], err = json.Marshal(filepath.Dir(legacyPath) + string(filepath.Separator) + "." + string(filepath.Separator) + filepath.Base(legacyPath))
43 if err != nil {
44 t.Fatal(err)
45 }
46 body, err = json.Marshal(report)
47 if err != nil {
48 t.Fatal(err)
49 }
50 if err := os.WriteFile(reportPath, body, 0600); err != nil {
51 t.Fatal(err)
52 }
53 for _, path := range []string{config.SessionStoreDir(), config.DesktopSessionStoreDir()} {
54 if _, err := os.Stat(path); !os.IsNotExist(err) {
55 t.Fatalf("fixture must not pre-create canonical history: %s: %v", path, err)
56 }
57 }
58 for _, phase := range []string{"first", "restart"} {
59 app := NewApp()
60 closeApp := sync.OnceFunc(func() {
61 app.stopHistoricalImports()
62 app.closeSessionServices()
63 if err := app.draftStore().Close(); err != nil {
64 t.Errorf("close fixture draft store: %v", err)
65 }
66 })
67 t.Cleanup(closeApp)
68 if app.NeedsOnboarding() {
69 t.Fatal("legacy fixture must restore the conversation instead of opening first-run provider settings")
70 }
71 app.startDesktopSessionMigration(t.Context())
72 if !app.waitForDesktopMigration(t.Context()) {
73 t.Fatal("startup discovery did not finish")
74 }
75 if phase == "first" {
76 file, _ := app.reconcileSavedTabs(t.Context(), loadTabsFile())
77 if len(file.Tabs) != 1 || file.Tabs[0].historicalSource == nil {
78 t.Fatalf("saved historical tab must be pending, not corrupt: %+v", file.Tabs)
79 }
80 tab := &WorkspaceTab{}
81 if prepareRestoredTabIdentity(tab, file.Tabs[0]) || tab.Ctrl != nil || tab.StartupErr != "" || tab.HistoricalSource == nil {
82 t.Fatalf("passive restore started a runtime or reported corruption: %+v", tab)
83 }
84 state, err := app.workspaceRegistry().Load(t.Context())
85 if err != nil || len(state.SourceMappings) != 0 || len(state.PendingOperations) != 0 {
86 t.Fatalf("startup converted historical content: %+v, %v", state, err)
87 }
88 if _, err := app.ImportHistoricalSession(desktopSourceKey(legacyPath, "")); err != nil {
89 t.Fatalf("explicit user preparation failed: %v", err)
90 }
91 }
92 if phase == "restart" {
93 // Real startup also snapshots the current registry before recovery.
94 if err := app.backupDesktopUpgradeMetadata(t.Context()); err != nil {
95 t.Fatal(err)
96 }
97 }
98 if err := upgradefixture.Run("verify", home, reportPath, phase); err != nil {
99 t.Fatalf("%s: %v", phase, err)
100 }
101 var evidence struct {
102 SessionID string `json:"sessionId"`
103 History string `json:"history"`
104 }
105 body, err := os.ReadFile(filepath.Join(filepath.Dir(reportPath), "verification-"+phase+".json"))
106 if err != nil {
107 t.Fatal(err)
108 }
109 if err := json.Unmarshal(body, &evidence); err != nil {
110 t.Fatal(err)
111 }
112 page, err := app.ReadSessionHistory(session.SessionRef{HostID: localDesktopHostID, SessionID: evidence.SessionID}, "", 10)
113 if err != nil || len(page.Messages) != 2 || page.Messages[1].Content != evidence.History {
114 t.Fatalf("%s history API: %+v, %v", phase, page, err)
115 }
116 closeApp()
117 }
118 }
119
119 lines GO