mesh/delivery-group group feat/774-l3-reland rejected: composed together: the checker's verdict at the members' heads (b48c90fea31f): integration: mesh-self-ch…
mesh/delivery closed: a newer head of the same pull request
mesh/check failed: integration: mesh-self-check/cmd/mesh-self-check.TestTheSelfCheckWholeRunsOnTheBus: the run answered {Run:doctor-1793351737-1 At:20…
One commit with exactly the tree of the reviewed head35b4509c0a, on main12c2574c9d, so two compiled programs added and removed on the branch leave no trace in history (issue 1577).
163 lines
6.1 KiB
Go
163 lines
6.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"slices"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// Issue 1482 (novox/hq ADR 0466 §3): the provider watches the build modules' state `keys` beside ssh-client's, and
|
|
// registers each builder entry read-only on nox-builder.
|
|
|
|
func keyJSON(node, account, kind, public string) []byte {
|
|
b, _ := json.Marshal(map[string]string{"node": node, "account": account, "kind": kind, "public": public,
|
|
"fingerprint": "SHA256:x", "at": "2026-10-20T10:00:00Z"})
|
|
return b
|
|
}
|
|
|
|
// watched is a team rig whose keys come through watches of the modules' states, as in the running provider.
|
|
type watched struct {
|
|
*teamRig
|
|
sources map[string]*fakeKeys
|
|
passes *int
|
|
logs *[]string
|
|
mu *sync.Mutex
|
|
}
|
|
|
|
func newWatched(t *testing.T) *watched {
|
|
r := newTeamRig(t)
|
|
r.svc.loaded, r.svc.loadedFrom = false, map[string]bool{}
|
|
r.svc.Pause = func(time.Duration) {}
|
|
n, logs, mu := 0, []string{}, &sync.Mutex{}
|
|
r.svc.OnKeys = func(string) { n++ }
|
|
r.svc.cfg.Log = func(f string, a ...any) { mu.Lock(); logs = append(logs, fmt.Sprintf(f, a...)); mu.Unlock() }
|
|
w := &watched{teamRig: r, sources: map[string]*fakeKeys{}, passes: &n, logs: &logs, mu: mu}
|
|
for _, module := range []string{"ssh-client", "mesh-build-go", "mesh-build-node", "mesh-build-image"} {
|
|
w.sources[module] = &fakeKeys{}
|
|
if err := r.svc.WatchSource(context.Background(), module, w.sources[module]); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
return w
|
|
}
|
|
|
|
func (w *watched) said() string {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
return strings.Join(*w.logs, "\n")
|
|
}
|
|
|
|
// 1482/AC1: a mesh-build-go.keys entry ace.mesh-build-go of kind builder: its public half is registered read-only on
|
|
// nox-builder titled mesh:ace.mesh-build-go.
|
|
func TestABuilderEntryOfABuildModulesStateIsRegisteredReadOnlyOnNoxBuilder(t *testing.T) {
|
|
w := newWatched(t)
|
|
w.bind("ace", "mesh-build-go")
|
|
w.sources["mesh-build-go"].send("ace.mesh-build-go", "put", keyJSON("ace", "mesh-build-go", "builder", pubGo+" mesh-build-go@ace (mesh)"), true)
|
|
w.pass()
|
|
keys := w.forge.keys["nox-builder"]
|
|
if len(keys) != 1 || keys[0].Title != "mesh:ace.mesh-build-go" || !keys[0].ReadOnly || keys[0].Key != pubGo+" mesh-build-go@ace (mesh)" {
|
|
t.Errorf("nox-builder's keys = %+v", keys)
|
|
}
|
|
if !w.svc.loadedFrom["mesh-build-go"] {
|
|
t.Errorf("the state was watched and its keys are not counted as read")
|
|
}
|
|
}
|
|
|
|
// 1482/AC2: that entry changed: the old key is removed and the new one registered; deleted: the key is removed and no key
|
|
// titled otherwise is touched.
|
|
func TestAChangedBuilderEntryReplacesItsKeyAndADeletedOneRemovesIt(t *testing.T) {
|
|
w := newWatched(t)
|
|
w.bind("ace", "mesh-build-go")
|
|
src := w.sources["mesh-build-go"]
|
|
src.send("ace.mesh-build-go", "put", keyJSON("ace", "mesh-build-go", "builder", pubGo), true)
|
|
w.pass()
|
|
w.forge.mu.Lock()
|
|
w.forge.keys["nox-builder"] = append(w.forge.keys["nox-builder"], forgeKey{ID: 99, Title: "my own", Key: pubOps})
|
|
w.forge.mu.Unlock()
|
|
|
|
before := *w.passes
|
|
src.send("ace.mesh-build-go", "put", keyJSON("ace", "mesh-build-go", "builder", pubNode), false)
|
|
if *w.passes != before+1 {
|
|
t.Errorf("a change asked for %d passes, want 1", *w.passes-before)
|
|
}
|
|
w.pass()
|
|
got := w.forge.keys["nox-builder"]
|
|
if len(got) != 2 || got[0].Title != "my own" || got[1].Title != "mesh:ace.mesh-build-go" || got[1].Key != pubNode || !got[1].ReadOnly {
|
|
t.Errorf("after the change: %+v", got)
|
|
}
|
|
|
|
src.send("ace.mesh-build-go", "delete", nil, false)
|
|
w.pass()
|
|
if got := strings.Join(w.forge.titles("nox-builder"), ","); got != "my own" {
|
|
t.Errorf("after the delete: %s, want only the operator's key", got)
|
|
}
|
|
}
|
|
|
|
// 1482/AC3: an entry of kind machine in a build module's state, or of kind builder in ssh-client's, is ignored and
|
|
// said in the provider's log.
|
|
func TestAKeyOfTheWrongKindForItsStateIsIgnoredAndSaid(t *testing.T) {
|
|
w := newWatched(t)
|
|
w.bind("ace", "mesh-build-go")
|
|
w.bind("g14", "ssh-client")
|
|
w.sources["mesh-build-go"].send("ace.mesh-build-go", "put", keyJSON("ace", "mesh-build-go", "machine", pubGo), true)
|
|
w.sources["ssh-client"].send("g14.nox", "put", keyJSON("g14", "nox", "builder", pubA), true)
|
|
w.pass()
|
|
if len(w.forge.users) != 0 || w.bus.has("ace.mesh-build-go.forge-account") || w.bus.has("g14.ssh-client.forge-account") {
|
|
t.Errorf("a key of the wrong kind was served: users %v", w.forge.users)
|
|
}
|
|
said := w.said()
|
|
for _, want := range []string{`ace.mesh-build-go in the state keys of mesh-build-go is of kind "machine", not "builder"`, `g14.nox in the state keys of ssh-client is of kind "builder", not "machine"`} {
|
|
if !strings.Contains(said, want) {
|
|
t.Errorf("the log lacks %q:\n%s", want, said)
|
|
}
|
|
}
|
|
}
|
|
|
|
// A build module's state that never answers holds back its own entries, never a machine's.
|
|
func TestABuildModulesStateThatNeverAnswersHoldsBackOnlyItsOwnEntries(t *testing.T) {
|
|
w := newWatched(t)
|
|
w.svc.loadedFrom = map[string]bool{} // mesh-build-go's watch has not answered
|
|
w.bind("ace", "mesh-build-go")
|
|
w.bind("g14", "ssh-client")
|
|
w.sources["ssh-client"].send("g14.nox", "put", keyJSON("g14", "nox", "machine", pubA+" nox@g14 (mesh)"), true)
|
|
out := w.pass()
|
|
if !w.bus.has("g14.ssh-client.forge-account") {
|
|
t.Errorf("a machine's entry waited for a build module's state")
|
|
}
|
|
waits := 0
|
|
for _, o := range out {
|
|
if strings.Contains(o.Key, "mesh-build-go") && strings.Contains(o.Why, "keys of mesh-build-go are not read yet") {
|
|
waits++
|
|
}
|
|
}
|
|
if waits != 1 {
|
|
t.Errorf("outcomes = %+v", out)
|
|
}
|
|
}
|
|
|
|
// 1482/AC4 (the provider's half): the manifest reads the states of both build modules beside ssh-client's and the
|
|
// seat mesh-provisioner's plans; the provider watches exactly the modules the code names as builders.
|
|
func TestTheManifestReadsTheBuildModulesKeys(t *testing.T) {
|
|
raw, err := os.ReadFile("../../module.json")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var m struct {
|
|
Reads []string `json:"reads"`
|
|
}
|
|
if err := json.Unmarshal(raw, &m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, state := range []string{"mesh-provisioner.plans", "mesh-provisioner.provisions", "ssh-client.keys", "mesh-build-go.keys", "mesh-build-node.keys", "mesh-build-image.keys"} {
|
|
if !slices.Contains(m.Reads, state) {
|
|
t.Errorf("gitea's reads %v lack %q", m.Reads, state)
|
|
}
|
|
}
|
|
}
|