Files
GCCWechatBot/tests/worker.test.ts
T

170 lines
4.9 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import type { AppConfig } from "../src/config.js";
import { signBody } from "../src/signature.js";
import { handleRequest } from "../src/worker.js";
import { testEnv } from "./helpers.js";
test("health check returns ok", async () => {
const response = await handleRequest(new Request("https://worker.test/healthz"), testEnv());
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), { ok: true });
});
test("accepts a valid push webhook and sends one WeCom message", async () => {
const sent: string[] = [];
const response = await postGitHubEvent("push", "delivery-1", {
ref: "refs/heads/main",
repository: { full_name: "acme/app", owner: { login: "acme" } },
pusher: { name: "alice" },
commits: []
}, async (_config, message) => {
sent.push(message);
});
assert.equal(response.status, 202);
assert.deepEqual(await response.json(), { sent: true });
assert.equal(sent.length, 1);
assert.match(sent[0] ?? "", /📁 acme\/app/);
});
test("rejects invalid signatures", async () => {
const body = JSON.stringify({ repository: { full_name: "acme/app" } });
const response = await handleRequest(
new Request("https://worker.test/github/webhook", {
method: "POST",
headers: {
"content-type": "application/json",
"x-github-event": "push",
"x-github-delivery": "bad-sig",
"x-hub-signature-256": "sha256=bad"
},
body
}),
testEnv(),
undefined,
async () => {
throw new Error("should not send");
}
);
assert.equal(response.status, 401);
});
test("deduplicates GitHub delivery ids", async () => {
const sent: string[] = [];
const payload = {
ref: "refs/heads/main",
repository: { full_name: "acme/app", owner: { login: "acme" } },
commits: []
};
const first = await postGitHubEvent("push", "same-delivery", payload, async (_config, message) => {
sent.push(message);
});
const second = await postGitHubEvent("push", "same-delivery", payload, async (_config, message) => {
sent.push(message);
});
assert.equal(first.status, 202);
assert.equal(second.status, 202);
assert.deepEqual(await second.json(), { duplicate: true });
assert.equal(sent.length, 1);
});
test("ignores events outside the allowed organization list", async () => {
const sent: string[] = [];
const response = await postGitHubEvent(
"push",
"wrong-org",
{
ref: "refs/heads/main",
repository: { full_name: "other/app", owner: { login: "other" } },
commits: []
},
async (_config, message) => {
sent.push(message);
},
{ ALLOWED_ORGS: "acme" }
);
assert.equal(response.status, 202);
assert.equal((await response.json() as { ignored: boolean }).ignored, true);
assert.equal(sent.length, 0);
});
test("accepts Gitea event headers on the Gitea webhook path", async () => {
const sent: string[] = [];
const payload = {
ref: "refs/heads/main",
repository: { full_name: "gcc/app", owner: { username: "gcc" } },
pusher: { username: "alice" },
commits: []
};
const body = JSON.stringify(payload);
const signature = await signBody("test-secret", new TextEncoder().encode(body));
const response = await handleRequest(
new Request("https://worker.test/gitea/webhook", {
method: "POST",
headers: {
"content-type": "application/json",
"x-gitea-event": "push",
"x-gitea-delivery": "gitea-delivery-1",
"x-gitea-signature": signature.slice("sha256=".length)
},
body
}),
testEnv(),
undefined,
async (_config, message) => {
sent.push(message);
}
);
assert.equal(response.status, 202);
assert.deepEqual(await response.json(), { sent: true });
assert.equal(sent.length, 1);
assert.match(sent[0] ?? "", /📁 gcc\/app/);
});
test("returns 500 when sending to WeCom fails so GitHub can retry", async () => {
const response = await postGitHubEvent("push", "send-fails", {
ref: "refs/heads/main",
repository: { full_name: "acme/app", owner: { login: "acme" } },
commits: []
}, async () => {
throw new Error("WeCom failed");
});
assert.equal(response.status, 500);
});
async function postGitHubEvent(
eventName: string,
deliveryId: string,
payload: Record<string, unknown>,
sender: (config: AppConfig, message: string) => Promise<unknown>,
envOverrides: Record<string, unknown> = {}
) {
const body = JSON.stringify(payload);
const signature = await signBody("test-secret", new TextEncoder().encode(body));
return handleRequest(
new Request("https://worker.test/github/webhook", {
method: "POST",
headers: {
"content-type": "application/json",
"x-github-event": eventName,
"x-github-delivery": deliveryId,
"x-hub-signature-256": signature
},
body
}),
testEnv(envOverrides),
undefined,
sender
);
}