Review of 082: a store killed mid-conversation is an outage and a wrong password is not; one report holds the queue at most two minutes, then is let go loudly; shutdown does not wait out the pause

This commit is contained in:
2026-09-22 13:34:04 +02:00
parent 047830a6b5
commit 3fd0c37d22
4 changed files with 182 additions and 32 deletions
+46 -3
View File
@@ -7,6 +7,7 @@ import (
"io"
"log"
"testing"
"time"
amqp "github.com/rabbitmq/amqp091-go"
)
@@ -40,22 +41,64 @@ func TestAReportTheStoreCouldNotTakeIsKeptAndOneItRefusedIsNot(t *testing.T) {
notNow := &saidTo{}
s := &Server{listener: heardWith{err: errors.Join(ErrTryAgain, errors.New("starting up"))}, log: quiet, again: 1}
s.handleReport(aReport(t, notNow))
s.handleReport(context.Background(), aReport(t, notNow))
if notNow.acked || !notNow.nacked || !notNow.requeued {
t.Fatalf("a report the store could not take yet was not handed back to be asked again: %+v", notNow)
}
refused := &saidTo{}
s = &Server{listener: heardWith{err: errors.New("a report named no node")}, log: quiet, again: 1}
s.handleReport(aReport(t, refused))
s.handleReport(context.Background(), aReport(t, refused))
if !refused.acked || refused.nacked {
t.Fatalf("a report the store answered no to was not acknowledged, so it would spin: %+v", refused)
}
recorded := &saidTo{}
s = &Server{listener: heardWith{}, log: quiet}
s.handleReport(aReport(t, recorded))
s.handleReport(context.Background(), aReport(t, recorded))
if !recorded.acked || recorded.nacked {
t.Fatalf("a recorded report was not acknowledged: %+v", recorded)
}
}
// A store that has not come back within the bound is not restarting: the report is let go, loudly,
// rather than holding every enrolment and report behind it for ever (novox/hq issue 082, review).
func TestAReportIsLetGoOnceTheStoreHasBeenGoneTooLong(t *testing.T) {
quiet := log.New(io.Discard, "", 0)
s := &Server{listener: heardWith{err: errors.Join(ErrTryAgain, errors.New("connection refused"))},
log: quiet, again: 1, giveUp: time.Millisecond}
first := &saidTo{}
s.handleReport(context.Background(), aReport(t, first))
if !first.requeued {
t.Fatalf("the first failure was not handed back: %+v", first)
}
time.Sleep(5 * time.Millisecond)
later := &saidTo{}
s.handleReport(context.Background(), aReport(t, later))
if !later.acked || later.nacked {
t.Fatalf("a report past the bound was not let go, so it would hold the queue for ever: %+v", later)
}
// Let go, and forgotten: the same report arriving fresh starts a new clock.
again := &saidTo{}
s.handleReport(context.Background(), aReport(t, again))
if !again.requeued {
t.Fatalf("a report let go was not forgotten, so its next arrival is given no chance: %+v", again)
}
}
// Shutting down does not wait out the pause.
func TestAReportBeingTriedAgainDoesNotHoldUpShutdown(t *testing.T) {
quiet := log.New(io.Discard, "", 0)
s := &Server{listener: heardWith{err: errors.Join(ErrTryAgain, errors.New("starting up"))},
log: quiet, again: time.Hour}
ctx, cancel := context.WithCancel(context.Background())
cancel()
done := make(chan struct{})
go func() { s.handleReport(ctx, aReport(t, &saidTo{})); close(done) }()
select {
case <-done:
case <-time.After(5 * time.Second):
t.Fatal("a cancelled context still waited out the pause")
}
}