novox/hq 04-ISSUES/107. A declaration's only identity was the digest of its bytes: a host could say "not the last" and could not say "older". On the link, nothing refused an older one at all, and the drain picked the last to arrive — wrong exactly when it mattered, a backlog drained out of order or a broker that split a burst. A declaration may now carry a sequence, one higher per send. A host refuses one lower than what it kept, whole, and says why. The drain keeps the highest sequence in a batch rather than the last to arrive. Only when both sides claim an order. Absent reads as zero — "no ordering claimed", not "first" — so a controller that sends none is still understood and a host that kept one before it understood them compares nothing. That is what lets hosts go first and the controller follow, which is the order 087 says a new field needs.
51 lines
1.6 KiB
Go
51 lines
1.6 KiB
Go
package link
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// The drain picked the last to arrive. A backlog longer than the batch, or a broker that split a
|
|
// burst, delivered a superseded declaration last (novox/hq 04-ISSUES/107).
|
|
|
|
func sequenced(t *testing.T, n int64) *said {
|
|
t.Helper()
|
|
inner, err := json.Marshal(map[string]any{"declaration": 1, "resources": []any{}, "sequence": n})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
body, err := json.Marshal(Signed{Declaration: inner, Signature: []byte("s")})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return &said{body: body}
|
|
}
|
|
|
|
func TestTheDrainKeepsTheHighestSequenceNotTheLastToArrive(t *testing.T) {
|
|
waiting := make(chan Declaration, 8)
|
|
waiting <- sequenced(t, 9)
|
|
waiting <- sequenced(t, 4) // arrived last, composed earlier
|
|
latest, aside := newest(waiting, sequenced(t, 8), 30*time.Millisecond)
|
|
if got := sequenceOf(latest.Body()); got != 9 {
|
|
t.Fatalf("the drain kept sequence %d, and 9 was waiting", got)
|
|
}
|
|
if len(aside) != 2 {
|
|
t.Fatalf("%d set aside, wanted 2 (the 8 and the late 4)", len(aside))
|
|
}
|
|
}
|
|
|
|
func TestWithoutSequencesTheLastToArriveStillWins(t *testing.T) {
|
|
// The behaviour this had before, kept for a controller that sends no order.
|
|
apply, aside := newest(arriving("two", "three"), &said{body: []byte("one")}, 30*time.Millisecond)
|
|
if string(apply.Body()) != "three" || len(aside) != 2 {
|
|
t.Fatalf("applied %q with %d set aside", apply.Body(), len(aside))
|
|
}
|
|
}
|
|
|
|
func TestAnUnreadableBodyClaimsNoOrder(t *testing.T) {
|
|
if got := sequenceOf([]byte("not json")); got != 0 {
|
|
t.Fatalf("garbage claimed sequence %d", got)
|
|
}
|
|
}
|