Keep working out the home page cards after startup (closes #211)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
Server.Start ran the loop that works out the home page's cards on the context it was given. fx ends that context once start-up is done, so the cards were worked out once and never again. The loop now runs on a context that only Stop ends, as the other background parts do. Stop waits for the loop to return, until its own context ends, before it stops the HTTP server. A new test starts a server in a synctest bubble and ends its context at once. On the bubble's fake clock, the cards must be worked out again a minute later, and not after Stop. Model: opus-5-5
This commit was merged in pull request #212.
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
"time"
|
||||
|
||||
"git.eeqj.de/sneak/routewatch/internal/database"
|
||||
@@ -341,6 +342,66 @@ func TestStartedServerWorksOutTheCards(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestStartedServerWorksOutTheCardsUntilStop starts a server with a context
|
||||
// that ends as soon as Start returns. It runs in a synctest bubble, whose clock
|
||||
// is fake: time.Sleep there moves the clock on and returns at once. The server
|
||||
// must work the cards out again a minute later, and no more after Stop. Each
|
||||
// time it works them out, it keeps a new copy. Before the fix the end of
|
||||
// Start's context stopped the goroutine that works them out.
|
||||
func TestStartedServerWorksOutTheCardsUntilStop(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// The server is made outside the bubble. The streamer's metrics start a
|
||||
// goroutine that never returns, and a bubble waits for each of its
|
||||
// goroutines to return.
|
||||
s := newServerWithTable(t, newCardsTable())
|
||||
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
|
||||
err := s.Start(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Start: %v", err)
|
||||
}
|
||||
|
||||
cancel()
|
||||
|
||||
// The bubble's clock moves only while each of its goroutines waits
|
||||
// on the bubble, and the goroutine that serves HTTP waits on the
|
||||
// network. The test sends no request, so it closes the HTTP server.
|
||||
_ = s.srv.Close()
|
||||
|
||||
synctest.Wait()
|
||||
|
||||
started := s.cards.Load()
|
||||
if started == nil {
|
||||
t.Fatal("the server did not work out the cards when it started")
|
||||
}
|
||||
|
||||
time.Sleep(homeCardsRefreshInterval)
|
||||
synctest.Wait()
|
||||
|
||||
if s.cards.Load() == started {
|
||||
t.Error("the server did not work out the cards again a minute " +
|
||||
"after its start context ended")
|
||||
}
|
||||
|
||||
err = s.Stop(t.Context())
|
||||
if err != nil {
|
||||
t.Fatalf("Stop: %v", err)
|
||||
}
|
||||
|
||||
stopped := s.cards.Load()
|
||||
|
||||
time.Sleep(homeCardsRefreshInterval)
|
||||
synctest.Wait()
|
||||
|
||||
if s.cards.Load() != stopped {
|
||||
t.Error("the server worked out the cards again after Stop")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// waitUntil fails the test unless done reports true within maxWait.
|
||||
func waitUntil(t *testing.T, maxWait time.Duration, done func() bool) {
|
||||
t.Helper()
|
||||
|
||||
Reference in New Issue
Block a user