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.
59 lines
2.0 KiB
Go
59 lines
2.0 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-host/internal/store"
|
|
)
|
|
|
|
// A declaration carries no order, so a host cannot tell an older one from a newer (novox/hq
|
|
// 04-ISSUES/107). Its only identity was the digest of its bytes: "not the last" could be said,
|
|
// "older" could not.
|
|
|
|
func keptWith(t *testing.T, sequence int64) store.Declared {
|
|
t.Helper()
|
|
body, err := json.Marshal(map[string]any{
|
|
"declaration": 1, "resources": []any{}, "owns_nothing": true, "sequence": sequence,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return store.Declared{Declaration: body, Signature: []byte("x")}
|
|
}
|
|
|
|
func TestAnOlderDeclarationFromTheMeshIsRefused(t *testing.T) {
|
|
err := refuseOlder(keptWith(t, 7), nil, 5)
|
|
if err == nil {
|
|
t.Fatal("sequence 5 was accepted over a kept 7")
|
|
}
|
|
if !strings.Contains(err.Error(), "older") || !strings.Contains(err.Error(), "nothing was applied") {
|
|
t.Fatalf("the refusal does not say what it is: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestANewerOrEqualDeclarationIsNot(t *testing.T) {
|
|
if err := refuseOlder(keptWith(t, 7), nil, 8); err != nil {
|
|
t.Fatalf("sequence 8 was refused over a kept 7: %v", err)
|
|
}
|
|
// Equal is the same declaration again, which reconciling is for.
|
|
if err := refuseOlder(keptWith(t, 7), nil, 7); err != nil {
|
|
t.Fatalf("the same sequence was refused: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestNoOrderClaimedMeansNoOrderCompared(t *testing.T) {
|
|
// An older controller sends none; a host that received before it understood them kept none.
|
|
// Refusing on a guess would strand a node the moment the controller is older than the host.
|
|
if err := refuseOlder(keptWith(t, 7), nil, 0); err != nil {
|
|
t.Fatalf("a declaration claiming no order was refused: %v", err)
|
|
}
|
|
if err := refuseOlder(keptWith(t, 0), nil, 3); err != nil {
|
|
t.Fatalf("a declaration was refused against a kept one that claimed no order: %v", err)
|
|
}
|
|
if err := refuseOlder(store.Declared{}, store.ErrNothingDeclared, 3); err != nil {
|
|
t.Fatalf("a first declaration was refused: %v", err)
|
|
}
|
|
}
|