Files
cfw-autumn/server/tests/integration/balances/lock/fetchLockReceipt.test.ts
2026-05-15 15:42:42 +01:00

115 lines
3.1 KiB
TypeScript

import { beforeEach, describe, expect, mock, test } from "bun:test";
import type { Redis } from "ioredis";
const sharedRedis = { name: "shared" } as unknown as Redis;
const dedicatedRedis = { name: "dedicated" } as unknown as Redis;
const mockState = {
jsonGetResult: null as string | null,
v2ResultsByRedis: new Map<object, { found: boolean }>(),
v2Calls: [] as object[],
};
mock.module("@/external/redis/initRedis.js", () => ({
redis: {
call: async () => mockState.jsonGetResult,
},
}));
mock.module("@/external/redis/orgRedisPool.js", () => ({
getOrgRedis: () => dedicatedRedis,
}));
mock.module("@/external/redis/resolveRedisV2.js", () => ({
resolveRedisV2: () => sharedRedis,
}));
mock.module("@/utils/cacheUtils/cacheUtils.js", () => ({
tryRedisRead: async (operation: () => Promise<unknown>) => operation(),
}));
mock.module(
"@/internal/balances/utils/lockV2/fetchAndClaimLockReceiptV2.js",
() => ({
fetchAndClaimLockReceiptV2: async ({
redisInstance,
}: {
redisInstance: object;
}) => {
mockState.v2Calls.push(redisInstance);
const result = mockState.v2ResultsByRedis.get(redisInstance);
if (!result?.found) return { found: false };
return {
found: true,
claimed: true,
lockReceiptKey: "lock:receipt",
redisInstance,
receipt: {
customer_id: "customer_123",
feature_id: "messages",
items: [],
},
};
},
}),
);
import { fetchLockReceipt } from "@/internal/balances/utils/lock/fetchLockReceipt.js";
const makeContext = ({ migrationPercent }: { migrationPercent: number }) =>
({
org: {
id: "org_123",
redis_config: {
connectionString: "encrypted",
url: "dragonfly.internal:6379",
migrationPercent,
previousMigrationPercent: 0,
migrationChangedAt: 1,
},
},
env: "sandbox",
redisV2: sharedRedis,
}) as never;
beforeEach(() => {
mockState.jsonGetResult = null;
mockState.v2ResultsByRedis.clear();
mockState.v2Calls = [];
});
describe("fetchLockReceipt", () => {
test("checks dedicated Redis during an org Redis migration and returns the source instance", async () => {
mockState.v2ResultsByRedis.set(sharedRedis, { found: false });
mockState.v2ResultsByRedis.set(dedicatedRedis, { found: true });
const result = await fetchLockReceipt({
ctx: makeContext({ migrationPercent: 50 }),
lockId: "lock_123",
});
expect(result.source).toBe("redis_v2");
if (result.source !== "redis_v2")
throw new Error("Expected Redis V2 receipt");
expect(result.redisInstance).toBe(dedicatedRedis);
expect(mockState.v2Calls).toEqual([sharedRedis, dedicatedRedis]);
});
test("does not check dedicated Redis when the org migration is complete", async () => {
mockState.v2ResultsByRedis.set(sharedRedis, { found: true });
const result = await fetchLockReceipt({
ctx: makeContext({ migrationPercent: 100 }),
lockId: "lock_123",
});
expect(result.source).toBe("redis_v2");
if (result.source !== "redis_v2")
throw new Error("Expected Redis V2 receipt");
expect(result.redisInstance).toBe(sharedRedis);
expect(mockState.v2Calls).toEqual([sharedRedis]);
});
});