diff --git a/modules/brother/cmd/brother/printlink_test.go b/modules/brother/cmd/brother/printlink_test.go index 045c4eb8..56670d1f 100644 --- a/modules/brother/cmd/brother/printlink_test.go +++ b/modules/brother/cmd/brother/printlink_test.go @@ -6,12 +6,14 @@ import ( "os" "path/filepath" "strings" + "sync" "testing" "time" ) // uploadFake stands for node-files.upload on another machine: it records the ask and answers a key, or refuses. type uploadFake struct { + mu sync.Mutex calls []string key string err error @@ -19,11 +21,20 @@ type uploadFake struct { // withUpload puts a fake node-files in the tool side's place, and the bucket file the mesh writes from the binding // (files/bucket.json) where the tool reads it. +// seen is the uploads asked so far, read under the fake's lock (the print runs in the background). +func (f *uploadFake) seen() []string { + f.mu.Lock() + defer f.mu.Unlock() + return append([]string(nil), f.calls...) +} + func withUpload(t *testing.T, key string, err error) *uploadFake { t.Helper() f := &uploadFake{key: key, err: err} old := uploadVia uploadVia = func(node, path, bucket string) (string, error) { + f.mu.Lock() + defer f.mu.Unlock() f.calls = append(f.calls, node+"|"+path+"|"+bucket) return f.key, f.err } @@ -66,8 +77,8 @@ func TestPrintTakesExactlyOneSource(t *testing.T) { t.Errorf("%s: the refusal does not name the rule: %v", name, err) } } - if r.bus.asks() != 0 || len(up.calls) != 0 || fake.body != nil { - t.Errorf("%d asks queued, %d uploads asked, printer sent %d bytes", r.bus.asks(), len(up.calls), len(fake.body)) + if r.bus.asks() != 0 || len(up.seen()) != 0 || fake.body != nil { + t.Errorf("%d asks queued, %d uploads asked, printer sent %d bytes", r.bus.asks(), len(up.seen()), len(fake.body)) } } @@ -84,8 +95,8 @@ func TestPrintOfAFileOfAnotherMachineUploadsThenPrintsTheKey(t *testing.T) { if err != nil { t.Fatal(err) } - if len(up.calls) != 1 || up.calls[0] != "g14|/home/ops/letter.pdf|brother-test" { - t.Fatalf("uploads asked: %v", up.calls) + if len(up.seen()) != 1 || up.seen()[0] != "g14|/home/ops/letter.pdf|brother-test" { + t.Fatalf("uploads asked: %v", up.seen()) } if len(r.bus.published) != 1 { t.Fatalf("%d asks queued", len(r.bus.published)) @@ -120,8 +131,8 @@ func TestARefusedUploadIsAnsweredWithItsReasonAndNothingIsPrinted(t *testing.T) if err == nil || !strings.Contains(err.Error(), "is refused by name: it is in .ssh") { t.Fatalf("error = %v", err) } - if len(up.calls) != 1 || r.bus.asks() != 0 || fake.body != nil { - t.Errorf("%d uploads, %d asks queued, printer sent %d bytes", len(up.calls), r.bus.asks(), len(fake.body)) + if len(up.seen()) != 1 || r.bus.asks() != 0 || fake.body != nil { + t.Errorf("%d uploads, %d asks queued, printer sent %d bytes", len(up.seen()), r.bus.asks(), len(fake.body)) } } @@ -272,7 +283,7 @@ func TestASlowUploadAndPrintAnswersStartedNeverATimeout(t *testing.T) { } m := got.(map[string]any) id, _ := m["ask"].(string) - if m["state"] != "started" || id == "" || len(up.calls) > 1 { + if m["state"] != "started" || id == "" || len(up.seen()) > 1 { t.Fatalf("answer %v", m) } for deadline := time.Now().Add(5 * time.Second); ; { @@ -290,8 +301,8 @@ func TestASlowUploadAndPrintAnswersStartedNeverATimeout(t *testing.T) { t.Fatal("never done") } } - if len(up.calls) != 1 || len(r.bus.published) != 1 || r.bus.published[0].Object != key { - t.Errorf("uploads %v, asks %v", up.calls, r.bus.published) + if len(up.seen()) != 1 || len(r.bus.published) != 1 || r.bus.published[0].Object != key { + t.Errorf("uploads %v, asks %v", up.seen(), r.bus.published) } // An upload that fails after the call answered is the outcome, read with the ask. uploadVia = func(node, path, bucket string) (string, error) {