1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
import { beforeEach, describe, expect, it } from "bun:test";
import { fireWebhooks } from "../routes/webhooks";
interface FakeHook {
id: string;
secret: string;
isActive: boolean;
events: string;
}
let _hooks: FakeHook[] = [];
let _selectShouldThrow = false;
let _enqueueCalls: Array<{ webhookId: string; event: string; payload: unknown }> = [];
let _drainCalls = 0;
const fakeDeps = {
loadHooks: async (_repositoryId: string) => {
if (_selectShouldThrow) throw new Error("db unavailable");
return _hooks;
},
enqueueWebhookDelivery: async (opts: any) => {
_enqueueCalls.push(opts);
return "delivery-id-1";
},
drainPendingDeliveries: async () => {
_drainCalls++;
},
} as any;
beforeEach(() => {
_hooks = [];
_selectShouldThrow = false;
_enqueueCalls = [];
_drainCalls = 0;
});
describe("fireWebhooks", () => {
it("enqueues a delivery for an active hook subscribed to the event", async () => {
_hooks = [{ id: "hook-1", secret: "s", isActive: true, events: "push,pr" }];
await fireWebhooks("repo-1", "push", { branch: "main" }, fakeDeps);
expect(_enqueueCalls).toHaveLength(1);
expect(_enqueueCalls[0]).toMatchObject({ webhookId: "hook-1", event: "push" });
expect(_enqueueCalls[0]!.payload).toEqual({ branch: "main" });
});
it("skips a hook not subscribed to the fired event", async () => {
_hooks = [{ id: "hook-1", secret: "s", isActive: true, events: "issue,star" }];
await fireWebhooks("repo-1", "push", { branch: "main" }, fakeDeps);
expect(_enqueueCalls).toHaveLength(0);
});
it("skips an inactive hook even if subscribed to the event", async () => {
_hooks = [{ id: "hook-1", secret: "s", isActive: false, events: "push" }];
await fireWebhooks("repo-1", "push", {}, fakeDeps);
expect(_enqueueCalls).toHaveLength(0);
});
it("enqueues one delivery per matching hook when several are configured", async () => {
_hooks = [
{ id: "hook-1", secret: "s", isActive: true, events: "pr" },
{ id: "hook-2", secret: "s", isActive: true, events: "push,pr" },
{ id: "hook-3", secret: "s", isActive: true, events: "star" },
];
await fireWebhooks("repo-1", "pr", { action: "opened", number: 1 }, fakeDeps);
expect(_enqueueCalls).toHaveLength(2);
expect(_enqueueCalls.map((c) => c.webhookId).sort()).toEqual(["hook-1", "hook-2"]);
});
it("kicks the delivery worker only when something was actually enqueued", async () => {
_hooks = [{ id: "hook-1", secret: "s", isActive: true, events: "push" }];
await fireWebhooks("repo-1", "push", {}, fakeDeps);
expect(_drainCalls).toBe(1);
_drainCalls = 0;
_hooks = [{ id: "hook-1", secret: "s", isActive: true, events: "issue" }];
await fireWebhooks("repo-1", "push", {}, fakeDeps);
expect(_drainCalls).toBe(0);
});
it("never throws when the hook lookup fails — fail-open, matches logActivity()'s contract", async () => {
_selectShouldThrow = true;
await expect(fireWebhooks("repo-1", "push", {}, fakeDeps)).resolves.toBeUndefined();
expect(_enqueueCalls).toHaveLength(0);
});
it("real default deps resolve without throwing (production wiring sanity check)", async () => {
await expect(
fireWebhooks("00000000-0000-0000-0000-000000000000", "push", {})
).resolves.toBeUndefined();
});
});
|