Files
2026-07-13 13:32:57 +08:00

88 lines
3.2 KiB
TypeScript

import { redisTest } from "@internal/testcontainers";
import { MollifierBuffer } from "@trigger.dev/redis-worker";
import { describe, expect, vi } from "vitest";
import { createRealTripEvaluator } from "~/v3/mollifier/mollifierTripEvaluator.server";
vi.setConfig({ testTimeout: 30_000 });
// Use a real MollifierBuffer backed by a Redis testcontainer — repo policy
// is no mocks for Redis. Per-test envIds keep keys disjoint without explicit
// cleanup. We close() the buffer in a finally to release the client.
const inputs = { envId: "env_a", orgId: "org_1", taskId: "t1" } as const;
describe("createRealTripEvaluator", () => {
redisTest(
"returns divert=false when the sliding window stays under threshold",
async ({ redisOptions }) => {
const buffer = new MollifierBuffer({ redisOptions });
try {
const evaluator = createRealTripEvaluator({
getBuffer: () => buffer,
options: () => ({ windowMs: 1000, threshold: 100, holdMs: 500 }),
});
const decision = await evaluator({ ...inputs, envId: "env_under" });
expect(decision).toEqual({ divert: false });
} finally {
await buffer.close();
}
}
);
redisTest(
"returns divert=true with reason per_env_rate once the window trips",
async ({ redisOptions }) => {
const buffer = new MollifierBuffer({ redisOptions });
try {
// threshold=2 → the 3rd call within windowMs is the first that trips.
const options = { windowMs: 5000, threshold: 2, holdMs: 5000 } as const;
const evaluator = createRealTripEvaluator({
getBuffer: () => buffer,
options: () => options,
});
const envId = "env_trip";
await evaluator({ ...inputs, envId });
await evaluator({ ...inputs, envId });
const decision = await evaluator({ ...inputs, envId });
expect(decision.divert).toBe(true);
if (decision.divert) {
expect(decision.reason).toBe("per_env_rate");
expect(decision.threshold).toBe(options.threshold);
expect(decision.windowMs).toBe(options.windowMs);
expect(decision.holdMs).toBe(options.holdMs);
expect(decision.count).toBeGreaterThan(options.threshold);
}
} finally {
await buffer.close();
}
}
);
redisTest("returns divert=false when getBuffer returns null (fail-open)", async () => {
const evaluator = createRealTripEvaluator({
getBuffer: () => null,
options: () => ({ windowMs: 200, threshold: 100, holdMs: 500 }),
});
const decision = await evaluator(inputs);
expect(decision).toEqual({ divert: false });
});
redisTest("returns divert=false when buffer throws (fail-open)", async ({ redisOptions }) => {
const buffer = new MollifierBuffer({ redisOptions });
// Closing the client up front means evaluateTrip will throw on the first
// Redis command — a real failure mode, not a stub.
await buffer.close();
const evaluator = createRealTripEvaluator({
getBuffer: () => buffer,
options: () => ({ windowMs: 200, threshold: 100, holdMs: 500 }),
});
const decision = await evaluator(inputs);
expect(decision).toEqual({ divert: false });
});
});