The CONTROL stream the facts, the enrolment and the overlay rekey were published into was the controller's, which ended by its unassignment (issue 1126) and whose stream is removed after group B's delivery: a publish there would fail every facts event before its haves are written. The facts go into the haves as they did after the report, the enrolment goes through mesh-enrolment alone, and overlay take is refused because no seat takes a rekey now. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
68 lines
3.6 KiB
Go
68 lines
3.6 KiB
Go
package link
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestTheWireFormatIsExactlyTheseFieldNames(t *testing.T) {
|
|
// The contract with the control plane, which defines these separately. A matching test lives
|
|
// there; rename a field on either side and both fail.
|
|
for _, c := range []struct {
|
|
value any
|
|
expect []string
|
|
}{
|
|
{Report{Node: "n", Applied: []string{"a"}, Failed: map[string]string{"k": "v"}, Refused: "r"},
|
|
[]string{"node", "applied", "failed", "refused"}},
|
|
// novox/hq ADR 0100: what an adopted node holds, the firewall it was found with, and what
|
|
// is reachable on it.
|
|
{Report{Node: "n", Held: []Held{{ID: "i"}}, Firewall: "ufw", Reachable: []Reach{{Port: 1}}},
|
|
[]string{"node", "held", "firewall", "reachable"}},
|
|
{Held{ID: "i", Module: "m", Kind: "file", Target: "/t", Changed: "rewritten", Kept: "/k"},
|
|
[]string{"id", "module", "kind", "target", "since", "changed", "kept"}},
|
|
{Reach{Protocol: "tcp", Address: "0.0.0.0", Port: 8080, By: "c", Published: true, ContainerPort: 80},
|
|
[]string{"protocol", "address", "port", "by", "published", "container-port"}},
|
|
// novox/hq to-be 45 §8: a witness's verdicts, said on every report while they stand, and the
|
|
// witness contract this host keeps.
|
|
{Report{Node: "n", Rollbacks: []Rollback{{Component: ComponentNodeTools}}, Witness: WitnessContract},
|
|
[]string{"node", "rollbacks", "witness"}},
|
|
{Rollback{Component: ComponentNodeTools, From: "sha256:b", To: "sha256:a", Outcome: RolledBack, Why: "w"},
|
|
[]string{"component", "from", "to", "outcome", "why", "at"}},
|
|
// novox/hq ADR 0240: every long-running resource's health, in every report and in its own event.
|
|
{Report{Node: "n", Health: &Health{Contract: LivenessContract}}, []string{"node", "health"}},
|
|
{Health{Contract: LivenessContract, Resources: []ResourceHealth{}}, []string{"contract", "at", "resources"}},
|
|
{ResourceHealth{Module: "m", Resource: "m.r", Kind: "container", Target: "t", State: StateUnhealthy,
|
|
Reason: ReasonRestarting, Streak: 2, Restarts: 3, Check: "http", Needs: "postgres-database"},
|
|
[]string{"module", "resource", "kind", "target", "state", "reason", "since", "streak", "restarts",
|
|
"check", "needs"}},
|
|
{HealthSaid{Node: "n"}, []string{"node", "health"}},
|
|
// novox/hq ADR 0266: an account judged for whether it can become root without a person.
|
|
{ResourceHealth{Module: "m", Resource: "m.agent", Kind: KindAccount, Account: "agent", Root: "never"},
|
|
[]string{"module", "resource", "kind", "target", "state", "since", "account", "root"}},
|
|
// novox/hq ADR 0241: the machine's own networking, beside its resources.
|
|
{Health{Contract: ReadinessContract, Resources: []ResourceHealth{}, Network: &NetworkHealth{State: "unhealthy",
|
|
Parts: []NetworkPart{}}}, []string{"contract", "at", "resources", "network"}},
|
|
{NetworkHealth{State: "unhealthy", Parts: []NetworkPart{}}, []string{"state", "since", "parts"}},
|
|
{NetworkPart{Part: "resolv-conf", State: "unhealthy", Reason: "r", Said: "s", Writer: "w", Owner: "o",
|
|
Toward: []string{"hub"}, Streak: 2}, []string{"part", "state", "reason", "said", "writer", "owner", "toward",
|
|
"since", "streak"}},
|
|
} {
|
|
raw, err := json.Marshal(c.value)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var fields map[string]any
|
|
if err := json.Unmarshal(raw, &fields); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, want := range c.expect {
|
|
if _, ok := fields[want]; !ok {
|
|
t.Errorf("%T has no %q field; the control plane uses that name", c.value, want)
|
|
}
|
|
}
|
|
if len(fields) != len(c.expect) {
|
|
t.Errorf("%T has %d fields, expected %d: %v", c.value, len(fields), len(c.expect), fields)
|
|
}
|
|
}
|
|
}
|