136 lines
5.9 KiB
Go
136 lines
5.9 KiB
Go
package main
|
|
|
|
import (
|
|
"time"
|
|
|
|
"errors"
|
|
"github.com/novox/mesh-controller/internal/inventory"
|
|
"strings"
|
|
"testing"
|
|
|
|
sdkdelivery "git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// **A machine is current when it has what is wanted of it** (novox/hq ADR 0539 §1, §9, issue 1945): every module wanted on it is
|
|
// had at the wanted fingerprint and composition, running, and every module wanted removed is gone. Read from the wants and the
|
|
// haves; there is no send to compare a report with.
|
|
func TestAMachineIsCurrentWhenItHasWhatIsWantedOfIt(t *testing.T) {
|
|
fp := func(c string) string { return sdkdelivery.SourcePrefix2 + strings.Repeat(c, 64) }
|
|
want := func(f, composed string) sdkdelivery.Want { return sdkdelivery.Want{V: 1, FP: f, Composed: composed} }
|
|
have := func(f, composed string, phase sdkdelivery.Phase) sdkdelivery.Have {
|
|
return sdkdelivery.Have{V: 1, FP: f, Composed: composed, Phase: phase, Health: sdkdelivery.HealthOK}
|
|
}
|
|
key := func(node, module string) string {
|
|
k, err := sdkdelivery.WantKey(node, module)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return k
|
|
}
|
|
for _, c := range []struct {
|
|
what string
|
|
wants map[string]sdkdelivery.Want
|
|
haves map[string]sdkdelivery.Have
|
|
current map[string]bool
|
|
}{
|
|
{"everything had as wanted",
|
|
map[string]sdkdelivery.Want{key("anchor", "web"): want(fp("a"), "d1")},
|
|
map[string]sdkdelivery.Have{key("anchor", "web"): have(fp("a"), "d1", sdkdelivery.PhaseRunning)},
|
|
map[string]bool{"anchor": true}},
|
|
{"a module not had yet",
|
|
map[string]sdkdelivery.Want{key("anchor", "web"): want(fp("a"), "d1")},
|
|
nil, map[string]bool{"anchor": false}},
|
|
{"an older fingerprint",
|
|
map[string]sdkdelivery.Want{key("anchor", "web"): want(fp("b"), "d1")},
|
|
map[string]sdkdelivery.Have{key("anchor", "web"): have(fp("a"), "d1", sdkdelivery.PhaseRunning)},
|
|
map[string]bool{"anchor": false}},
|
|
{"the same fingerprint, an older composition",
|
|
map[string]sdkdelivery.Want{key("anchor", "web"): want(fp("a"), "d2")},
|
|
map[string]sdkdelivery.Have{key("anchor", "web"): have(fp("a"), "d1", sdkdelivery.PhaseRunning)},
|
|
map[string]bool{"anchor": false}},
|
|
{"still applying",
|
|
map[string]sdkdelivery.Want{key("anchor", "web"): want(fp("a"), "d1")},
|
|
map[string]sdkdelivery.Have{key("anchor", "web"): have(fp("a"), "d1", sdkdelivery.PhaseApplying)},
|
|
map[string]bool{"anchor": false}},
|
|
{"held for a backup that failed",
|
|
map[string]sdkdelivery.Want{key("anchor", "web"): want(fp("a"), "d1")},
|
|
map[string]sdkdelivery.Have{key("anchor", "web"): have(fp("a"), "d1", sdkdelivery.PhaseHeld)},
|
|
map[string]bool{"anchor": false}},
|
|
{"a module wanted removed that is gone",
|
|
map[string]sdkdelivery.Want{key("anchor", "web"): {V: 1, Removed: true}},
|
|
map[string]sdkdelivery.Have{key("anchor", "web"): have("", "", sdkdelivery.PhaseRemoved)},
|
|
map[string]bool{"anchor": true}},
|
|
{"a module wanted removed that still runs",
|
|
map[string]sdkdelivery.Want{key("anchor", "web"): {V: 1, Removed: true}},
|
|
map[string]sdkdelivery.Have{key("anchor", "web"): have(fp("a"), "d1", sdkdelivery.PhaseRunning)},
|
|
map[string]bool{"anchor": false}},
|
|
{"one machine behind does not hold another back",
|
|
map[string]sdkdelivery.Want{key("anchor", "web"): want(fp("a"), "d1"), key("laptop", "web"): want(fp("a"), "d1")},
|
|
map[string]sdkdelivery.Have{key("anchor", "web"): have(fp("a"), "d1", sdkdelivery.PhaseRunning)},
|
|
map[string]bool{"anchor": true, "laptop": false}},
|
|
} {
|
|
got := currentNodes(c.wants, c.haves)
|
|
for node, want := range c.current {
|
|
if got[node] != want {
|
|
t.Errorf("%s: %s is current %v, want %v", c.what, node, got[node], want)
|
|
}
|
|
}
|
|
}
|
|
if got := currentNodes(nil, nil); len(got) != 0 {
|
|
t.Errorf("no want names a node, yet %v", got)
|
|
}
|
|
}
|
|
|
|
// **The bus's machine is behind while its have does not name the composition carrying the user list** (ADR 0539 §15): the
|
|
// digest of the bus module's composition written now against the one its have names.
|
|
func TestTheBusMachineIsBehindUntilItsHaveNamesTheCompositionCarryingTheUserList(t *testing.T) {
|
|
have := sdkdelivery.Have{Composed: "d2", Phase: sdkdelivery.PhaseRunning, Health: sdkdelivery.HealthOK}
|
|
for _, c := range []struct {
|
|
what string
|
|
digest string
|
|
err error
|
|
have sdkdelivery.Have
|
|
had bool
|
|
behind bool
|
|
}{
|
|
{"its have names the composition written now", "d2", nil, have, true, false},
|
|
{"its have names an older composition (a new user list)", "d3", nil, have, true, true},
|
|
{"it has no have of the module yet", "d2", nil, sdkdelivery.Have{}, false, true},
|
|
{"the composition cannot be read: not known is behind", "", errors.New("no composition"), have, true, true},
|
|
} {
|
|
if got := listBehind(c.digest, c.err, c.have, c.had); got != c.behind {
|
|
t.Errorf("%s: behind %v, want %v", c.what, got, c.behind)
|
|
}
|
|
}
|
|
}
|
|
|
|
// **A node nothing is wanted on that has reported is current; one that has not is not** (issue 1945): it has nothing to apply.
|
|
func TestANodeWithNoWantThatHasReportedIsCurrent(t *testing.T) {
|
|
at := time.Now()
|
|
reports := []inventory.Reported{{Node: "anchor", At: &at}, {Node: "laptop"}, {Node: "ace", At: &at}}
|
|
applyCurrent(reports, map[string]bool{"ace": false})
|
|
got := map[string]bool{}
|
|
for _, r := range reports {
|
|
got[r.Node] = r.Current
|
|
if r.CurrentUnknown {
|
|
t.Errorf("%s: current is unknown with the haves read", r.Node)
|
|
}
|
|
}
|
|
if !got["anchor"] || got["laptop"] || got["ace"] {
|
|
t.Errorf("current by node: %v; want anchor (reported, nothing wanted) true, laptop (never reported) false, ace (behind) false", got)
|
|
}
|
|
}
|
|
|
|
// **With the bus out of reach, whether a node is current is not known** (issue 1945): every report says so, and none says "not
|
|
// current".
|
|
func TestWithTheBusOutOfReachNoNodeIsSaidCurrentOrNot(t *testing.T) {
|
|
at := time.Now()
|
|
reports := []inventory.Reported{{Node: "anchor", At: &at, Current: true}, {Node: "laptop"}}
|
|
currentUnknown(reports)
|
|
for _, r := range reports {
|
|
if r.Current || !r.CurrentUnknown {
|
|
t.Errorf("%s: current %v, unknown %v; want not known", r.Node, r.Current, r.CurrentUnknown)
|
|
}
|
|
}
|
|
}
|