Files
mesh-catalog/modules/mesh-knowledge/cmd/mesh-knowledge/sent_test.go
T
jschoubben 7bf0e991d8 CAT-K7: every operation's event is sent once, after a restart too
An event of a change carries the record, the version it follows and the event as its message id; the last version sent per
record is a key of the state sent; at start the events of the operations after it are sent again under the same ids, so a
stop between an operation and its event loses none and a second start sends none.

Issue 1966.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 12:09:26 +01:00

58 lines
2.0 KiB
Go

package main
import (
"errors"
"strings"
"testing"
)
// Every operation's event is sent once, after a restart too (to-be 55 §1, AC51): the message id is the record, the version
// and the event; the last version sent is kept; a module stopped between an operation and its event sends it at start,
// under the same id, and sends it once.
func TestEveryOperationsEventIsSentOnceAfterARestartToo(t *testing.T) {
w, f := ledgerWorld(t)
type send struct{ event, id string }
var sends []send
down := false
w.k.EmitID = func(event string, body any, id string) error {
if down {
return errors.New("the bus is down")
}
sends = append(sends, send{event, id})
return nil
}
r, err := w.k.ReserveNumber("author@g14", KindDecision, "a test record")
if err != nil {
t.Fatal(err)
}
key := Key{KindDecision, r.Number}
if len(sends) != 1 || sends[0].event != EventReserved || sends[0].id != key.Kind+"."+strings.Repeat("0", 4-len(itoa(key.Number)))+itoa(key.Number)+".v1.reserved" {
t.Fatalf("%+v", sends)
}
if k := w.k.sentUpTo(key); k != 1 {
t.Fatalf("sent up to %d", k)
}
// Stopped between the operation and its event: the proposal is in the history, its event was not sent.
down = true
if _, err := w.k.Propose("author@g14", valid(r.Number)); err != nil {
t.Fatal(err)
}
if w.k.sentUpTo(key) != 1 {
t.Fatal("an event never sent was marked sent")
}
// A restart: a new knowledge base over the same ledger and states sends what the stop lost, once.
down = false
sends = nil
again := &KB{Store: w.k.Store, States: w.k.States, EmitID: w.k.EmitID, Now: w.k.Now, Logf: w.k.Logf}
n, err := again.ResendEvents(t.Context())
if err != nil || n != 1 || len(sends) != 1 || sends[0].event != EventProposed || !strings.HasSuffix(sends[0].id, ".v2.proposed") {
t.Fatalf("%v: %d, %+v", err, n, sends)
}
if n, _ := again.ResendEvents(t.Context()); n != 0 || len(sends) != 1 {
t.Fatalf("a second start sent %d again", n)
}
_ = f
}
func itoa(n int) string { return Key{KindDecision, n}.String()[4:] }