返回 DeepSeek-Reasonix
reconcile_queue_test.go
根目录 / internal / sessioncatalog / reconcile_queue_test.go
1 package sessioncatalog
2
3 import "testing"
4
5 func TestReconcileTokenUsesLatestPreDispatchTargetOnce(t *testing.T) {
6 catalog := &Catalog{
7 reconcileCh: make(chan DirectoryTarget, 2), reconcileDirty: map[string]DirectoryTarget{}, stop: make(chan struct{}),
8 }
9 a := DirectoryTarget{Path: "/sessions", Scope: "global", mutationSeq: 1}
10 b := DirectoryTarget{Path: "/sessions", Scope: "workspace", WorkspaceRoot: "/work", mutationSeq: 2}
11 if !catalog.RequestReconcile(a) || !catalog.RequestReconcile(b) {
12 t.Fatal("failed to queue targets")
13 }
14 token := <-catalog.reconcileCh
15 got, ok := catalog.resolveReconcileToken(token)
16 if !ok || got.Scope != b.Scope || got.WorkspaceRoot != b.WorkspaceRoot || got.mutationSeq <= a.mutationSeq {
17 t.Fatalf("resolved target = %+v ok=%v, want latest B", got, ok)
18 }
19 if _, dirty := catalog.takeReconcileDirty(); dirty {
20 t.Fatal("pre-dispatch dirty target remained queued")
21 }
22 select {
23 case extra := <-catalog.reconcileCh:
24 t.Fatalf("unexpected second channel token: %+v", extra)
25 default:
26 }
27 }
28
29 func TestReconcileRunningUpdatesKeepOnlyLatestFollowUp(t *testing.T) {
30 catalog := &Catalog{reconcileDirty: map[string]DirectoryTarget{}}
31 key := queuePathKey("/sessions")
32 catalog.reconcileQueued.Store(key, DirectoryTarget{Path: "/sessions", mutationSeq: 1})
33 catalog.markReconcileDirty(DirectoryTarget{Path: "/sessions", Scope: "global", mutationSeq: 2})
34 catalog.markReconcileDirty(DirectoryTarget{Path: "/sessions", Scope: "workspace", WorkspaceRoot: "/latest", mutationSeq: 3})
35 got, ok := catalog.takeReconcileDirty()
36 if !ok || got.mutationSeq != 3 || got.WorkspaceRoot != "/latest" {
37 t.Fatalf("follow-up = %+v ok=%v, want latest only", got, ok)
38 }
39 if _, ok := catalog.takeReconcileDirty(); ok {
40 t.Fatal("more than one follow-up remained")
41 }
42 }
43
44 func TestReconcileDirtyNeverDowngradesToLateOlderTarget(t *testing.T) {
45 newer := DirectoryTarget{Path: "/sessions", Scope: "workspace", WorkspaceRoot: "/new", mutationSeq: 3}
46 older := DirectoryTarget{Path: "/sessions", Scope: "global", mutationSeq: 2}
47 for _, tc := range []struct {
48 name string
49 seedDirty bool
50 }{
51 {name: "queued target"},
52 {name: "dirty target", seedDirty: true},
53 } {
54 t.Run(tc.name, func(t *testing.T) {
55 catalog := &Catalog{reconcileDirty: map[string]DirectoryTarget{}}
56 key := queuePathKey(newer.Path)
57 catalog.reconcileQueued.Store(key, newer)
58 if tc.seedDirty {
59 catalog.reconcileDirty[key] = newer
60 }
61 catalog.markReconcileDirty(older)
62 got, ok := catalog.takeReconcileDirty()
63 if !ok || got.mutationSeq != newer.mutationSeq || got.WorkspaceRoot != newer.WorkspaceRoot {
64 t.Fatalf("dirty target = %+v ok=%v, want newer target", got, ok)
65 }
66 })
67 }
68 }
69
69 lines GO