105 lines
3.7 KiB
Go
105 lines
3.7 KiB
Go
package link
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"log"
|
|
"testing"
|
|
"time"
|
|
|
|
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(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(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(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")
|
|
}
|
|
}
|