---------------------------------------------------------------------- P5 — Auto-disable ----------------------------------------------------------------------
(t *testing.T)
| 617 | // ---------------------------------------------------------------------- |
| 618 | |
| 619 | func TestWebhooksE2E_AutoDisableAfterFailures(t *testing.T) { |
| 620 | pool := testutil.TestDB(t) |
| 621 | ts := testutil.TestServer(t, pool, testutil.WithOutboundSMTP("127.0.0.1", 1025, "test.e2a.dev")) |
| 622 | receiver := testutil.SubscriberReceiver(t) |
| 623 | receiver.SetStatus("/dead", 503) |
| 624 | |
| 625 | _, _, agent := setupSubscriberOwner(t, ts, "wh-autodis", false) |
| 626 | wh := registerWebhook(t, ts, agent.UserID, receiver.Server.URL+"/dead", |
| 627 | []string{"email.sent"}, identity.WebhookFilters{}) |
| 628 | |
| 629 | // Seed 10 failed delivery rows directly. Going through real |
| 630 | // /send and exhausting retries would take longer than the test |
| 631 | // budget (5 attempts × backoff). The auto-disable janitor only |
| 632 | // reads the rows' final status; seeding them keeps the test |
| 633 | // deterministic. |
| 634 | ctx := context.Background() |
| 635 | for i := 0; i < 10; i++ { |
| 636 | _, err := pool.Exec(ctx, |
| 637 | `INSERT INTO webhook_subscriber_deliveries |
| 638 | (id, webhook_id, event_type, event_payload, status, attempts, max_attempts, last_error, last_status_code) |
| 639 | VALUES ($1, $2, 'email.sent', '{"event":"email.sent"}'::jsonb, 'failed', 5, 5, 'HTTP 503', 503)`, |
| 640 | "whd_seed_autodis_"+strconv.Itoa(i)+"_"+wh.ID, wh.ID, |
| 641 | ) |
| 642 | if err != nil { |
| 643 | t.Fatalf("seed failed delivery: %v", err) |
| 644 | } |
| 645 | } |
| 646 | |
| 647 | n, err := ts.Store.AutoDisableFailingWebhooks(ctx) |
| 648 | if err != nil { |
| 649 | t.Fatalf("AutoDisableFailingWebhooks: %v", err) |
| 650 | } |
| 651 | if n != 1 { |
| 652 | t.Errorf("disabled count = %d, want 1", n) |
| 653 | } |
| 654 | after, err := ts.Store.GetWebhookByID(ctx, wh.ID, agent.UserID) |
| 655 | if err != nil { |
| 656 | t.Fatalf("GetWebhookByID: %v", err) |
| 657 | } |
| 658 | if after.Enabled { |
| 659 | t.Errorf("webhook should be disabled after threshold failures") |
| 660 | } |
| 661 | if after.AutoDisabledAt == nil { |
| 662 | t.Errorf("auto_disabled_at not set") |
| 663 | } |
| 664 | } |
| 665 | |
| 666 | // summarize turns captured payloads into a debuggable one-line summary |
| 667 | // for failed assertions. Returning the full envelope blob would dwarf |
nothing calls this directly
no test coverage detected