package main import ( "context" "encoding/json" "sync" "testing" "time" "github.com/nats-io/nats.go" "github.com/nats-io/nats.go/jetstream" "git.novox.be/novox/mesh-sdk/go/asks" "github.com/novox/mesh-controller/internal/broker" "github.com/novox/mesh-controller/internal/conditions" "github.com/novox/mesh-controller/internal/link" "github.com/novox/mesh-controller/internal/testbus" ) // busAsker is an asker on a real bus's `asked` bucket, counting what it performs: two of them are two // controllers sharing one record. type busAskerRig struct { mu sync.Mutex called int acts int open []conditions.Condition sent [][]byte } func (rig *busAskerRig) asker(t *testing.T, conn *nats.Conn, now time.Time) *asker { return &asker{ open: func(context.Context) ([]conditions.Condition, error) { rig.mu.Lock() defer rig.mu.Unlock() return rig.open, nil }, silence: func(context.Context, string, time.Duration, string, string) error { return nil }, store: busAsked{conn: conn}, publish: func(_ context.Context, subject string, body []byte, _ string) error { rig.mu.Lock() defer rig.mu.Unlock() if subject == asks.AskSubject(askerName) { rig.sent = append(rig.sent, body) } return nil }, call: func(context.Context, conditions.Action, map[string]string) error { time.Sleep(20 * time.Millisecond) // long enough for the other delivery to arrive meanwhile rig.mu.Lock() defer rig.mu.Unlock() rig.called++ return nil }, record: func(context.Context, link.HandAct) error { rig.mu.Lock() defer rig.mu.Unlock() rig.acts++ return nil }, now: func() time.Time { return now }, logf: t.Logf, } } func askedBus(t *testing.T) *nats.Conn { t.Helper() conn, err := nats.Connect(testbus.URL(t)) if err != nil { t.Fatal(err) } t.Cleanup(conn.Close) js, err := jetstream.New(conn) if err != nil { t.Fatal(err) } if _, err := js.CreateKeyValue(context.Background(), jetstream.KeyValueConfig{Bucket: broker.AskedBucket}); err != nil { t.Fatal(err) } return conn } // The review of 2026-10-09 (L7): two deliveries of one warrant, to two controllers at once, perform its act // exactly once and record it once — the record's compare-and-set decides, never the warrant's message id. func TestTwoAnswersAtOnceActOnce(t *testing.T) { conn := askedBus(t) now := time.Date(2026, 10, 9, 14, 0, 0, 0, time.UTC) rig := &busAskerRig{open: []conditions.Condition{heldCondition()}} first, second := rig.asker(t, conn, now), rig.asker(t, conn, now) if err := first.reconcile(context.Background()); err != nil { t.Fatal(err) } if len(rig.sent) != 1 { t.Fatalf("asked %d times", len(rig.sent)) } var q asks.Ask _ = json.Unmarshal(rig.sent[0], &q) release, _ := q.Option("release") w := asks.Warrant{Ask: q.ID, Asker: askerName, About: q.About, Outcome: asks.OutcomeChosen, Option: release.ID, Label: release.Label, Level: release.Level, Channel: "telegram", Proofs: []string{"P1"}, At: now, AskDigest: q.Digest(), By: &asks.Person{Who: asks.Operator, Kind: "telegram", Identity: "42", Verified: "user id verified"}} body, _ := json.Marshal(w) var wg sync.WaitGroup for _, a := range []*asker{first, second, first, second} { wg.Add(1) go func(a *asker) { defer wg.Done() if err := a.Decided(context.Background(), body); err != nil { t.Error(err) } }(a) } wg.Wait() if rig.called != 1 || rig.acts != 1 { t.Fatalf("performed %d time(s), recorded %d time(s)", rig.called, rig.acts) } got, err := busAsked{conn: conn}.Get(context.Background(), q.ID) if err != nil || got == nil || got.Acted != "done" { t.Fatalf("kept as %+v (%v)", got, err) } } // The review of 2026-10-09 (L2): a write decided on a record read earlier never lands over one made since. A // cancel read before the answer was acted on leaves the act's record as it is. func TestAStaleCancelDoesNotWriteOverAnAct(t *testing.T) { conn := askedBus(t) now := time.Date(2026, 10, 9, 14, 0, 0, 0, time.UTC) rig := &busAskerRig{open: []conditions.Condition{heldCondition()}} a := rig.asker(t, conn, now) if err := a.reconcile(context.Background()); err != nil { t.Fatal(err) } var q asks.Ask _ = json.Unmarshal(rig.sent[0], &q) stale, _ := busAsked{conn: conn}.Get(context.Background(), q.ID) release, _ := q.Option("release") w := asks.Warrant{Ask: q.ID, Asker: askerName, About: q.About, Outcome: asks.OutcomeChosen, Option: release.ID, Label: release.Label, Level: release.Level, Channel: "telegram", At: now, AskDigest: q.Digest(), By: &asks.Person{Who: asks.Operator, Kind: "telegram", Identity: "42", Verified: "user id verified"}} body, _ := json.Marshal(w) if err := a.Decided(context.Background(), body); err != nil { t.Fatal(err) } if err := a.cancel(context.Background(), *stale, "the condition ended"); err != nil { t.Fatal(err) } got, _ := busAsked{conn: conn}.Get(context.Background(), q.ID) if got.State != string(asks.OutcomeChosen) || got.Acted != "done" { t.Errorf("a stale cancel wrote over the act: %+v", got) } }