返回 DeepSeek-Reasonix
historical_sidecar_test.go
根目录 / desktop / historical_sidecar_test.go
1 package main
2
3 import (
4 "encoding/json"
5 "os"
6 "path/filepath"
7 "testing"
8 )
9
10 func TestHistoricalSidecarPreservesUnknownFieldsAndIndependentWriters(t *testing.T) {
11 isolateDesktopUserDirs(t)
12 path := historicalImportQueuePath()
13 if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
14 t.Fatal(err)
15 }
16 old := []byte(`{"version":1,"current":"active","queue":["next"],"future":{"keep":true},"presentations":{"a":{"title":"old","futureBadge":"keep"}}}`)
17 if err := os.WriteFile(path, old, 0o600); err != nil {
18 t.Fatal(err)
19 }
20 a, b := newHistoricalLifecycleApp(t), newHistoricalLifecycleApp(t)
21 for _, app := range []*App{a, b} {
22 if _, err := app.ListHistoricalSessions(); err != nil {
23 t.Fatal(err)
24 }
25 }
26 if err := a.saveHistoricalSourcePresentation("a", func(p *historicalSourcePresentation) { p.Title = "new" }); err != nil {
27 t.Fatal(err)
28 }
29 if err := b.saveHistoricalSourcePresentation("a", func(p *historicalSourcePresentation) { pin := true; p.Pinned = &pin }); err != nil {
30 t.Fatal(err)
31 }
32 saved, err := readHistoricalSidecar()
33 if err != nil {
34 t.Fatal(err)
35 }
36 if saved.Current != "active" || len(saved.Queue) != 1 || saved.Queue[0] != "next" || saved.Presentations["a"].Title != "new" || saved.Presentations["a"].Pinned == nil || !*saved.Presentations["a"].Pinned {
37 t.Fatalf("independent fields lost: %+v", saved)
38 }
39 a.historicalImports.mu.Lock()
40 err = a.historicalImports.saveQueueLocked()
41 a.historicalImports.mu.Unlock()
42 if err != nil {
43 t.Fatal(err)
44 }
45 saved, err = readHistoricalSidecar()
46 if err != nil {
47 t.Fatal(err)
48 }
49 if saved.Presentations["a"].Title != "new" || saved.Presentations["a"].Pinned == nil {
50 t.Fatalf("queue overwrote current presentations: %+v", saved)
51 }
52 data, err := json.Marshal(saved)
53 if err != nil {
54 t.Fatal(err)
55 }
56 var fields map[string]json.RawMessage
57 if err := json.Unmarshal(data, &fields); err != nil {
58 t.Fatal(err)
59 }
60 if string(fields["future"]) != `{"keep":true}` || string(saved.Presentations["a"].extra["futureBadge"]) != `"keep"` {
61 t.Fatalf("unknown fields lost: %s", data)
62 }
63 b.historicalImports.mu.Lock()
64 err = b.historicalImports.saveQueueLocked()
65 b.historicalImports.mu.Unlock()
66 if err == nil {
67 t.Fatal("stale batch revision overwrote a newer selection")
68 }
69 }
70
71 func TestHistoricalQueueRejectsSecondProcessOwner(t *testing.T) {
72 isolateDesktopUserDirs(t)
73 a, b := newHistoricalLifecycleApp(t), newHistoricalLifecycleApp(t)
74 a.historicalImports.mu.Lock()
75 err := a.historicalImports.claimQueueLocked()
76 a.historicalImports.mu.Unlock()
77 if err != nil {
78 t.Fatal(err)
79 }
80 t.Cleanup(func() {
81 a.historicalImports.mu.Lock()
82 a.historicalImports.releaseQueueLocked()
83 a.historicalImports.mu.Unlock()
84 })
85 if _, err := b.StartHistoricalImport(nil); err == nil {
86 t.Fatal("second owner started a competing batch")
87 }
88 if _, err := b.ControlHistoricalImport("cancel"); err == nil {
89 t.Fatal("second owner cancelled another process batch")
90 }
91 if err := b.saveHistoricalSourcePresentation("a", func(p *historicalSourcePresentation) { p.Title = "still writable" }); err != nil {
92 t.Fatal(err)
93 }
94 }
95
95 lines GO