issue 1453: read the fake printer's connection count under its lock, which the race detector requires; say 700 KiB as ADR 0468 does
mesh/merge-gate head 2f6086120c46 merged into trunk 809dd76973fd — pass: builds scan, new: modules/brother, sent nowhere; no bus step; every machine compos…
mesh/repo-check head 2f6086120c46 merged into trunk 809dd76973fd — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery stopped: a merged change never reached the machines: its walk plan-1792525688362824501 ended done before its word without building scan (mo…

This commit is contained in:
2026-10-20 21:39:27 +02:00
parent 02cb424d5c
commit 2f6086120c
4 changed files with 17 additions and 12 deletions
+1 -1
View File
@@ -82,7 +82,7 @@ is not given, and the printer is not contacted.
### Documents in parts ### Documents in parts
The bus refuses a message over 1 MiB, so a document crosses it in parts of at most 700 KiB (both the size this module The bus refuses a message over 1 MiB, so a document crosses it in parts of at most 700 KiB (both the size this module
cuts and the most it accepts; ADR 0468 clause 3 says 768 KiB, which is 1 MiB of base64 before the message around it), cuts and the most it accepts, as ADR 0468 clause 3 says),
counted from 1, each carried base64-encoded in JSON. A caller joins the parts and checks the SHA-256. The bucket counted from 1, each carried base64-encoded in JSON. A caller joins the parts and checks the SHA-256. The bucket
(`s3-bucket`, from `minio`) is spoken to by the device process alone, from `store.json` (owner `brother-device`, mode (`s3-bucket`, from `minio`) is spoken to by the device process alone, from `store.json` (owner `brother-device`, mode
0600), with the S3 client mesh-mail uses; a scan is kept once as `<sha256>.pdf` and an upload as `uploads/<id>.<ext>`. 0600), with the S3 client mesh-mail uses; a scan is kept once as `<sha256>.pdf` and an upload as `uploads/<id>.<ext>`.
@@ -119,6 +119,12 @@ func (f *fakePrinter) host() string { return strings.TrimPrefix(f.URL, "https://
// print is the fingerprint of the certificate the server serves. // print is the fingerprint of the certificate the server serves.
func (f *fakePrinter) print() string { return Fingerprint(f.TLS.Certificates[0].Certificate[0]) } func (f *fakePrinter) print() string { return Fingerprint(f.TLS.Certificates[0].Certificate[0]) }
func (f *fakePrinter) connsNow() int {
f.mu.Lock()
defer f.mu.Unlock()
return f.conns
}
func (f *fakePrinter) loggedInNow() int { func (f *fakePrinter) loggedInNow() int {
f.mu.Lock() f.mu.Lock()
defer f.mu.Unlock() defer f.mu.Unlock()
+1 -2
View File
@@ -11,8 +11,7 @@ import (
const ( const (
// PartSize is how large the parts this module cuts are, and MaxPart the most raw bytes a part may hold; a part // PartSize is how large the parts this module cuts are, and MaxPart the most raw bytes a part may hold; a part
// of more is refused. They are one: 700 KiB, so that a part's base64 text (about 933 KB) and the message around // of more is refused. They are one: 700 KiB, so that a part's base64 text (about 933 KB) and the message around
// it stay under the bus's 1 MiB. (ADR 0468 clause 3 says at most 768 KiB, which is 1 MiB of base64 before the // it stay under the bus's 1 MiB. (ADR 0468 clause 3.)
// message around it, and so over the bus's limit.)
PartSize = 700 << 10 PartSize = 700 << 10
MaxPart = PartSize MaxPart = PartSize
// MostParts bounds how many parts one document has (a 100 MiB document is the most). // MostParts bounds how many parts one document has (a 100 MiB document is the most).
+9 -9
View File
@@ -119,8 +119,8 @@ func TestPrinterSettingsSaysWhichConfigIsUnsetAndQueuesNothing(t *testing.T) {
t.Errorf("%s: an ask was queued", c.name) t.Errorf("%s: an ask was queued", c.name)
} }
} }
if f.conns != 0 || len(f.requests) != 0 { if f.connsNow() != 0 || len(f.requests) != 0 {
t.Errorf("the printer was contacted: %d connections, %v", f.conns, f.requests) t.Errorf("the printer was contacted: %d connections, %v", f.connsNow(), f.requests)
} }
} }
@@ -141,8 +141,8 @@ func TestPrinterSettingsSaysTheSecretIsNotGivenAndContactsNothing(t *testing.T)
if _, err := r.run(nil); err == nil || !strings.Contains(err.Error(), "admin-password is not given") { if _, err := r.run(nil); err == nil || !strings.Contains(err.Error(), "admin-password is not given") {
t.Errorf("empty secret: error = %v", err) t.Errorf("empty secret: error = %v", err)
} }
if f.conns != 0 || len(f.requests) != 0 { if f.connsNow() != 0 || len(f.requests) != 0 {
t.Errorf("the printer was contacted: %d connections, %v", f.conns, f.requests) t.Errorf("the printer was contacted: %d connections, %v", f.connsNow(), f.requests)
} }
} }
@@ -162,8 +162,8 @@ func TestPrinterSettingsRefusesAPageOutsideTheSite(t *testing.T) {
if _, err := r.run(map[string]any{"page": 5}); err == nil { if _, err := r.run(map[string]any{"page": 5}); err == nil {
t.Errorf("a page that is no string was accepted") t.Errorf("a page that is no string was accepted")
} }
if r.bus.asks() != 0 || f.conns != 0 { if r.bus.asks() != 0 || f.connsNow() != 0 {
t.Errorf("%d asks queued, the printer contacted %d times", r.bus.asks(), f.conns) t.Errorf("%d asks queued, the printer contacted %d times", r.bus.asks(), f.connsNow())
} }
} }
@@ -193,14 +193,14 @@ func TestTheAdminWorkerSettlesEachAsk(t *testing.T) {
t.Errorf("an unreadable ask: action %v, want term", act) t.Errorf("an unreadable ask: action %v, want term", act)
} }
old, _ := json.Marshal(Ask{ID: "old", Op: OpSettings, Page: DefaultPage, At: fixedNow.Add(-StaleAfter - time.Second)}) old, _ := json.Marshal(Ask{ID: "old", Op: OpSettings, Page: DefaultPage, At: fixedNow.Add(-StaleAfter - time.Second)})
if act, _ := w.Handle(old, nil); act != actionAck || r.answers.get("old") != nil || f.conns != 0 { if act, _ := w.Handle(old, nil); act != actionAck || r.answers.get("old") != nil || f.connsNow() != 0 {
t.Errorf("a stale ask: action %v, answer %s, %d connections", act, r.answers.get("old"), f.conns) t.Errorf("a stale ask: action %v, answer %s, %d connections", act, r.answers.get("old"), f.connsNow())
} }
fresh, _ := json.Marshal(Ask{ID: "a1", Op: OpSettings, Page: DefaultPage, At: fixedNow}) fresh, _ := json.Marshal(Ask{ID: "a1", Op: OpSettings, Page: DefaultPage, At: fixedNow})
if act, _ := w.Handle(fresh, nil); act != actionAck || r.answers.get("a1") == nil { if act, _ := w.Handle(fresh, nil); act != actionAck || r.answers.get("a1") == nil {
t.Errorf("a fresh ask: action %v", act) t.Errorf("a fresh ask: action %v", act)
} }
conns := f.conns conns := f.connsNow()
if act, _ := w.Handle(fresh, nil); act != actionAck { if act, _ := w.Handle(fresh, nil); act != actionAck {
t.Errorf("an ask already answered: action %v, want ack", act) t.Errorf("an ask already answered: action %v, want ack", act)
} }