返回 DeepSeek-Reasonix
session_recovery_rebase_test.go
根目录 / desktop / session_recovery_rebase_test.go
1 package main
2
3 import (
4 "path/filepath"
5 "testing"
6
7 "reasonix/internal/agent"
8 "reasonix/internal/config"
9 "reasonix/internal/provider"
10 "reasonix/internal/session"
11 )
12
13 func TestRestoreRecoveryUsesSourceVersionOnDiskAfterFurtherChange(t *testing.T) {
14 isolateDesktopUserDirs(t)
15 root := config.SessionDir()
16 sourceFile := filepath.Join(root, "old.jsonl")
17 legacy := agent.NewSession("system")
18 legacy.Add(provider.Message{ID: "old", Role: provider.RoleUser, Content: "original work"})
19 if err := legacy.Save(sourceFile); err != nil {
20 t.Fatal(err)
21 }
22 appendLine := func(content string) {
23 legacy.Add(provider.Message{ID: content, Role: provider.RoleUser, Content: content})
24 if err := legacy.Save(sourceFile); err != nil {
25 t.Fatal(err)
26 }
27 }
28 source := desktopMigrationSource{root: root, scope: "global", exact: map[string]bool{sourceFile: true}}
29 migrate := func(app *App) {
30 t.Helper()
31 if err := app.migrateLegacyDirectory(t.Context(), source); err != nil {
32 t.Fatal(err)
33 }
34 source.exact = nil
35 }
36 restart := func(app *App) *App {
37 app.closeSessionServices()
38 next := NewApp()
39 t.Cleanup(next.closeSessionServices)
40 return next
41 }
42 pending := func(app *App) []RecoveryEntryView {
43 t.Helper()
44 page, err := app.ListRecoveryEntries("", "", 50)
45 if err != nil {
46 t.Fatal(err)
47 }
48 return page.Items
49 }
50
51 app := NewApp()
52 t.Cleanup(app.closeSessionServices)
53 migrate(app)
54 appendLine("first-change")
55 app = restart(app)
56 migrate(app)
57 entries := pending(app)
58 if len(entries) != 1 || entries[0].Reason != "source_changed_after_adoption" {
59 t.Fatalf("changed source was not quarantined: %+v", entries)
60 }
61 quarantined := entries[0].ID
62
63 appendLine("second-change")
64 app = restart(app)
65 migrate(app)
66 release, err := acquireHistoricalSource(t.Context(), desktopSourceKey(sourceFile, ""), historicalSource{path: sourceFile, format: "legacy"})
67 if err != nil {
68 t.Fatal(err)
69 }
70 if _, err := app.RestoreRecoveryEntry(quarantined, ""); !historicalSourceBusyError(err) {
71 t.Fatalf("restore did not refuse a source another writer holds: %v", err)
72 }
73 release()
74 result, err := app.RestoreRecoveryEntry(quarantined, "")
75 if err != nil {
76 t.Fatalf("restore refused a source that changed again: %v", err)
77 }
78 history, err := app.desktopSessionService("").Query().History(t.Context(), session.SessionRef{HostID: localDesktopHostID, SessionID: result.Session.SessionID})
79 if err != nil || len(history) == 0 || history[len(history)-1].Content != "second-change" {
80 t.Fatalf("restore did not read the version on disk: %+v %v", history, err)
81 }
82 if left := pending(app); len(left) != 0 {
83 t.Fatalf("restored version is still offered for recovery: %+v", left)
84 }
85 app = restart(app)
86 for range 2 {
87 migrate(app)
88 }
89 if left := pending(app); len(left) != 0 {
90 t.Fatalf("restart re-quarantined the restored version: %+v", left)
91 }
92 }
93
93 lines GO