package server import ( "errors" "fmt" "testing" "time" "golang.org/x/crypto/acme" ) func TestCooldown(t *testing.T) { now := time.Now() c := newCooldown() c.now = func() time.Time { return now } for i := 0; i < 4; i++ { if d := c.failure(); d != 0 { t.Fatalf("failure %d paused for %v, want no pause", i+1, d) } } if d := c.failure(); d != time.Minute { t.Fatalf("fifth failure pause = %v, want 1m", d) } if d := c.remaining(); d != time.Minute { t.Fatalf("remaining = %v, want 1m", d) } if d := c.failure(); d != 2*time.Minute { t.Fatalf("sixth failure pause = %v, want 2m", d) } for i := 0; i < 20; i++ { c.failure() } if d := c.failure(); d != time.Hour { t.Fatalf("pause cap = %v, want 1h", d) } now = now.Add(2 * time.Hour) if d := c.remaining(); d != 0 { t.Fatalf("remaining after expiry = %v", d) } c.success() if c.failures != 0 { t.Fatalf("success left failures = %d", c.failures) } } func TestCAFailureClassification(t *testing.T) { cases := []struct { err error want bool }{ {errors.New("dns: create _acme-challenge: nope"), false}, {errors.New("acme: authorization for x is invalid"), false}, {errors.New("acme: authorize order: context deadline exceeded"), true}, {fmt.Errorf("acme: authorize order: %w", &acme.Error{StatusCode: 503}), true}, {fmt.Errorf("acme: authorize order: %w", &acme.Error{StatusCode: 429}), true}, } for _, c := range cases { if got := caFailure(c.err); got != c.want { t.Errorf("caFailure(%v) = %v, want %v", c.err, got, c.want) } } }