Fix the try: guard shared test state with mutexes, pgxpool over one conn, a short batch gap for integration builds, unique+forced database drops (issues 1431, 1524, 1517)

This commit is contained in:
jochen
2026-10-21 01:11:48 +02:00
parent d61fe4e2da
commit 794de09c4d
7 changed files with 186 additions and 57 deletions
@@ -12,9 +12,47 @@ import (
"io"
"net/http"
"net/url"
"sync"
"testing"
)
// recordedArgs is a mutex-guarded holder: a stand-in's own closure (called from the player's readLoop
// goroutine, runtime_integration_test.go's handleBundleRequest) records what it was asked here, and the
// test (its own, main goroutine) reads it back safely afterward. The coordinator's own fix for issue 1523:
// the merge check's `go test -race` found this exact unsynchronized pattern — a bare variable written by
// one goroutine and read by another, with no memory synchronization the race detector can see (the two
// communicate only over a stdio pipe and an HTTP round trip, neither of which it tracks as ordinary Go
// synchronization).
type recordedArgs struct {
mu sync.Mutex
args map[string]any
set bool
}
func (r *recordedArgs) record(args map[string]any) {
r.mu.Lock()
r.args, r.set = args, true
r.mu.Unlock()
}
func (r *recordedArgs) clear() {
r.mu.Lock()
r.args, r.set = nil, false
r.mu.Unlock()
}
func (r *recordedArgs) get() map[string]any {
r.mu.Lock()
defer r.mu.Unlock()
return r.args
}
func (r *recordedArgs) wasSet() bool {
r.mu.Lock()
defer r.mu.Unlock()
return r.set
}
func TestAcceptanceMailCorrectionAndUndoReachTheStandIn(t *testing.T) {
mw := startMailWeb(t, acceptanceAccounts(), []string{"alice"})
mw.mailReading.Status = func(map[string]any) (any, error) {
@@ -33,13 +71,13 @@ func TestAcceptanceMailCorrectionAndUndoReachTheStandIn(t *testing.T) {
{"id": 9, "sender-name": "Bob", "subject": "fyi", "change": "mark: neither -> matters", "made": "2026-10-20T10:00:00Z"},
}}, nil
}
var correctArgs, undoArgs map[string]any
var correctArgs, undoArgs recordedArgs
mw.mailReading.Correct = func(args map[string]any) (any, error) {
correctArgs = args
correctArgs.record(args)
return map[string]any{"id": args["id"]}, nil
}
mw.mailReading.Undo = func(args map[string]any) (any, error) {
undoArgs = args
undoArgs.record(args)
return map[string]any{"undone": args["id"]}, nil
}
@@ -65,19 +103,19 @@ func TestAcceptanceMailCorrectionAndUndoReachTheStandIn(t *testing.T) {
if correctResp.StatusCode != http.StatusOK {
t.Fatalf("the correction: status %d: %s", correctResp.StatusCode, correctBody)
}
if correctArgs["id"] != float64(1) || correctArgs["mark"] != "matters" || correctArgs["group"] != "bills" {
t.Fatalf("mail-reading.correct was asked %v, want id 1, mark matters, group bills", correctArgs)
if got := correctArgs.get(); got["id"] != float64(1) || got["mark"] != "matters" || got["group"] != "bills" {
t.Fatalf("mail-reading.correct was asked %v, want id 1, mark matters, group bills", got)
}
// Without the token, the correction never reaches the stand-in (1523/AC1).
correctArgs = nil
correctArgs.clear()
noTokenResp := doForm(t, mw, "/mail-correct", url.Values{"id": {"1"}, "mark": {"neither"}}, cookie)
_ = noTokenResp.Body.Close()
if noTokenResp.StatusCode != http.StatusForbidden {
t.Fatalf("a correction with no token: status %d, want 403", noTokenResp.StatusCode)
}
if correctArgs != nil {
t.Fatalf("mail-reading.correct was asked %v with no token", correctArgs)
if correctArgs.wasSet() {
t.Fatalf("mail-reading.correct was asked %v with no token", correctArgs.get())
}
// 1523/AC2: an undo posted with the session's own token reaches the stand-in's Undo.
@@ -87,8 +125,8 @@ func TestAcceptanceMailCorrectionAndUndoReachTheStandIn(t *testing.T) {
if undoResp.StatusCode != http.StatusOK {
t.Fatalf("the undo: status %d: %s", undoResp.StatusCode, undoBody)
}
if undoArgs["id"] != float64(9) {
t.Fatalf("mail-reading.undo was asked %v, want id 9", undoArgs)
if got := undoArgs.get(); got["id"] != float64(9) {
t.Fatalf("mail-reading.undo was asked %v, want id 9", got)
}
// 1523/AC4: nothing of mail is read but through mail-store — this flow never asks mail-store.search or