Upload files to "tests/dispatcher"

This commit is contained in:
2026-07-03 02:56:22 +00:00
parent 6e580ddf8b
commit 96f7780dbb
+114
View File
@@ -0,0 +1,114 @@
import { describe, expect, mock, test } from "bun:test";
import { Dispatcher } from "../../src/dispatcher/dispatcher";
import type { ProviderResult } from "../../src/providers/types";
import type { Sender } from "../../src/sender/base";
import type { EncryptedPackage, SenderName } from "../../src/sender/types";
function makeFakeSender(
name: SenderName,
opts: { healthy?: boolean; sendThrows?: boolean } = {},
): Sender {
const createEnvelope = mock().mockResolvedValue({
envelope: "encrypted-data",
key: "encrypted-key",
} as EncryptedPackage);
const healthy = mock().mockResolvedValue(opts.healthy ?? true);
const send = opts.sendThrows
? mock().mockRejectedValue(new Error(`${name} send failed`))
: mock().mockResolvedValue(undefined);
return {
name,
destination: { repo: "test-repo", token: "fake" },
createEnvelope,
healthy,
send,
} as unknown as Sender;
}
function makeBatch(count = 3): ProviderResult[] {
return Array.from({ length: count }, (_, i) => ({
provider: "filesystem",
service: `test-${i}`,
success: true,
size: 100,
}));
}
describe("Dispatcher", () => {
test("does not throw when no senders (handled gracefully)", () => {
expect(() => new Dispatcher({ senders: [] })).not.toThrow();
});
test("does not throw for dryRun with no senders", () => {
expect(() => new Dispatcher({ senders: [], dryRun: true })).not.toThrow();
});
test("filters null senders", () => {
const s1 = makeFakeSender("github");
const dispatcher = new Dispatcher({ senders: [null, s1] });
expect(dispatcher).toBeDefined();
});
test("dispatches to first healthy sender", async () => {
const s1 = makeFakeSender("domain");
const s2 = makeFakeSender("github");
const dispatcher = new Dispatcher({ senders: [s1, s2] });
await dispatcher.dispatch(makeBatch());
expect(s1.healthy).toHaveBeenCalled();
expect(s1.send).toHaveBeenCalled();
expect(s2.send).not.toHaveBeenCalled();
});
test("falls back when first sender is unhealthy", async () => {
const s1 = makeFakeSender("domain", { healthy: false });
const s2 = makeFakeSender("github");
const dispatcher = new Dispatcher({ senders: [s1, s2] });
await dispatcher.dispatch(makeBatch());
expect(s1.send).not.toHaveBeenCalled();
expect(s2.send).toHaveBeenCalled();
});
test("falls back when sender throws on send", async () => {
const s1 = makeFakeSender("domain", { sendThrows: true });
const s2 = makeFakeSender("github");
const dispatcher = new Dispatcher({ senders: [s1, s2] });
await dispatcher.dispatch(makeBatch());
expect(s1.send).toHaveBeenCalled();
expect(s2.send).toHaveBeenCalled();
});
test("tries all senders when none succeed", async () => {
const s1 = makeFakeSender("domain", { sendThrows: true, healthy: false });
const s2 = makeFakeSender("github", { sendThrows: true });
const dispatcher = new Dispatcher({ senders: [s1, s2] });
await expect(dispatcher.dispatch(makeBatch())).resolves.toBeUndefined();
});
test("skips preflight when preflight is false", async () => {
const s1 = makeFakeSender("domain");
const dispatcher = new Dispatcher({ senders: [s1], preflight: false });
await dispatcher.dispatch(makeBatch());
expect(s1.healthy).not.toHaveBeenCalled();
expect(s1.send).toHaveBeenCalled();
});
test("empty batch returns immediately", async () => {
const s1 = makeFakeSender("domain");
const dispatcher = new Dispatcher({ senders: [s1] });
await dispatcher.dispatch([]);
expect(s1.healthy).not.toHaveBeenCalled();
});
});