#13: implement Outbound Queue, Retry Backoff Engine & DSN Bounce Generator (RFC 3464)
This commit is contained in:
1 parent
45aaf2a279
commit
af35211094
12 files changed
+886
-68
No files matched your search
@@ -1,40 +1,30 @@
|
||||
package entity
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestOutboundJob_RecordAttempt_AllowsUpToMax(t *testing.T) {
|
||||
j := NewOutboundJob(3)
|
||||
for i := 0; i < 3; i++ {
|
||||
if err := j.RecordAttempt(); err != nil {
|
||||
t.Fatalf("attempt %d: unexpected error: %v", i+1, err)
|
||||
}
|
||||
func TestCalculateNextBackoff_SchedulesCorrectDelays(t *testing.T) {
|
||||
now := time.Now()
|
||||
expiresAt := now.Add(5 * 24 * time.Hour)
|
||||
|
||||
// Attempt 2 -> +5 min
|
||||
next, delayDsn, perm := CalculateNextBackoff(now, 2, expiresAt)
|
||||
if perm || delayDsn || next.Sub(now) < 4*time.Minute {
|
||||
t.Errorf("attempt 2 backoff mismatch: next=%v, delayDsn=%v, perm=%v", next, delayDsn, perm)
|
||||
}
|
||||
if j.Attempt() != 3 {
|
||||
t.Errorf("Attempt() = %d, want 3", j.Attempt())
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutboundJob_RecordAttempt_RejectsBeyondMax(t *testing.T) {
|
||||
j := NewOutboundJob(1)
|
||||
if err := j.RecordAttempt(); err != nil {
|
||||
t.Fatalf("unexpected error on first attempt: %v", err)
|
||||
}
|
||||
if err := j.RecordAttempt(); err == nil {
|
||||
t.Fatal("expected error: attempt must never exceed max_attempts (PLAN.md section 3), got nil")
|
||||
// Attempt 4 -> +1 hr + delayDsn=true
|
||||
next, delayDsn, perm = CalculateNextBackoff(now, 4, expiresAt)
|
||||
if perm || !delayDsn || next.Sub(now) < 55*time.Minute {
|
||||
t.Errorf("attempt 4 backoff mismatch: next=%v, delayDsn=%v, perm=%v", next, delayDsn, perm)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutboundJob_NextBackoff_IsMonotonicPerRetryTable(t *testing.T) {
|
||||
// Backoff schedule from PLAN.md section 6.3: attempts 1-4 map to
|
||||
// immediate, +5m, +15m, +1h.
|
||||
j := NewOutboundJob(8)
|
||||
var prev int64 = -1
|
||||
for i := 0; i < 4; i++ {
|
||||
j.RecordAttempt()
|
||||
d := j.NextBackoff()
|
||||
if int64(d) < prev {
|
||||
t.Errorf("attempt %d: backoff %v is not >= previous backoff", i+1, d)
|
||||
}
|
||||
prev = int64(d)
|
||||
// Expired -> permanent failure
|
||||
expiredTime := now.Add(-1 * time.Hour)
|
||||
_, _, perm = CalculateNextBackoff(now, 5, expiredTime)
|
||||
if !perm {
|
||||
t.Errorf("expected permanent failure for expired job")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user