The bus module's have names what its server runs, and a node's have what its agent keeps (ADR 0594 §4, §8)
This commit is contained in:
+23
-1
@@ -360,6 +360,12 @@ type Have struct {
|
|||||||
// slot that holds it, so a provider and a consumer of one value on one node each keep their own. Written in Sealed's
|
// slot that holds it, so a provider and a consumer of one value on one node each keep their own. Written in Sealed's
|
||||||
// place by a node-engine that knows it; Sealed is read only from a have written before.
|
// place by a node-engine that knows it; Sealed is read only from a have written before.
|
||||||
SealedAt Seals `json:"sealed-at,omitempty"`
|
SealedAt Seals `json:"sealed-at,omitempty"`
|
||||||
|
// Server is, in the have of the bus module, what the bus server runs (novox/hq ADR 0594 §4): the fingerprint whose
|
||||||
|
// server the node agent last made, or, from the take-over of a server a node's own composition made, that old-form
|
||||||
|
// build's name (`build-...`). FP is the fingerprint applied: the two differ while a build changed the server and no
|
||||||
|
// warranted want replaced it yet. Empty on every other have, and on a bus module's have from a node agent that does
|
||||||
|
// not keep the server.
|
||||||
|
Server string `json:"server,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserListWritten is the bus's user list as the node-engine of the bus node wrote it to the bus module's file, applied
|
// UserListWritten is the bus's user list as the node-engine of the bus node wrote it to the bus module's file, applied
|
||||||
@@ -421,8 +427,15 @@ type HaveNode struct {
|
|||||||
// controller ended may still say `controller` (composedByTheEndedController), which is read and never written.
|
// controller ended may still say `controller` (composedByTheEndedController), which is read and never written.
|
||||||
Composes string `json:"composes,omitempty"`
|
Composes string `json:"composes,omitempty"`
|
||||||
ComposesWhy string `json:"composes-why,omitempty"`
|
ComposesWhy string `json:"composes-why,omitempty"`
|
||||||
|
// Keeps names what the node agent keeps as it runs on a want without the warrant's mark (novox/hq ADR 0594 §8):
|
||||||
|
// KeepsBusServer for a node agent that leaves the bus server alone. Written at each start; the assigner writes the
|
||||||
|
// bus module's want only to a node whose have names it. Empty from a node agent before it.
|
||||||
|
Keeps []string `json:"keeps,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeepsBusServer is a node agent that keeps the bus server unless a want is warranted (HaveNode.Keeps, ADR 0594 §8).
|
||||||
|
const KeepsBusServer = "bus-server"
|
||||||
|
|
||||||
// ComposesOwn is a node applying its own compositions (HaveNode.Composes).
|
// ComposesOwn is a node applying its own compositions (HaveNode.Composes).
|
||||||
const ComposesOwn = "own"
|
const ComposesOwn = "own"
|
||||||
|
|
||||||
@@ -494,6 +507,10 @@ func (h Have) check() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if h.Server != "" && checkFingerprint(h.Server, "the bus server's fingerprint") != nil &&
|
||||||
|
(!strings.HasPrefix(h.Server, "build-") || checkName("bus server's build", h.Server) != nil) {
|
||||||
|
return fmt.Errorf("delivery: the bus server runs %q, neither a fingerprint nor a build's name", h.Server)
|
||||||
|
}
|
||||||
switch h.Health {
|
switch h.Health {
|
||||||
case HealthOK, HealthFailed, HealthWaits, HealthUnknown:
|
case HealthOK, HealthFailed, HealthWaits, HealthUnknown:
|
||||||
default:
|
default:
|
||||||
@@ -529,6 +546,11 @@ func (n HaveNode) check() error {
|
|||||||
default:
|
default:
|
||||||
return fmt.Errorf("delivery: a node composes %q, not %s", n.Composes, ComposesOwn)
|
return fmt.Errorf("delivery: a node composes %q, not %s", n.Composes, ComposesOwn)
|
||||||
}
|
}
|
||||||
|
for _, k := range n.Keeps {
|
||||||
|
if k == "" {
|
||||||
|
return fmt.Errorf("delivery: a node keeps an empty name")
|
||||||
|
}
|
||||||
|
}
|
||||||
for group, a := range n.Candidates {
|
for group, a := range n.Candidates {
|
||||||
if group == "" {
|
if group == "" {
|
||||||
return fmt.Errorf("delivery: a node's candidate answer names no group")
|
return fmt.Errorf("delivery: a node's candidate answer names no group")
|
||||||
@@ -615,7 +637,7 @@ func SameHaveNode(a, b HaveNode) bool {
|
|||||||
sameJSON(a.Strays, b.Strays) && sameJSON(a.Filters, b.Filters) && sameJSON(a.Profile, b.Profile) &&
|
sameJSON(a.Strays, b.Strays) && sameJSON(a.Filters, b.Filters) && sameJSON(a.Profile, b.Profile) &&
|
||||||
(a.Record == nil) == (b.Record == nil) && (a.Record == nil || SameNodeRecord(*a.Record, *b.Record)) &&
|
(a.Record == nil) == (b.Record == nil) && (a.Record == nil || SameNodeRecord(*a.Record, *b.Record)) &&
|
||||||
jsonEqual(a.Sealed, b.Sealed) && maps.Equal(a.SealedAt, b.SealedAt) && jsonEqual(a.Candidates, b.Candidates) && a.Composes == b.Composes &&
|
jsonEqual(a.Sealed, b.Sealed) && maps.Equal(a.SealedAt, b.SealedAt) && jsonEqual(a.Candidates, b.Candidates) && a.Composes == b.Composes &&
|
||||||
a.ComposesWhy == b.ComposesWhy
|
a.ComposesWhy == b.ComposesWhy && slices.Equal(a.Keeps, b.Keeps)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SamePresence says whether two presences are the same value.
|
// SamePresence says whether two presences are the same value.
|
||||||
|
|||||||
@@ -282,6 +282,51 @@ func TestRoundTrip(t *testing.T) {
|
|||||||
t.Error("a list was sealed to no key")
|
t.Error("a list was sealed to no key")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
// 774/S2: the bus module's have names the fingerprint applied and what the server runs, a fingerprint or, at the
|
||||||
|
// take-over, an old-form build's name (ADR 0594 §4); a have written before decodes as it was.
|
||||||
|
t.Run("have of the bus with its server", func(t *testing.T) {
|
||||||
|
fpA, fpB := fp2of('a'), fp2of('b')
|
||||||
|
for _, server := range []string{fpA, "build-1792674595610176744"} {
|
||||||
|
in := Have{FP: fpB, Server: server, Phase: PhaseRunning, Health: HealthOK}
|
||||||
|
b, err := EncodeHave(in)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(b), `"server":"`+server+`"`) {
|
||||||
|
t.Errorf("the have says %s", b)
|
||||||
|
}
|
||||||
|
out, err := DecodeHave(b)
|
||||||
|
in.V = Version
|
||||||
|
if err != nil || !SameHave(out, in) || SameHave(out, Have{V: Version, FP: fpB, Phase: PhaseRunning, Health: HealthOK}) {
|
||||||
|
t.Errorf("got %+v, %v", out, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, server := range []string{"nats", "build-a.b", "src2:abc"} {
|
||||||
|
if _, err := EncodeHave(Have{FP: fpB, Server: server, Phase: PhaseRunning, Health: HealthOK}); err == nil {
|
||||||
|
t.Errorf("a server running %q was encoded", server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old, err := DecodeHave([]byte(`{"v":1,"build":"build-17","phase":"running","health":"ok"}`))
|
||||||
|
if err != nil || old.Server != "" || !SameHave(old, Have{V: Version, Build: "build-17", Phase: PhaseRunning, Health: HealthOK}) {
|
||||||
|
t.Errorf("an old have read %+v, %v", old, err)
|
||||||
|
}
|
||||||
|
keeper := HaveNode{Composes: ComposesOwn, Keeps: []string{KeepsBusServer}}
|
||||||
|
b, err := EncodeHaveNode(keeper)
|
||||||
|
if err != nil || !strings.Contains(string(b), `"keeps":["bus-server"]`) {
|
||||||
|
t.Fatalf("the keeper's have is %s, %v", b, err)
|
||||||
|
}
|
||||||
|
back, err := DecodeHaveNode(b)
|
||||||
|
keeper.V = Version
|
||||||
|
if err != nil || !SameHaveNode(back, keeper) || SameHaveNode(back, HaveNode{V: Version, Composes: ComposesOwn}) {
|
||||||
|
t.Errorf("the keeper came back %+v, %v", back, err)
|
||||||
|
}
|
||||||
|
if older, err := DecodeHaveNode([]byte(`{"v":1,"composes":"own"}`)); err != nil || older.Keeps != nil {
|
||||||
|
t.Errorf("an older node's have read %+v, %v", older, err)
|
||||||
|
}
|
||||||
|
if _, err := EncodeHaveNode(HaveNode{Keeps: []string{""}}); err == nil {
|
||||||
|
t.Error("a node keeping an empty name was encoded")
|
||||||
|
}
|
||||||
|
})
|
||||||
t.Run("have node", func(t *testing.T) {
|
t.Run("have node", func(t *testing.T) {
|
||||||
in := HaveNode{Windows: json.RawMessage(`{"a":1}`), Busy: json.RawMessage(`true`)}
|
in := HaveNode{Windows: json.RawMessage(`{"a":1}`), Busy: json.RawMessage(`true`)}
|
||||||
b, err := EncodeHaveNode(in)
|
b, err := EncodeHaveNode(in)
|
||||||
|
|||||||
Reference in New Issue
Block a user