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() } }