mesh/delivery-group group feat/335-a-busy-container-is-replaced-when-idle rejected: its order contradicts itself: novox/mesh-catalog@190608193764, novox/mesh-c…
mesh/merge-gate out of date: judged against trunk 56d6313262e8, the trunk is now cbac703e817d; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk 56d6313262e8, the trunk is now cbac703e817d; judged again on a recheck or when it is merged
mesh/delivery superseded: a newer head of the same pull request
A merge into mesh-controller replaced every build agent and threw away the checks in flight (issue 594). The manifest's container busy is checked and sent only to an engine that reads it; a report's busy waits are kept, the gate starts at the report that says the container replaced, and the wait is a phase of the delivery time. mesh-builder busy drains the agent and answers while a build is in hand (novox/hq ADR 0335).
78 lines
2.3 KiB
Go
78 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
// `mesh-builder busy` answers 0 while a build is in hand and non-zero when idle, and after its first ask the
|
|
// agent takes no new build request (novox/hq ADR 0335 §5).
|
|
func TestBusyAnswersWhileABuildIsInHandAndDrainsTheAgent(t *testing.T) {
|
|
t.Setenv("TMPDIR", t.TempDir())
|
|
if err := undrained(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if drained() {
|
|
t.Fatal("an agent never asked is drained")
|
|
}
|
|
// A build is claimed and runs.
|
|
if !claim() {
|
|
t.Fatal("an agent never asked refused a build")
|
|
}
|
|
holding("novox/mesh-controller (check-280)")
|
|
said, err := busy()
|
|
if err != nil || !strings.Contains(said, "novox/mesh-controller (check-280)") {
|
|
t.Fatalf("an agent with a build in hand did not answer busy with what it holds: %q %v", said, err)
|
|
}
|
|
// From that ask on it takes nothing new: the fetch is not made, and one fetched is handed back.
|
|
if !drained() {
|
|
t.Fatal("the ask did not drain the agent")
|
|
}
|
|
if claim() {
|
|
t.Fatal("a drained agent took a new build")
|
|
}
|
|
// The build in hand is still in hand after the refused claim, and busy goes on saying so.
|
|
if _, err := busy(); err != nil {
|
|
t.Fatalf("a refused claim ended the build in hand: %v", err)
|
|
}
|
|
// It ends: idle, and still drained.
|
|
released()
|
|
if _, err := busy(); err == nil {
|
|
t.Fatal("an agent with nothing in hand answered busy")
|
|
}
|
|
if claim() {
|
|
t.Fatal("a drained agent took a build after its last one ended")
|
|
}
|
|
// Started again, it is asked afresh.
|
|
if err := undrained(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if drained() || !claim() {
|
|
t.Fatal("a holder started again is still drained")
|
|
}
|
|
released()
|
|
}
|
|
|
|
// An ask racing a fetch sees the build in hand, or the agent sees the drain and hands the request back: never
|
|
// neither, which would replace the container under a build just taken.
|
|
func TestAnAskRacingAFetchNeverMissesTheBuild(t *testing.T) {
|
|
t.Setenv("TMPDIR", t.TempDir())
|
|
for i := 0; i < 200; i++ {
|
|
if err := undrained(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var claimed bool
|
|
var askErr error
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
go func() { defer wg.Done(); claimed = claim() }()
|
|
go func() { defer wg.Done(); _, askErr = busy() }()
|
|
wg.Wait()
|
|
if claimed && askErr != nil {
|
|
t.Fatalf("round %d: the agent took a build and the ask said idle", i)
|
|
}
|
|
released()
|
|
}
|
|
}
|