mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 19:58:11 +00:00
feat: add drain tail to the payments
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import {
|
||||
DEFAULT_PAYMENT_DRAIN_MINUTES,
|
||||
paymentDrainMs,
|
||||
payWindowLapsed,
|
||||
} from "./booking-batch.constants";
|
||||
|
||||
/**
|
||||
* The drain tail is what keeps a pay window's LAST payment from being thrown
|
||||
* away: settlement is asynchronous (provider confirm → payment-api → outbox
|
||||
* relay), so a payment made in the window's final seconds lands after
|
||||
* `paymentDeadline`. Nothing may expire, no wagons may be resold and no window
|
||||
* cycle may conclude until the tail has passed.
|
||||
*/
|
||||
describe("payWindowLapsed — pay-window drain tail", () => {
|
||||
const deadline = new Date("2026-08-02T22:04:41Z");
|
||||
const at = (offsetMs: number) => deadline.getTime() + offsetMs;
|
||||
const MIN = 60_000;
|
||||
|
||||
afterEach(() => {
|
||||
delete process.env.FREIGHT_PAYMENT_DRAIN_MINUTES;
|
||||
});
|
||||
|
||||
it("is not lapsed before the deadline", () => {
|
||||
expect(payWindowLapsed(deadline, at(-1 * MIN))).toBe(false);
|
||||
});
|
||||
|
||||
it("is not lapsed inside the drain tail", () => {
|
||||
// The reproduced finding: settled ~7 minutes late. With the default 5-minute
|
||||
// tail the booking is still live at 4 minutes.
|
||||
expect(payWindowLapsed(deadline, at(4 * MIN))).toBe(false);
|
||||
expect(payWindowLapsed(deadline, at(DEFAULT_PAYMENT_DRAIN_MINUTES * MIN - 1))).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it("is lapsed once the tail passes", () => {
|
||||
expect(payWindowLapsed(deadline, at(DEFAULT_PAYMENT_DRAIN_MINUTES * MIN))).toBe(
|
||||
true,
|
||||
);
|
||||
expect(payWindowLapsed(deadline, at(7 * MIN))).toBe(true);
|
||||
});
|
||||
|
||||
it("never lapses without a deadline — callers decide what unknown means", () => {
|
||||
expect(payWindowLapsed(null, at(60 * MIN))).toBe(false);
|
||||
expect(payWindowLapsed(undefined, at(60 * MIN))).toBe(false);
|
||||
});
|
||||
|
||||
it("honours FREIGHT_PAYMENT_DRAIN_MINUTES", () => {
|
||||
process.env.FREIGHT_PAYMENT_DRAIN_MINUTES = "20";
|
||||
expect(paymentDrainMs()).toBe(20 * MIN);
|
||||
expect(payWindowLapsed(deadline, at(10 * MIN))).toBe(false);
|
||||
expect(payWindowLapsed(deadline, at(20 * MIN))).toBe(true);
|
||||
});
|
||||
|
||||
it("allows an explicit zero drain (old deadline-is-the-line behaviour)", () => {
|
||||
process.env.FREIGHT_PAYMENT_DRAIN_MINUTES = "0";
|
||||
expect(paymentDrainMs()).toBe(0);
|
||||
expect(payWindowLapsed(deadline, at(0))).toBe(true);
|
||||
});
|
||||
|
||||
it("falls back to the default on garbage or negative values", () => {
|
||||
for (const bad of ["", "abc", "-3"]) {
|
||||
process.env.FREIGHT_PAYMENT_DRAIN_MINUTES = bad;
|
||||
expect(paymentDrainMs()).toBe(DEFAULT_PAYMENT_DRAIN_MINUTES * MIN);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user