返回 DeepSeek-Reasonix
retired_source_test.go
根目录 / desktop / internal / workspacestate / retired_source_test.go
1 package workspacestate
2
3 import (
4 "errors"
5 "path/filepath"
6 "reflect"
7 "testing"
8 )
9
10 func TestRetiredSourceReceiptPreservesLifecycleAndPresentation(t *testing.T) {
11 for _, lifecycle := range []string{Archived, Deleted} {
12 t.Run(lifecycle, func(t *testing.T) {
13 store := NewStore(filepath.Join(t.TempDir(), "state.json"))
14 ctx := t.Context()
15 if err := store.EnsureWorkspace(ctx, Workspace{ID: GlobalWorkspaceID, Visible: true}); err != nil {
16 t.Fatal(err)
17 }
18 if err := store.AttachSession(ctx, "", GlobalWorkspaceID, "original", ""); err != nil {
19 t.Fatal(err)
20 }
21 if err := store.ArchiveSession(ctx, "original"); err != nil {
22 t.Fatal(err)
23 }
24 before, err := store.Load(ctx)
25 if err != nil {
26 t.Fatal(err)
27 }
28 if lifecycle == Deleted {
29 if err := store.BeginPurge(ctx, "original", before.Generation); err != nil {
30 t.Fatal(err)
31 }
32 before, err = store.Load(ctx)
33 if err != nil {
34 t.Fatal(err)
35 }
36 }
37 mapping := SourceMapping{SourceKey: "canonical-copy", Path: "/source", Format: "canonical", Fingerprint: "actual-file-fingerprint", SessionID: "original", WorkspaceID: GlobalWorkspaceID}
38 if err := store.RecordRetiredSource(ctx, mapping, before.Generation); err != nil {
39 t.Fatal(err)
40 }
41 after, err := NewStore(store.Path()).Load(ctx)
42 if err != nil {
43 t.Fatal(err)
44 }
45 if !reflect.DeepEqual(before.SessionStates, after.SessionStates) || !reflect.DeepEqual(before.Workspaces, after.Workspaces) ||
46 !reflect.DeepEqual(before.Presentation, after.Presentation) || !reflect.DeepEqual(before.PendingOperations, after.PendingOperations) {
47 t.Fatal("receipt repair mutated lifecycle, membership, presentation or journal")
48 }
49 if err := store.RecordRetiredSource(ctx, mapping, before.Generation); !errors.Is(err, ErrMutationConflict) {
50 t.Fatalf("stale proof accepted: %v", err)
51 }
52 if err := store.RecordRetiredSource(ctx, mapping, after.Generation); err != nil {
53 t.Fatal(err)
54 }
55 })
56 }
57 }
58
59 func TestArchiveTransferRejectsChangedReservation(t *testing.T) {
60 store := NewStore(filepath.Join(t.TempDir(), "state.json"))
61 ctx := t.Context()
62 if err := store.EnsureWorkspace(ctx, Workspace{ID: GlobalWorkspaceID}); err != nil {
63 t.Fatal(err)
64 }
65 op := Operation{ID: "import-source", Kind: "import", Lifecycle: Active, WorkspaceID: GlobalWorkspaceID, SessionIDs: []string{"copy"},
66 Mapping: &SourceMapping{SourceKey: "source", Fingerprint: "fingerprint", SessionID: "copy", WorkspaceID: GlobalWorkspaceID}}
67 if err := store.BeginOperation(ctx, op); err != nil {
68 t.Fatal(err)
69 }
70 state, err := store.Load(ctx)
71 if err != nil {
72 t.Fatal(err)
73 }
74 observed := state.PendingOperations[op.ID]
75 if err := store.StageHistoricalArchive(ctx, observed, state.Generation); err != nil {
76 t.Fatal(err)
77 }
78 if err := store.StageHistoricalArchive(ctx, observed, state.Generation); !errors.Is(err, ErrMutationConflict) {
79 t.Fatalf("stale transfer: %v", err)
80 }
81 state, err = store.Load(ctx)
82 if err != nil || state.PendingOperations[op.ID].Kind != "archive-import" || len(state.SessionStates) != 0 {
83 t.Fatalf("transfer published membership: %v", err)
84 }
85 if err := store.CommitOperation(ctx, op.ID); !errors.Is(err, ErrMutationConflict) {
86 t.Fatalf("orphan child committed: %v", err)
87 }
88 }
89
90 func TestArchiveReservationFencesOtherImportKinds(t *testing.T) {
91 for _, kind := range []string{"import", "archive-import", "restore"} {
92 t.Run(kind, func(t *testing.T) {
93 store := NewStore(filepath.Join(t.TempDir(), "state.json"))
94 ctx := t.Context()
95 if err := store.EnsureWorkspace(ctx, Workspace{ID: GlobalWorkspaceID}); err != nil {
96 t.Fatal(err)
97 }
98 reserved := Operation{ID: "archive-child", Kind: "archive-import", Lifecycle: Archived,
99 WorkspaceID: GlobalWorkspaceID, SessionIDs: []string{"reserved"},
100 Mapping: &SourceMapping{SourceKey: "source", Fingerprint: "fingerprint", SessionID: "reserved", WorkspaceID: GlobalWorkspaceID}}
101 if err := store.BeginOperation(ctx, reserved); err != nil {
102 t.Fatal(err)
103 }
104 other := reserved
105 other.ID, other.Kind = "competing-operation", kind
106 if err := store.BeginOperation(ctx, other); !errors.Is(err, ErrMutationConflict) {
107 t.Fatalf("%s stole archive reservation: %v", kind, err)
108 }
109 })
110 }
111 }
112
112 lines GO