Test shutdown exit codes, Sentry startup failure and the processing wait (closes #86)
check / check (push) Waiting to run
check / check (push) Waiting to run
These tests fail until the change that follows: runApp and WaitForProcessing do not exist yet, the server has no shutdowner, and a Sentry DSN that cannot be used exits the process from a goroutine instead of failing the server's start hook. runApp must return the exit code a shutdown request carries, 0 without one, and 1 when the app fails to start or stop. A listen error must ask fx to shut down with exit code 1. WaitForProcessing must wait for an image being processed and report it when its context ends first. Model: opus-5-5
This commit is contained in:
@@ -300,3 +300,69 @@ func TestProcessReleasesSlotOnError(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWaitForProcessing holds a processing slot with a Process call that
|
||||
// cannot finish reading its input. WaitForProcessing must report that image
|
||||
// when its context ends first, wait for it otherwise, return 0 once it has
|
||||
// finished, and give back the slots it took while waiting.
|
||||
func TestWaitForProcessing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
proc := New(Params{MaxConcurrentProcessing: 2})
|
||||
|
||||
gate := make(chan struct{})
|
||||
entered := make(chan struct{}, 1)
|
||||
results := make(chan error, 1)
|
||||
|
||||
openGate := sync.OnceFunc(func() { close(gate) })
|
||||
t.Cleanup(openGate)
|
||||
|
||||
processInBackground(proc, &gatedReader{
|
||||
data: bytes.NewReader(createTestJPEG(t, 10, 10)), gate: gate,
|
||||
entered: entered, counter: &readingCounter{},
|
||||
}, results)
|
||||
waitForEntries(t, entered, 1)
|
||||
|
||||
ctx, cancel := context.WithTimeout(t.Context(), 100*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
stillProcessing := proc.WaitForProcessing(ctx)
|
||||
t.Logf("WaitForProcessing() after its context ended: %d", stillProcessing)
|
||||
|
||||
if stillProcessing != 1 {
|
||||
t.Errorf("WaitForProcessing() after its context ended = %d, want 1",
|
||||
stillProcessing)
|
||||
}
|
||||
|
||||
waited := make(chan int, 1)
|
||||
|
||||
go func() { waited <- proc.WaitForProcessing(t.Context()) }()
|
||||
|
||||
select {
|
||||
case got := <-waited:
|
||||
t.Fatalf("WaitForProcessing() = %d while an image was being processed",
|
||||
got)
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
}
|
||||
|
||||
openGate()
|
||||
|
||||
err := <-results
|
||||
if err != nil {
|
||||
t.Errorf("Process() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case got := <-waited:
|
||||
if got != 0 {
|
||||
t.Errorf("WaitForProcessing() once processing finished = %d, want 0",
|
||||
got)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("WaitForProcessing() did not return once processing finished")
|
||||
}
|
||||
|
||||
if held := len(proc.processingSemaphore); held != 0 {
|
||||
t.Errorf("%d slots still held after WaitForProcessing() returned", held)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user