96 lines
4.6 KiB
Go
96 lines
4.6 KiB
Go
package build
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
func tcs(language, version string, nodes ...string) []delivery.NodeToolchain {
|
|
var out []delivery.NodeToolchain
|
|
for _, n := range nodes {
|
|
out = append(out, delivery.NodeToolchain{Node: n, Toolchain: delivery.Toolchain{Language: language, Version: version, Recipe: "1"}})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func TestChooseTakesTheAgreedNodesWithFewestRunningStepsTiesByName(t *testing.T) { // 1607/AC4, ADR 0478 clause 3
|
|
entries := tcs("go", "go1.27.1", "novox", "ace", "g14", "shanks")
|
|
nodes, tc, err := ChooseNodes("go", entries, placesRunning(map[string]int{"novox": 3, "ace": 1, "g14": 1, "shanks": 0}), nil, 2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(nodes) != 2 || nodes[0] != "shanks" || nodes[1] != "ace" {
|
|
t.Errorf("nodes = %v, want [shanks ace]: fewest steps first, a tie by name", nodes)
|
|
}
|
|
if tc.Version != "go1.27.1" || tc.Recipe != "1" || tc.Language != "go" {
|
|
t.Errorf("toolchain = %+v", tc)
|
|
}
|
|
}
|
|
|
|
func TestChooseWithOneNodeAnswersOneNode(t *testing.T) { // 1607/AC4
|
|
nodes, _, err := ChooseNodes("go", tcs("go", "go1.27.1", "novox"), nil, nil, 2)
|
|
if err != nil || len(nodes) != 1 || nodes[0] != "novox" {
|
|
t.Errorf("nodes = %v, err %v, want [novox]", nodes, err)
|
|
}
|
|
}
|
|
|
|
func TestChooseFailsNamingTheLanguageAndTheVersionsWhenNoNodeQualifies(t *testing.T) { // 1607/AC4
|
|
_, _, err := ChooseNodes("typescript", nil, nil, nil, 2)
|
|
if err == nil || !strings.Contains(err.Error(), "typescript") || !strings.Contains(err.Error(), delivery.ToolchainNoReport) {
|
|
t.Errorf("no report: error = %v, want it to name typescript and %q", err, delivery.ToolchainNoReport)
|
|
}
|
|
entries := append(tcs("go", "go1.27.1", "novox"), tcs("go", "go1.26.0", "ace")...)
|
|
_, _, err = ChooseNodes("go", entries, nil, nil, 2)
|
|
if err == nil || !strings.Contains(err.Error(), "go1.27.1") || !strings.Contains(err.Error(), "go1.26.0") || !strings.Contains(err.Error(), "go") {
|
|
t.Errorf("disagreeing nodes: error = %v, want both versions named", err)
|
|
}
|
|
}
|
|
|
|
func TestAgreeNeedsEqualDigestsAndNamesBothNodesWhenTheyDiffer(t *testing.T) { // 1607/AC4, ADR 0478 clause 4
|
|
d, err := Agree("tool", map[string]string{"ace": digest, "novox": digest})
|
|
if err != nil || d != digest {
|
|
t.Errorf("Agree = %q, %v, want %q", d, err, digest)
|
|
}
|
|
_, err = Agree("tool", map[string]string{"ace": digest, "novox": "sha256:" + hex64('9')})
|
|
if err == nil || !strings.Contains(err.Error(), "ace") || !strings.Contains(err.Error(), "novox") || !strings.Contains(err.Error(), digest) || !strings.Contains(err.Error(), hex64('9')) || !strings.Contains(err.Error(), "tool") {
|
|
t.Errorf("differing digests: error = %v, want the artifact, both nodes and both digests", err)
|
|
}
|
|
if d, err := Agree("tool", map[string]string{"ace": digest}); err != nil || d != digest {
|
|
t.Errorf("one node: %q, %v", d, err)
|
|
}
|
|
}
|
|
|
|
func TestChooseSkipsNodesThatAreNotOnlineAndFailsNamingThemWhenNoneIs(t *testing.T) { // 1607 review 3, ADR 0478 clause 3
|
|
entries := tcs("go", "go1.27.1", "ace", "g14", "novox")
|
|
online := func(n string) bool { return n != "g14" } // a sleeping laptop
|
|
nodes, tc, err := ChooseNodes("go", entries, placesRunning(map[string]int{"novox": 5}), online, 2)
|
|
if err != nil || len(nodes) != 2 || nodes[0] != "ace" || nodes[1] != "novox" || tc.Version != "go1.27.1" {
|
|
t.Errorf("nodes = %v, toolchain %+v, err %v, want [ace novox] with g14 left out although it runs nothing", nodes, tc, err)
|
|
}
|
|
_, tc, err = ChooseNodes("go", entries, nil, func(string) bool { return false }, 2)
|
|
if err == nil || !strings.Contains(err.Error(), "online") || !strings.Contains(err.Error(), "g14") || !strings.Contains(err.Error(), "go") {
|
|
t.Errorf("none online: error = %v, want it to name the nodes that report and that none is online", err)
|
|
}
|
|
if tc.Version != "go1.27.1" {
|
|
t.Errorf("none online: the agreed toolchain %+v is still answered", tc)
|
|
}
|
|
}
|
|
|
|
// placesRunning is Places with these steps counted as running, for a test of the choice.
|
|
func placesRunning(running map[string]int) *Places {
|
|
return &Places{running: running, changed: make(chan struct{})}
|
|
}
|
|
|
|
func TestChoosePrefersNodesBelowTheirCapacity(t *testing.T) { // round 3
|
|
entries := tcs("go", "go1.27.1", "ace", "novox", "shanks")
|
|
// shanks has capacity 3 with 2 running: room; ace has the default 1 with 1 running: none; novox has none running.
|
|
p := placesRunning(map[string]int{"shanks": 2, "ace": 1})
|
|
p.Capacity = map[string]int{"shanks": 3}
|
|
nodes, _, err := ChooseNodes("go", entries, p, nil, 2)
|
|
if err != nil || len(nodes) != 2 || nodes[0] != "novox" || nodes[1] != "shanks" {
|
|
t.Errorf("nodes = %v, err %v, want [novox shanks]: the nodes with room, ace at capacity left out", nodes, err)
|
|
}
|
|
}
|