Files
doormile_backend/internal/assignment/retrywindow_test.go

79 lines
2.5 KiB
Go

package assignment
import (
"encoding/json"
"testing"
"time"
)
func TestRetryWindowDefaultAndOverride(t *testing.T) {
t.Setenv("ASSIGNMENT_RETRY_WINDOW_MINUTES", "")
if got := retryWindow(); got != 120*time.Minute {
t.Fatalf("default window = %v, want 2h", got)
}
t.Setenv("ASSIGNMENT_RETRY_WINDOW_MINUTES", "45")
if got := retryWindow(); got != 45*time.Minute {
t.Fatalf("override window = %v, want 45m", got)
}
// 0 restores the old single-round behaviour.
t.Setenv("ASSIGNMENT_RETRY_WINDOW_MINUTES", "0")
if got := retryWindow(); got != 0 {
t.Fatalf("zero window = %v, want 0", got)
}
// A typo must not disable retries.
for _, bad := range []string{"abc", "-5", "1.5"} {
t.Setenv("ASSIGNMENT_RETRY_WINDOW_MINUTES", bad)
if got := retryWindow(); got != 120*time.Minute {
t.Fatalf("bad value %q gave %v, want the 2h default", bad, got)
}
}
}
func TestWithinRetryWindow(t *testing.T) {
t.Setenv("ASSIGNMENT_RETRY_WINDOW_MINUTES", "120")
now := time.Now()
if !withinRetryWindow(now.Add(-10*time.Minute).Unix(), now) {
t.Fatal("10 minutes in should still retry")
}
if withinRetryWindow(now.Add(-121*time.Minute).Unix(), now) {
t.Fatal("121 minutes in should give up")
}
// Messages queued before this change carry no timestamp; they get a
// window starting now rather than being dropped.
if !withinRetryWindow(0, now) {
t.Fatal("a message without first_queued_at should retry")
}
t.Setenv("ASSIGNMENT_RETRY_WINDOW_MINUTES", "0")
if withinRetryWindow(now.Add(-time.Second).Unix(), now) {
t.Fatal("window 0 should never start another round")
}
}
// Messages already on the ASSIGNMENTS stream when this ships were published
// with only booking_id and kind. They must still decode and act as round 1.
func TestAssignmentRequestDecodesOldPayload(t *testing.T) {
var req assignmentRequest
if err := json.Unmarshal([]byte(`{"booking_id":664517,"kind":"express"}`), &req); err != nil {
t.Fatalf("old payload failed to decode: %v", err)
}
if req.BookingID != 664517 || req.Kind != kindExpress {
t.Fatalf("decoded %+v", req)
}
if req.Round != 0 || req.FirstQueuedAt != 0 || req.NotBefore != 0 {
t.Fatalf("new fields should be zero on an old payload, got %+v", req)
}
}
// requeueNextRound must refuse (return false) rather than panic when
// JetStream is not connected, so the caller falls back to giving up cleanly.
func TestRequeueWithoutJetStream(t *testing.T) {
if requeueNextRound(assignmentRequest{BookingID: 1, Kind: kindExpress, Round: 1}, time.Now()) {
t.Fatal("requeue should report false with no JetStream connection")
}
}