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") } }