Name no node in brother's and keycloak's fixtures (issue 1838)

This commit is contained in:
jochen
2026-10-22 21:43:05 +02:00
parent afc919e47e
commit 649865b7d2
12 changed files with 41 additions and 41 deletions
@@ -64,7 +64,7 @@ func TestTheAdminProcessAnswersAnAskOverARealBus(t *testing.T) {
Retention: jetstream.WorkQueuePolicy, Discard: jetstream.DiscardNew, MaxAge: 24 * time.Hour, MaxBytes: 8 << 20}); err != nil {
t.Fatal(err)
}
account := process.Account{URL: url, Node: "g14", Module: "brother", User: "g14.brother." + DeviceProcessID, Password: "pw"}
account := process.Account{URL: url, Node: "node-b", Module: "brother", User: "node-b.brother." + DeviceProcessID, Password: "pw"}
if _, err := js.CreateConsumer(ctx, AsksStream, jetstream.ConsumerConfig{Durable: account.QueueConsumerName(),
AckPolicy: jetstream.AckExplicitPolicy, AckWait: 30 * time.Second, MaxDeliver: 3}); err != nil {
t.Fatal(err)
+1 -1
View File
@@ -234,7 +234,7 @@ func TestAFetchedPDFIsStoredUnderItsHashAndPrinted(t *testing.T) {
// A refusal inside the mesh is answered, and nothing is stored nor printed.
fake.body = nil
before := len(r.objects.keys())
if _, err := r.call(t, "printer.print", map[string]any{"url": "http://127.0.0.1:9000/mesh-shanks-brother/x"}); err == nil || !strings.Contains(err.Error(), "loopback") {
if _, err := r.call(t, "printer.print", map[string]any{"url": "http://127.0.0.1:9000/mesh-node-d-brother/x"}); err == nil || !strings.Contains(err.Error(), "loopback") {
t.Errorf("a loopback address: error = %v", err)
}
if len(r.objects.keys()) != before || fake.body != nil {
+14 -14
View File
@@ -56,15 +56,15 @@ func TestPrintTakesExactlyOneSource(t *testing.T) {
for name, args := range map[string]map[string]any{
"none": {},
"only options": {"copies": float64(2)},
"object and path": {"object": key, "path": "/home/ops/a.pdf", "node": "g14"},
"object and path": {"object": key, "path": "/home/ops/a.pdf", "node": "node-b"},
"object and url": {"object": key, "url": "https://example.com/a.pdf"},
"path+node and url": {"path": "/home/ops/a.pdf", "node": "g14", "url": "https://example.com/a.pdf"},
"all three": {"object": key, "path": "/home/ops/a.pdf", "node": "g14", "url": "https://example.com/a.pdf"},
"path+node and url": {"path": "/home/ops/a.pdf", "node": "node-b", "url": "https://example.com/a.pdf"},
"all three": {"object": key, "path": "/home/ops/a.pdf", "node": "node-b", "url": "https://example.com/a.pdf"},
"path without node": {"path": "/home/ops/a.pdf"},
"node without path": {"node": "g14", "object": key},
"node without path": {"node": "node-b", "object": key},
"the retired upload": {"upload": "u1"},
"object and upload": {"object": key, "upload": "u1"},
"path and its object": {"path": "/home/ops/a.pdf", "node": "g14", "object": key},
"path and its object": {"path": "/home/ops/a.pdf", "node": "node-b", "object": key},
} {
_, err := r.call(t, "printer.print", args)
if err == nil {
@@ -82,7 +82,7 @@ func TestPrintTakesExactlyOneSource(t *testing.T) {
}
}
// 1598/AC2: with path and node g14, printer.print asks g14's node-files to upload the path into brother's bucket, and
// 1598/AC2: with path and node node-b, printer.print asks node-b's node-files to upload the path into brother's bucket, and
// queues a print ask that carries the returned key and the options: under 4 KiB, and no path, node or bytes.
func TestPrintOfAFileOfAnotherMachineUploadsThenPrintsTheKey(t *testing.T) {
fake := newIPPFake(t, 31, 5)
@@ -90,12 +90,12 @@ func TestPrintOfAFileOfAnotherMachineUploadsThenPrintsTheKey(t *testing.T) {
key := sha256Hex(doc)
up := withUpload(t, key, nil)
r := newRig(t, `{"printer":"192.0.2.10"}`, "pw")
r.objects.Put(t.Context(), key, "application/pdf", doc) // what g14's upload stored
got, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/letter.pdf", "node": "g14", "copies": float64(2)})
r.objects.Put(t.Context(), key, "application/pdf", doc) // what node-b's upload stored
got, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/letter.pdf", "node": "node-b", "copies": float64(2)})
if err != nil {
t.Fatal(err)
}
if len(up.seen()) != 1 || up.seen()[0] != "g14|/home/ops/letter.pdf|brother-test" {
if len(up.seen()) != 1 || up.seen()[0] != "node-b|/home/ops/letter.pdf|brother-test" {
t.Fatalf("uploads asked: %v", up.seen())
}
if len(r.bus.published) != 1 {
@@ -114,7 +114,7 @@ func TestPrintOfAFileOfAnotherMachineUploadsThenPrintsTheKey(t *testing.T) {
}
}
m := got.(map[string]any)
if m["job-id"] != float64(31) || m["node"] != "g14" || m["path"] != "/home/ops/letter.pdf" {
if m["job-id"] != float64(31) || m["node"] != "node-b" || m["path"] != "/home/ops/letter.pdf" {
t.Errorf("answer = %v", m)
}
if _, sent := fake.request(t); string(sent) != string(doc) {
@@ -127,7 +127,7 @@ func TestARefusedUploadIsAnsweredWithItsReasonAndNothingIsPrinted(t *testing.T)
fake := newIPPFake(t, 1, 3)
up := withUpload(t, "", errors.New("/home/ops/.ssh/id_ed25519 is refused by name: it is in .ssh, which holds an account's credentials"))
r := newRig(t, `{"printer":"192.0.2.10"}`, "pw")
_, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/.ssh/id_ed25519", "node": "g14"})
_, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/.ssh/id_ed25519", "node": "node-b"})
if err == nil || !strings.Contains(err.Error(), "is refused by name: it is in .ssh") {
t.Fatalf("error = %v", err)
}
@@ -277,7 +277,7 @@ func TestASlowUploadAndPrintAnswersStartedNeverATimeout(t *testing.T) {
t.Cleanup(func() { uploadVia = old })
r := newRig(t, `{"printer":"192.0.2.10"}`, "pw")
r.objects.Put(t.Context(), key, "application/pdf", doc)
got, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/letter.pdf", "node": "g14"})
got, err := r.call(t, "printer.print", map[string]any{"path": "/home/ops/letter.pdf", "node": "node-b"})
if err != nil {
t.Fatalf("a slow upload failed the call: %v", err)
}
@@ -292,7 +292,7 @@ func TestASlowUploadAndPrintAnswersStartedNeverATimeout(t *testing.T) {
t.Fatal(err)
}
if rm := read.(map[string]any); rm["state"] == nil {
if rm["job-id"] != float64(72) || rm["path"] != "/home/ops/letter.pdf" || rm["node"] != "g14" {
if rm["job-id"] != float64(72) || rm["path"] != "/home/ops/letter.pdf" || rm["node"] != "node-b" {
t.Errorf("the outcome = %v", rm)
}
break
@@ -309,7 +309,7 @@ func TestASlowUploadAndPrintAnswersStartedNeverATimeout(t *testing.T) {
time.Sleep(150 * time.Millisecond)
return "", errors.New("/home/ops/.ssh/id_ed25519 is refused by name")
}
got, _ = r.call(t, "printer.print", map[string]any{"path": "/home/ops/.ssh/id_ed25519", "node": "g14"})
got, _ = r.call(t, "printer.print", map[string]any{"path": "/home/ops/.ssh/id_ed25519", "node": "node-b"})
id2, _ := got.(map[string]any)["ask"].(string)
time.Sleep(300 * time.Millisecond)
if _, err := r.call(t, "printer.print", map[string]any{"ask": id2}); err == nil || !strings.Contains(err.Error(), "refused by name") {
+1 -1
View File
@@ -139,7 +139,7 @@ func newRig(t *testing.T, settings, password string) *printerRig {
return nil
},
Answers: answers,
Node: "shanks",
Node: "node-d",
Now: func() time.Time { return fixedNow },
}
bus := &fakeAskBus{worker: w, answers: answers}
+2 -2
View File
@@ -76,7 +76,7 @@ func TestTheDeviceAnswerCarriesALinkAndNoBytes(t *testing.T) {
}
// The real store: the binding's key signs, for the binding's host and port, in the module's bucket.
s3 := NewS3(StoreFacts{Scheme: "http", At: "novox.internal", Port: "20001", Bucket: "mesh-shanks-brother", Region: "eu-west",
s3 := NewS3(StoreFacts{Scheme: "http", At: "node-c.internal", Port: "20001", Bucket: "mesh-node-d-brother", Region: "eu-west",
Key: "binding-key", Secret: "binding-secret"})
s3.Now = func() time.Time { return fixedNow }
got, err := s3.Link("GET", "abc.pdf", 10*time.Minute)
@@ -84,7 +84,7 @@ func TestTheDeviceAnswerCarriesALinkAndNoBytes(t *testing.T) {
t.Fatal(err)
}
gu, _ := url.Parse(got)
if gu.Host != "novox.internal:20001" || gu.Path != "/mesh-shanks-brother/abc.pdf" ||
if gu.Host != "node-c.internal:20001" || gu.Path != "/mesh-node-d-brother/abc.pdf" ||
!strings.HasPrefix(gu.Query().Get("X-Amz-Credential"), "binding-key/") || gu.Query().Get("X-Amz-Expires") != "600" {
t.Errorf("link %s", got)
}
+1 -1
View File
@@ -111,7 +111,7 @@ func TestScanNowEmitsOneEventAfterTheScanIsKeptUnderTheSha256(t *testing.T) {
if kept, err := r.objects.Get(t.Context(), want+".pdf"); err != nil || !bytes.Equal(kept, pdf) {
t.Errorf("the bucket does not hold the filed PDF under its sha256 (%v)", err)
}
if ev.body["bytes"] != len(pdf) || ev.body["node"] != "shanks" || ev.body["cropped"] != true || ev.body["color-mode"] != "color" {
if ev.body["bytes"] != len(pdf) || ev.body["node"] != "node-d" || ev.body["cropped"] != true || ev.body["color-mode"] != "color" {
t.Errorf("event = %v", ev.body)
}
if want := fixedNow.UTC().Format(time.RFC3339); ev.body["scanned-at"] != want {
@@ -52,7 +52,7 @@ type guardWorld struct {
func newGuardWorld(t *testing.T) *guardWorld {
w := &guardWorld{now: time.Date(2026, 10, 5, 23, 55, 0, 0, time.UTC)}
w.f = newFakeKeycloak(t, "Novox", "old-password-from-2022")
w.f = newFakeKeycloak(t, "NodeC", "old-password-from-2022")
w.x = &fakeExec{f: w.f}
w.g = &Guard{KC: w.f.client("the-mesh-minted-this"), Exec: w.x,
Now: func() time.Time { return w.now },
@@ -195,7 +195,7 @@ func TestWhileTheAdminIsRefusedTheProvisionerDoesNotAskKeycloak(t *testing.T) {
w := newGuardWorld(t)
w.x.fails = true
w.g.Ensure(ctx, true, false)
a := provisioner{clients: OidcClients{KC: w.g.KC, Realm: "Novox"}, guard: w.g,
a := provisioner{clients: OidcClients{KC: w.g.KC, Realm: "NodeC"}, guard: w.g,
announce: func(string, map[string]any) {}, log: func(string, ...any) {}}
logins := w.f.logins
err := a.Create(ctx, grafana("s", nil))
@@ -91,13 +91,13 @@ func movedWorld(t *testing.T, h *harness.Harness) (f *fakeKeycloak, start func()
}
}
// 1332/AC1: a consumer only the grant file gives (oidc-client for novox.mesh-mail-web, not moved) is wanted and
// 1332/AC1: a consumer only the grant file gives (oidc-client for node-c.mesh-mail-web, not moved) is wanted and
// Adapter.Create is asked for its client, though keycloak runs on the moved path.
func TestAGrantFileConsumerNotMovedIsMadeOnTheMovedPath(t *testing.T) {
mailWeb := "mesh_novox_mail_web"
receives := grantGives(t, map[string]any{"as": mailWeb, "node": "novox", "values": map[string]any{
mailWeb := "mesh_node_c_mail_web"
receives := grantGives(t, map[string]any{"as": mailWeb, "node": "node-c", "values": map[string]any{
"label": "mail-web", "endpoint": "web", "callback": "/login/generic_oauth", "name": "mail.example.org"}})
h := &harness.Harness{Resource: ProvisionName, Receives: receives, Node: "novox"}
h := &harness.Harness{Resource: ProvisionName, Receives: receives, Node: "node-c"}
f, start := movedWorld(t, h)
start()
waitUntil(t, time.Second, func() bool {
@@ -113,13 +113,13 @@ func TestAGrantFileConsumerNotMovedIsMadeOnTheMovedPath(t *testing.T) {
})
}
// 1332/AC2: a grant-file consumer whose client already exists in the backend (mesh_ace_grafana) counts as asked and
// 1332/AC2: a grant-file consumer whose client already exists in the backend (mesh_node_a_grafana) counts as asked and
// is not held for retirement on the moved path.
func TestAGrantFileConsumerAlreadyInKeycloakIsNotRetiredOnTheMovedPath(t *testing.T) {
grafana := "mesh_ace_grafana"
receives := grantGives(t, map[string]any{"as": grafana, "node": "ace", "values": map[string]any{
grafana := "mesh_node_a_grafana"
receives := grantGives(t, map[string]any{"as": grafana, "node": "node-a", "values": map[string]any{
"label": "grafana", "endpoint": "web", "callback": "/login/generic_oauth", "name": "grafana.example.org"}})
h := &harness.Harness{Resource: ProvisionName, Receives: receives, Node: "ace",
h := &harness.Harness{Resource: ProvisionName, Receives: receives, Node: "node-a",
StablePasses: 1, StableFor: time.Millisecond}
f, start := movedWorld(t, h)
// Seed the backend with the client the mesh made earlier, exactly as grafana's already is — before anything
@@ -8,7 +8,7 @@ import "testing"
// 1332/AC3: the moved-path harness, built from the environment, reads MESH_RECEIVES the way the grant path does
// (main.go's other branch, line 67), as postgres's moved harness does (postgres-provider/main.go:43).
func TestTheMovedPathHarnessReadsMESH_RECEIVESAsTheGrantPathDoes(t *testing.T) {
env := map[string]string{"MESH_RECEIVES": "/grants/mesh.json", "MESH_NODE": "novox"}
env := map[string]string{"MESH_RECEIVES": "/grants/mesh.json", "MESH_NODE": "node-c"}
getenv := func(k string) string { return env[k] }
h := movedHarness(getenv, provisioner{})
if h.Receives != env["MESH_RECEIVES"] {
@@ -14,7 +14,7 @@ import (
"git.novox.be/novox/mesh-sdk/go/provider/harness"
)
const testIssuer = "https://id.example.org/realms/Novox"
const testIssuer = "https://id.example.org/realms/NodeC"
// keycloak's own part of the moved path (issue 849): the shared driving of it is proven in the SDK's harness package.
@@ -143,12 +143,12 @@ func TestBothPathsLeaveTheSameClientInKeycloak(t *testing.T) {
})
viaFile := made(func(p provisioner) {
list, _ := json.Marshal([]provider.ConsumerCredential{{Consumer: "home", Module: "grafana",
Credential: provider.PairName("novox", ProvisionName, "home", "grafana", ""), Value: "pw-" + grafana}})
Credential: provider.PairName("node-c", ProvisionName, "home", "grafana", ""), Value: "pw-" + grafana}})
file := filepath.Join(t.TempDir(), "consumers.json")
if err := os.WriteFile(file, list, 0o600); err != nil {
t.Fatal(err)
}
h := &harness.Harness{Resource: ProvisionName, Adapter: p, Node: "novox",
h := &harness.Harness{Resource: ProvisionName, Adapter: p, Node: "node-c",
Now: func() time.Time { return now }, Log: func(string, ...any) {}}
run, _, _, err := moved(file, h, testIssuer)
if err != nil {
@@ -156,10 +156,10 @@ func TestBothPathsLeaveTheSameClientInKeycloak(t *testing.T) {
}
bus := &bucketBus{buckets: map[string]map[string][]byte{}}
plan, _ := json.Marshal(map[string]any{"node": "home", "module": "grafana", "provisioning": map[string]any{
"provisions": []any{map[string]any{"provision": ProvisionName, "provider": "novox",
"provisions": []any{map[string]any{"provision": ProvisionName, "provider": "node-c",
"provider-module": "keycloak", "contributes": grafanaContributes, "names": grafanaNames}}}})
_ = bus.Put(ctx, provider.AssignmentsBucket, "home.grafana", plan)
pr := provider.New(provider.Options{Node: "novox", Module: "keycloak", Bus: bus,
pr := provider.New(provider.Options{Node: "node-c", Module: "keycloak", Bus: bus,
Vault: provider.ConsumersFile{Paths: []string{file}},
Offers: map[string]provider.Offer{ProvisionName: {Credential: provider.PerConsumer,
Serves: servedValues(testIssuer)}},
@@ -64,7 +64,7 @@ func RolesMapper() Rep {
var realmPath = regexp.MustCompile(`/realms/([^/]+)/?$`)
// RealmOf is the realm named by an issuer URL — `https://id.example/realms/Novox` is realm `Novox`.
// RealmOf is the realm named by an issuer URL — `https://id.example/realms/NodeC` is realm `NodeC`.
// The issuer is the one value an assignment sets, so the realm is read out of it rather than set a
// second time where the two could disagree.
func RealmOf(issuer string) (string, error) {
@@ -15,8 +15,8 @@ import (
)
func oidcWorld(t *testing.T) (*fakeKeycloak, OidcClients) {
f := newFakeKeycloak(t, "Novox", "pw")
return f, OidcClients{KC: f.client("pw"), Realm: "Novox"}
f := newFakeKeycloak(t, "NodeC", "pw")
return f, OidcClients{KC: f.client("pw"), Realm: "NodeC"}
}
// grafana is a dashboard on the home server, as the mesh hands it to the provisioner.
@@ -53,8 +53,8 @@ func mustHold(t *testing.T, o OidcClients, p harness.Provision, want bool) {
func TestTheRealmIsReadOutOfTheIssuer(t *testing.T) {
for issuer, want := range map[string]string{
"https://id.example.org/realms/Novox": "Novox",
"https://id.example.org/realms/Novox/": "Novox",
"https://id.example.org/realms/NodeC": "NodeC",
"https://id.example.org/realms/NodeC/": "NodeC",
"http://127.0.0.1:18500/realms/master": "master",
} {
if got, err := RealmOf(issuer); err != nil || got != want {