返回 DeepSeek-Reasonix
topic_removal_test.go
根目录 / desktop / internal / workspacestate / topic_removal_test.go
1 package workspacestate
2
3 import (
4 "encoding/json"
5 "errors"
6 "path/filepath"
7 "testing"
8 )
9
10 func TestTopicRemovalJournalSurvivesFailedEffectAndClonesEvidence(t *testing.T) {
11 s := NewStore(filepath.Join(t.TempDir(), "state.json"))
12 failed := errors.New("external metadata unavailable")
13 err := s.TransitionTopicRemoval(t.Context(), "remove", func(_ State, item *TopicRemoval, checkpoint func() error) error {
14 *item = TopicRemoval{ID: "remove", TopicID: "topic", WorkspaceID: GlobalWorkspaceID, Phase: "prepared", Snapshot: json.RawMessage(`{"title":"keep"}`), Metadata: json.RawMessage(`{"future":[1,2]}`)}
15 if err := checkpoint(); err != nil {
16 return err
17 }
18 item.Phase = "committed"
19 return failed
20 })
21 if !errors.Is(err, failed) {
22 t.Fatal(err)
23 }
24 state, err := s.Load(t.Context())
25 if err != nil {
26 t.Fatal(err)
27 }
28 if state.TopicRemovals["remove"].Phase != "prepared" {
29 t.Fatal("failure reported as durable commit")
30 }
31 state.TopicRemovals["remove"].Snapshot[0] = '!'
32 state.TopicRemovals["remove"].Metadata[0] = '!'
33 again, err := s.Load(t.Context())
34 if err != nil {
35 t.Fatal(err)
36 }
37 if string(again.TopicRemovals["remove"].Snapshot) != `{"title":"keep"}` || string(again.TopicRemovals["remove"].Metadata) != `{"future":[1,2]}` {
38 t.Fatal("snapshot aliases private reader cache")
39 }
40 before := again.Generation
41 if err := s.TransitionTopicRemoval(t.Context(), "remove", func(_ State, item *TopicRemoval, _ func() error) error { item.Phase = "committed"; return nil }); err != nil {
42 t.Fatal(err)
43 }
44 again, _ = s.Load(t.Context())
45 if again.Generation <= before {
46 t.Fatal("completion did not invalidate list cursors")
47 }
48 }
49
50 func TestTopicRemovalUnknownFieldsRoundTrip(t *testing.T) {
51 var item TopicRemoval
52 if err := json.Unmarshal([]byte(`{"id":"remove","phase":"prepared","future":{"keep":[1,2]}}`), &item); err != nil {
53 t.Fatal(err)
54 }
55 item.Phase = "committed"
56 body, err := json.Marshal(item)
57 if err != nil {
58 t.Fatal(err)
59 }
60 var fields map[string]json.RawMessage
61 if err := json.Unmarshal(body, &fields); err != nil {
62 t.Fatal(err)
63 }
64 if string(fields["future"]) != `{"keep":[1,2]}` {
65 t.Fatal("future writer evidence lost")
66 }
67 state := newState()
68 body, _ = json.Marshal(state)
69 if err := json.Unmarshal(body, &fields); err != nil {
70 t.Fatal(err)
71 }
72 if _, exists := fields["topicRemovals"]; exists {
73 t.Fatal("empty collection changed old-data shape")
74 }
75 }
76
76 lines GO