diff --git a/internal/cron/jitter.go b/internal/cron/jitter.go index 04f5e8c7..92b45366 100644 --- a/internal/cron/jitter.go +++ b/internal/cron/jitter.go @@ -46,8 +46,8 @@ func DefaultJitterConfig() JitterConfig { // The returned duration is in [cfg.MinSec, cfg.MaxSec]. Minute-mark avoidance // is applied separately at fire time via avoidMinuteMarks. func computeJitter(cfg JitterConfig, jobID, schedule string) time.Duration { - // Sanity: if disabled or range is zero, return zero. - if !cfg.Enabled || cfg.MinSec >= cfg.MaxSec { + // Sanity: if disabled or the range is invalid (min greater than max, or negative min), return zero. + if !cfg.Enabled || cfg.MinSec > cfg.MaxSec || cfg.MinSec < 0 { return 0 } diff --git a/internal/cron/jitter_test.go b/internal/cron/jitter_test.go index 41a33a47..8369993e 100644 --- a/internal/cron/jitter_test.go +++ b/internal/cron/jitter_test.go @@ -56,15 +56,27 @@ func TestComputeJitter_Disabled(t *testing.T) { } } -func TestComputeJitter_ZeroRange(t *testing.T) { +func TestComputeJitter_EqualBounds(t *testing.T) { cfg := DefaultJitterConfig() cfg.MinSec = 300 cfg.MaxSec = 300 - // When MinSec >= MaxSec, should return 0 (sanity check). + // When MinSec == MaxSec, should return exactly MinSec seconds. + jitter := computeJitter(cfg, "job-1", "*/5 * * * *") + if jitter != time.Duration(300)*time.Second { + t.Fatalf("expected jitter of 300s when MinSec == MaxSec, got %v", jitter) + } +} + +func TestComputeJitter_MinGreaterThanMax(t *testing.T) { + cfg := DefaultJitterConfig() + cfg.MinSec = 400 + cfg.MaxSec = 300 + + // When MinSec > MaxSec, should return 0. jitter := computeJitter(cfg, "job-1", "*/5 * * * *") if jitter != 0 { - t.Fatalf("expected zero jitter when MinSec >= MaxSec, got %v", jitter) + t.Fatalf("expected zero jitter when MinSec > MaxSec, got %v", jitter) } }