package link import ( "context" "encoding/json" "errors" "io" "log" "testing" amqp "github.com/rabbitmq/amqp091-go" ) type saidTo struct{ acked, nacked, requeued bool } func (a *saidTo) Ack(uint64, bool) error { a.acked = true; return nil } func (a *saidTo) Nack(_ uint64, _ bool, requeue bool) error { a.nacked, a.requeued = true, requeue return nil } func (a *saidTo) Reject(uint64, bool) error { return nil } type heardWith struct{ err error } func (h heardWith) Heard(context.Context, Report) error { return h.err } func aReport(t *testing.T, to *saidTo) amqp.Delivery { t.Helper() body, err := json.Marshal(Report{Node: "anchor", Applied: []string{"store"}}) if err != nil { t.Fatal(err) } return amqp.Delivery{Acknowledger: to, RoutingKey: KeyReport, Body: body} } // A report the store could not take right now goes back to the broker to be asked again; one the // store answered no to is acknowledged, or it would come back for ever (novox/hq issue 082). func TestAReportTheStoreCouldNotTakeIsKeptAndOneItRefusedIsNot(t *testing.T) { quiet := log.New(io.Discard, "", 0) notNow := &saidTo{} s := &Server{listener: heardWith{err: errors.Join(ErrTryAgain, errors.New("starting up"))}, log: quiet, again: 1} s.handleReport(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)) 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)) if !recorded.acked || recorded.nacked { t.Fatalf("a recorded report was not acknowledged: %+v", recorded) } }