Name no node in cups's, nats's, mesh-watcher's, mesh-files's, dunst's and desk-channel's fixtures (issue 1838)
This commit is contained in:
@@ -22,7 +22,7 @@ Research 027 asked for "`cups` with the printer's driver". Measured on 2026-10-0
|
||||
| workstation | queue | device | prints through | driver package installed |
|
||||
|---|---|---|---|---|
|
||||
| laptop | `Brother` (MFC-L8690CDW) | `ipp://` on the LAN | **IPP Everywhere, driverless** | `brother-mfc-l8690cdw` (AUR), unused |
|
||||
| desktop | `Brother_MFC_Novox` (default) | `ipp://` on the LAN | **IPP Everywhere, driverless** | `brother-mfc-l8390cdw` and its `-debug` (AUR), unused |
|
||||
| desktop | `Brother_MFC_NodeC` (default) | `ipp://` on the LAN | **IPP Everywhere, driverless** | `brother-mfc-l8390cdw` and its `-debug` (AUR), unused |
|
||||
| desktop | `Kanjuro` (Canon PIXMA MG4200) | `cnijnet:` | the vendor's PPD and filter | `cnijfilter-mg4200` 3.80 (AUR) |
|
||||
|
||||
**Both Brother queues already print without a vendor driver.** CUPS's own IPP Everywhere support,
|
||||
|
||||
@@ -36,13 +36,13 @@ func theDesktop(t *testing.T, more func(line string, c Cmd) (Result, bool)) *fak
|
||||
case "lpstat -r":
|
||||
return ok("scheduler is running\n")
|
||||
case "lpstat -d":
|
||||
return ok("system default destination: Brother_MFC_Novox\n")
|
||||
return ok("system default destination: Brother_MFC_NodeC\n")
|
||||
case "lpstat -p":
|
||||
return ok("printer Brother_MFC_Novox is idle. enabled since Mon Jun 29 21:34:30 2026\n" +
|
||||
return ok("printer Brother_MFC_NodeC is idle. enabled since Mon Jun 29 21:34:30 2026\n" +
|
||||
"printer Kanjuro disabled since Sun Jun 9 11:16:03 2024 -\n\tPaused\n")
|
||||
case "lpstat -a":
|
||||
return ok("Brother_MFC_Novox accepting requests since Mon Jun 29 21:34:30 2026\nKanjuro not accepting requests since Sun Jun 9 11:16:03 2024 -\n\tRejecting Jobs\n")
|
||||
case "lpoptions -p Brother_MFC_Novox":
|
||||
return ok("Brother_MFC_NodeC accepting requests since Mon Jun 29 21:34:30 2026\nKanjuro not accepting requests since Sun Jun 9 11:16:03 2024 -\n\tRejecting Jobs\n")
|
||||
case "lpoptions -p Brother_MFC_NodeC":
|
||||
return ok(`copies=1 device-uri=ipp://192.0.2.171/ipp/port1 finishings=3 marker-levels=70,100,8,100 marker-low-levels=10,10,10,10 marker-names='Black\ Toner\ Cartridge,Cyan\ Toner\ Cartridge,Magenta\ Toner\ Cartridge,Yellow\ Toner\ Cartridge' marker-types=toner,toner,toner,toner printer-is-shared=false printer-make-and-model='Printer - IPP Everywhere' printer-state-reasons=none`)
|
||||
case "lpoptions -p Kanjuro":
|
||||
return ok(`device-uri=cnijnet:/18-0C-AC-B0-62-83 printer-is-shared=false printer-make-and-model='Canon MG4200 series Ver.3.80' printer-state-reasons=paused`)
|
||||
@@ -54,7 +54,7 @@ func theDesktop(t *testing.T, more func(line string, c Cmd) (Result, bool)) *fak
|
||||
func TestPrintersReadsStateDeviceModelAndSupplies(t *testing.T) {
|
||||
theDesktop(t, nil)
|
||||
got, err := Printers()
|
||||
if err != nil || len(got.Printers) != 2 || got.Default != "Brother_MFC_Novox" || got.Scheduler != "scheduler is running" {
|
||||
if err != nil || len(got.Printers) != 2 || got.Default != "Brother_MFC_NodeC" || got.Scheduler != "scheduler is running" {
|
||||
t.Fatalf("%+v %v", got, err)
|
||||
}
|
||||
b, k := got.Printers[0], got.Printers[1]
|
||||
@@ -186,11 +186,11 @@ func TestDefaultReadsAndSetsThroughSudo(t *testing.T) {
|
||||
return Result{}, false
|
||||
})
|
||||
got, err := Default("")
|
||||
if err != nil || got["default"] != "Brother_MFC_Novox" {
|
||||
if err != nil || got["default"] != "Brother_MFC_NodeC" {
|
||||
t.Fatalf("%v %v", got, err)
|
||||
}
|
||||
got, err = Default("Kanjuro")
|
||||
if err != nil || got["default"] != "Kanjuro" || got["was"] != "Brother_MFC_Novox" {
|
||||
if err != nil || got["default"] != "Kanjuro" || got["was"] != "Brother_MFC_NodeC" {
|
||||
t.Fatalf("%v %v", got, err)
|
||||
}
|
||||
if l := f.lines(); l[len(l)-1] != "sudo -n lpadmin -d Kanjuro" {
|
||||
|
||||
@@ -133,7 +133,7 @@ func TestANotifierThatStartedAgainIsShownNothingFromMemory(t *testing.T) {
|
||||
d, shown, said, store := newDesk(t, "laptop")
|
||||
d.Paused("laptop", false)
|
||||
d.SayStanding()
|
||||
take(t, d, asks.Show, asks.Message{Handle: "open", Title: "2 failed services on shanks",
|
||||
take(t, d, asks.Show, asks.Message{Handle: "open", Title: "2 failed services on node-d",
|
||||
Buttons: []asks.Button{{Label: "Silence for a week", Ticket: "t-open"}}})
|
||||
take(t, d, asks.Show, asks.Message{Handle: "silenced", Title: "Agent-home shrank",
|
||||
Buttons: []asks.Button{{Label: "Silence for a week", Ticket: "t-silenced"}}})
|
||||
@@ -162,7 +162,7 @@ func TestANotifierThatStartedAgainIsShownNothingFromMemory(t *testing.T) {
|
||||
t.Fatalf("the standing after the start: %d said, last %s", len(got)-standings, got[len(got)-1])
|
||||
}
|
||||
// The router says the open one again under its handle: in place of its notification, with its answers.
|
||||
take(t, d, asks.Show, asks.Message{Handle: "open", Title: "2 failed services on shanks",
|
||||
take(t, d, asks.Show, asks.Message{Handle: "open", Title: "2 failed services on node-d",
|
||||
Buttons: []asks.Button{{Label: "Silence for a week", Ticket: "t-open"}}})
|
||||
last := (*shown)[len(*shown)-1]
|
||||
if len(*shown) != before+1 || last.args["replace_id"] != openID || last.args["actions"] == nil {
|
||||
@@ -329,7 +329,7 @@ func TestItRunsAsItsOwnAccount(t *testing.T) {
|
||||
// was not shown; a message under a new handle replaces nothing.
|
||||
func TestAMessageSaidAgainUnderItsHandleReplacesItsNotification(t *testing.T) {
|
||||
d, shown, _, store := newDesk(t, "laptop", "desktop")
|
||||
take(t, d, asks.Send, asks.Message{Handle: "m1", Title: "2 failed services on shanks"})
|
||||
take(t, d, asks.Send, asks.Message{Handle: "m1", Title: "2 failed services on node-d"})
|
||||
take(t, d, asks.Send, asks.Message{Handle: "m2", Title: "another problem"})
|
||||
if len(*shown) != 4 {
|
||||
t.Fatalf("shown %d", len(*shown))
|
||||
@@ -342,7 +342,7 @@ func TestAMessageSaidAgainUnderItsHandleReplacesItsNotification(t *testing.T) {
|
||||
first := store["m1"].On
|
||||
// The desk now names a third machine as well.
|
||||
d.Machines = func() []string { return []string{"laptop", "desktop", "third"} }
|
||||
take(t, d, asks.Show, asks.Message{Handle: "m1", Title: "Still open: 2 failed services on shanks", Urgent: true,
|
||||
take(t, d, asks.Show, asks.Message{Handle: "m1", Title: "Still open: 2 failed services on node-d", Urgent: true,
|
||||
Buttons: []asks.Button{{Label: "Silence for a week", Ticket: "t1"}}})
|
||||
again := (*shown)[4:]
|
||||
if len(again) != 3 {
|
||||
@@ -367,7 +367,7 @@ func TestAMessageSaidAgainUnderItsHandleReplacesItsNotification(t *testing.T) {
|
||||
// later edit or clearing still reaches it; failing everywhere, it is said to the router as failed.
|
||||
func TestAFailedReplaceKeepsTheNotificationItWasToReplace(t *testing.T) {
|
||||
d, shown, said, store := newDesk(t, "laptop", "desktop")
|
||||
take(t, d, asks.Send, asks.Message{Handle: "m1", Title: "2 failed services on shanks"})
|
||||
take(t, d, asks.Send, asks.Message{Handle: "m1", Title: "2 failed services on node-d"})
|
||||
first := store["m1"].On
|
||||
notify := d.Notify
|
||||
d.Notify = func(machine string, args map[string]any) (json.RawMessage, error) {
|
||||
@@ -376,12 +376,12 @@ func TestAFailedReplaceKeepsTheNotificationItWasToReplace(t *testing.T) {
|
||||
}
|
||||
return notify(machine, args)
|
||||
}
|
||||
take(t, d, asks.Send, asks.Message{Handle: "m1", Title: "Still open: 2 failed services on shanks"})
|
||||
take(t, d, asks.Send, asks.Message{Handle: "m1", Title: "Still open: 2 failed services on node-d"})
|
||||
if got := store["m1"].On["desktop"]; got != first["desktop"] {
|
||||
t.Fatalf("the desktop's notification %d was forgotten: %v", first["desktop"], store["m1"].On)
|
||||
}
|
||||
d.Notify = func(string, map[string]any) (json.RawMessage, error) { return nil, errors.New("away") }
|
||||
take(t, d, asks.Send, asks.Message{Handle: "m1", Title: "Now urgent: 2 failed services on shanks"})
|
||||
take(t, d, asks.Send, asks.Message{Handle: "m1", Title: "Now urgent: 2 failed services on node-d"})
|
||||
if len(said[asks.IntakeSubject(asks.FailedWhat, Kind)]) != 1 {
|
||||
t.Fatalf("shown nowhere, and not said as failed")
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ func TestANotificationsChosenAnswerIsSaidAsAnEvent(t *testing.T) {
|
||||
withBus(t)
|
||||
bin := fakeBinaries(t, map[string]string{"notify-send": `for a in "$@"; do printf '[%s]' "$a"; done > "$LOG"; echo 42; sleep 0.2; echo "$CHOSEN"`})
|
||||
t.Setenv("LOG", filepath.Join(bin, "log"))
|
||||
t.Setenv("MESH_NODE", "g14")
|
||||
t.Setenv("MESH_NODE", "node-b")
|
||||
var mu sync.Mutex
|
||||
var said []map[string]any
|
||||
before := emit
|
||||
@@ -58,7 +58,7 @@ func TestANotificationsChosenAnswerIsSaidAsAnEvent(t *testing.T) {
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
}
|
||||
mu.Lock()
|
||||
if len(said) != 1 || said[0]["token"] != "c3d4" || said[0]["id"] != 42 || said[0]["machine"] != "g14" {
|
||||
if len(said) != 1 || said[0]["token"] != "c3d4" || said[0]["id"] != 42 || said[0]["machine"] != "node-b" {
|
||||
t.Fatalf("said %v", said)
|
||||
}
|
||||
said = nil
|
||||
@@ -96,7 +96,7 @@ func TestActionsAreRefusedForWhatTheyCannotBe(t *testing.T) {
|
||||
// **A bundle that started says so**, so the operator channel shows again the answers lost with the one
|
||||
// before.
|
||||
func TestABundleThatStartedSaysSo(t *testing.T) {
|
||||
t.Setenv("MESH_NODE", "g14")
|
||||
t.Setenv("MESH_NODE", "node-b")
|
||||
var said []string
|
||||
before := emit
|
||||
emit = func(event string, body any) error {
|
||||
@@ -105,7 +105,7 @@ func TestABundleThatStartedSaysSo(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(func() { emit = before })
|
||||
sayStarted()
|
||||
if len(said) != 1 || said[0] != "started map[machine:g14]" {
|
||||
if len(said) != 1 || said[0] != "started map[machine:node-b]" {
|
||||
t.Fatalf("%v", said)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func testFiles(t *testing.T) *rig {
|
||||
r.Root = g.root
|
||||
r.Now = func() time.Time { return time.Date(2026, 10, 16, 12, 0, 0, 0, time.UTC) }
|
||||
seq := 0
|
||||
g.Files = &Files{Reader: r, State: filepath.Join(dir, "state"), Owned: map[string]string{}, Node: "shanks",
|
||||
g.Files = &Files{Reader: r, State: filepath.Join(dir, "state"), Owned: map[string]string{}, Node: "node-d",
|
||||
OwnerOf: func(p string) (Ident, error) {
|
||||
if id, ok := g.owners[p]; ok {
|
||||
return id, nil
|
||||
@@ -344,7 +344,7 @@ func TestAnOwnedPathIsRefusedNamingItsOwnerAndPassesWithAnOverride(t *testing.T)
|
||||
if len(lines) != 1 || lines[0]["override"] != ov.Override {
|
||||
t.Errorf("log: %v", lines)
|
||||
}
|
||||
if len(g.told) != 1 || !strings.HasPrefix(g.told[0], "mesh-files on shanks | ") ||
|
||||
if len(g.told) != 1 || !strings.HasPrefix(g.told[0], "mesh-files on node-d | ") ||
|
||||
!strings.Contains(g.told[0], ov.Override) || !strings.Contains(g.told[0], "mesh-hosts (node-hostname)") ||
|
||||
!strings.Contains(g.told[0], "person.jochen") {
|
||||
t.Errorf("told: %v", g.told)
|
||||
@@ -384,7 +384,7 @@ func TestACredentialFileIsRefusedToReadButMayBeCopied(t *testing.T) {
|
||||
func TestATargetOnAnotherNodeIsRefused(t *testing.T) {
|
||||
g := testFiles(t)
|
||||
write(t, g.path("a"), "x")
|
||||
for _, to := range []string{"ace:/tmp/a", "novox:/etc/hosts"} {
|
||||
for _, to := range []string{"node-a:/tmp/a", "node-c:/etc/hosts"} {
|
||||
for _, run := range []func() error{
|
||||
func() error { _, err := g.Copy(by, g.path("a"), to); return err },
|
||||
func() error { _, err := g.Move(by, g.path("a"), to); return err },
|
||||
|
||||
@@ -80,7 +80,7 @@ func TestUploadSendsTheFileUnderItsHash(t *testing.T) {
|
||||
g, st, lv := transferRig(t)
|
||||
body := bytes.Repeat([]byte("a document\n"), 1000)
|
||||
write(t, g.path("home/ops/doc.pdf"), string(body))
|
||||
ans, err := g.Upload(g.path("home/ops/doc.pdf"), "mesh-shanks-brother", "")
|
||||
ans, err := g.Upload(g.path("home/ops/doc.pdf"), "mesh-node-d-brother", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -88,10 +88,10 @@ func TestUploadSendsTheFileUnderItsHash(t *testing.T) {
|
||||
if ans.Key != want || ans.SHA256 != want || ans.Size != int64(len(body)) {
|
||||
t.Fatalf("answer %+v", ans)
|
||||
}
|
||||
if !bytes.Equal(st.objects["/mesh-shanks-brother/"+want], body) {
|
||||
if !bytes.Equal(st.objects["/mesh-node-d-brother/"+want], body) {
|
||||
t.Fatal("the store did not receive exactly the file's bytes")
|
||||
}
|
||||
if len(lv.asks) != 1 || lv.asks[0] != "put mesh-shanks-brother/"+want {
|
||||
if len(lv.asks) != 1 || lv.asks[0] != "put mesh-node-d-brother/"+want {
|
||||
t.Fatalf("link asks %v", lv.asks)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func (c *clock) pass(d time.Duration) { c.t = c.t.Add(d) }
|
||||
func watcher(t *testing.T) (*Watcher, *fakeTelegram, *clock) {
|
||||
c := &clock{t: time.Date(2026, 10, 6, 12, 0, 0, 0, time.UTC)}
|
||||
tg := &fakeTelegram{}
|
||||
return NewWatcher(tg, c.now, t.Logf, "ace"), tg, c
|
||||
return NewWatcher(tg, c.now, t.Logf, "node-a"), tg, c
|
||||
}
|
||||
|
||||
// beatEvery has the controller's doctor run, and the bus answer, every five minutes up to d.
|
||||
@@ -204,11 +204,11 @@ func TestNotGivenATokenIsBlind(t *testing.T) {
|
||||
|
||||
func TestOnTheControlNodeItSaysItIsMisplaced(t *testing.T) {
|
||||
w, _, _ := watcher(t)
|
||||
w.Placed([]string{"novox"})
|
||||
if st := w.Status("listening"); st.Verdict != "ok: watching" || st.Control != "novox" {
|
||||
w.Placed([]string{"node-c"})
|
||||
if st := w.Status("listening"); st.Verdict != "ok: watching" || st.Control != "node-c" {
|
||||
t.Fatalf("%+v", st)
|
||||
}
|
||||
w.Placed([]string{"ace"})
|
||||
w.Placed([]string{"node-a"})
|
||||
if st := w.Status("listening"); !strings.HasPrefix(st.Verdict, "MISPLACED") {
|
||||
t.Fatalf("%+v", st)
|
||||
}
|
||||
|
||||
@@ -135,8 +135,8 @@ func TestClosedConnectionsArePerUserAndNameAndSayWhichWereDropped(t *testing.T)
|
||||
const closed = `{"connections":[
|
||||
{"cid":10,"name":"mesh-controller verb conditions","authorized_user":"controller","start":"2026-10-08T14:12:00Z","stop":"2026-10-08T14:12:01Z","reason":"Client Closed"},
|
||||
{"cid":11,"name":"mesh-controller verb conditions","authorized_user":"controller","start":"2026-10-08T14:13:00Z","stop":"2026-10-08T14:13:03Z","reason":"Client Closed"},
|
||||
{"cid":12,"name":"ace.node-tools","authorized_user":"ace.node-tools","start":"2026-10-08T13:00:00Z","stop":"2026-10-08T14:14:00Z","reason":"Stale Connection"},
|
||||
{"cid":13,"name":"ace.node-tools","authorized_user":"ace.node-tools","start":"2026-10-08T14:14:05Z","stop":"2026-10-08T14:15:00Z","reason":"Read Error"},
|
||||
{"cid":12,"name":"node-a.node-tools","authorized_user":"node-a.node-tools","start":"2026-10-08T13:00:00Z","stop":"2026-10-08T14:14:00Z","reason":"Stale Connection"},
|
||||
{"cid":13,"name":"node-a.node-tools","authorized_user":"node-a.node-tools","start":"2026-10-08T14:14:05Z","stop":"2026-10-08T14:15:00Z","reason":"Read Error"},
|
||||
{"cid":5,"name":"old","authorized_user":"controller","start":"2026-10-08T10:00:00Z","stop":"2026-10-08T10:00:01Z","reason":"Client Closed"},
|
||||
{"cid":14,"name":"","start":"2026-10-08T14:16:00Z","stop":"2026-10-08T14:16:00Z","reason":"Authentication Failure"}]}`
|
||||
now, _ := time.Parse(time.RFC3339, "2026-10-08T14:20:00Z")
|
||||
@@ -157,7 +157,7 @@ func TestClosedConnectionsArePerUserAndNameAndSayWhichWereDropped(t *testing.T)
|
||||
c.Names[0].Name != "mesh-controller verb conditions" || c.Names[0].Lived != 3 {
|
||||
t.Errorf("the controller's: %+v", c)
|
||||
}
|
||||
tools := byUser["ace.node-tools"]
|
||||
tools := byUser["node-a.node-tools"]
|
||||
if tools.Closed != 2 || tools.Dropped != 2 || tools.Names[0].Reasons["Stale Connection"] != 1 {
|
||||
t.Errorf("the runtime's: %+v", tools)
|
||||
}
|
||||
@@ -168,7 +168,7 @@ func TestClosedConnectionsArePerUserAndNameAndSayWhichWereDropped(t *testing.T)
|
||||
t.Error("a record older than the window does not reach back the whole window")
|
||||
}
|
||||
narrowed, _ := ClosedConnections([]byte(closed), now, 1, "node-tools")
|
||||
if got := narrowed["users"].([]ClosedUser); len(got) != 1 || got[0].User != "ace.node-tools" {
|
||||
if got := narrowed["users"].([]ClosedUser); len(got) != 1 || got[0].User != "node-a.node-tools" {
|
||||
t.Errorf("narrowed: %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user