package main import ( "encoding/json" "testing" ) // A declaration's only identity was the digest of its bytes; the controller already held a per-node // lock and recorded each send, so the order existed and was thrown away at the wire (novox/hq // 04-ISSUES/107). func TestASendCarriesItsNumberInsideTheSignedBytes(t *testing.T) { body, err := sendable{Resources: []map[string]any{{"id": "x", "type": "file"}}, Sequence: 7}.Body() if err != nil { t.Fatal(err) } var env map[string]any if err := json.Unmarshal(body, &env); err != nil { t.Fatal(err) } if got, _ := env["sequence"].(float64); got != 7 { t.Fatalf("the body carries sequence %v, wanted 7", env["sequence"]) } } func TestAnUnnumberedSendIsByteForByteWhatItWasBefore(t *testing.T) { // Zero is not sent at all. A host reads absence as "no order claimed" — the shape of every // declaration before this — so an older host, or the read-only comparison against a machine // sent nothing since sends were numbered, sees exactly the bytes it always saw. body, err := sendable{Resources: []map[string]any{{"id": "x", "type": "file"}}}.Body() if err != nil { t.Fatal(err) } var env map[string]any if err := json.Unmarshal(body, &env); err != nil { t.Fatal(err) } if _, present := env["sequence"]; present { t.Fatalf("a send numbered zero put a sequence on the wire: %s", body) } } func TestEachSendToANodeIsOneHigherAndReadable(t *testing.T) { open := aMesh(t) record, err := open.inventory.NodeByName(t.Context(), "anchor") if err != nil { t.Fatal(err) } // Sent nothing since numbering existed: what it would be sent is composed with zero, which is // not on the wire, which is what it was actually sent. if n, err := open.inventory.Sequence(t.Context(), record.ID); err != nil || n != 0 { t.Fatalf("a fresh node reads sequence %d, %v", n, err) } first, err := open.inventory.NextSequence(t.Context(), record.ID) if err != nil { t.Fatal(err) } second, err := open.inventory.NextSequence(t.Context(), record.ID) if err != nil { t.Fatal(err) } if first != 1 || second != 2 { t.Fatalf("two sends were numbered %d and %d", first, second) } // And the read path sees the last one taken, so the comparison composes what was sent. if n, err := open.inventory.Sequence(t.Context(), record.ID); err != nil || n != 2 { t.Fatalf("after two sends the node reads sequence %d, %v", n, err) } // Another node counts on its own. other, err := open.inventory.NodeByName(t.Context(), "laptop") if err != nil { t.Fatal(err) } if n, err := open.inventory.NextSequence(t.Context(), other.ID); err != nil || n != 1 { t.Fatalf("a second node's first send was numbered %d, %v", n, err) } }