A delivery and the five-minute reconcile were two paths that applied, ordered only by a lock, and each order it allowed was met live (issues 257, 261, 267). Now both only enqueue: one worker takes the newest declaration held when it starts, applies it once and makes one report, and reports leave in the order they are made. A declaration may carry the controller's lease epoch beside its sequence; one older than what this node applied is refused before anything is touched, counted, logged and reported. A report carries the declaration's epoch and sequence and the host's own report sequence, kept on disk so it goes on increasing across restarts and self-updates. Without an epoch, today's behaviour stands.
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 := orderOf(latest.Body()).Sequence; 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 := orderOf([]byte("not json")); got != (Order{}) {
|
|
t.Fatalf("garbage claimed %+v", got)
|
|
}
|
|
}
|