Files
insforge--insforge/backend/tests/unit/payments-advisory-lock.test.ts
wehub-resource-sync 3a28426bf4
Lint and Format Check / lint-and-format (push) Failing after 0s
Check Migrations / Check for duplicate migration numbers (push) Failing after 1s
CI Pre-merge Check / CI Pre-merge Check (push) Failing after 2m17s
chore: import upstream snapshot with attribution
2026-07-13 12:23:40 +08:00

99 lines
3.2 KiB
TypeScript

import type { Pool } from 'pg';
import { beforeEach, describe, expect, it, vi } from 'vitest';
const { mockLogger } = vi.hoisted(() => ({
mockLogger: { error: vi.fn(), info: vi.fn(), warn: vi.fn(), debug: vi.fn() },
}));
vi.mock('../../src/utils/logger', () => ({ default: mockLogger }));
import { withPaymentSessionAdvisoryLock } from '../../src/services/payments/payments-advisory-lock';
describe('withPaymentSessionAdvisoryLock', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('releases the client normally after a successful unlock', async () => {
const client = {
query: vi.fn().mockResolvedValue({ rows: [] }),
release: vi.fn(),
};
const pool = {
connect: vi.fn().mockResolvedValue(client),
} as unknown as Pool;
await expect(
withPaymentSessionAdvisoryLock(pool, 'payments_environment_test', async () => 'ok')
).resolves.toBe('ok');
expect(client.query).toHaveBeenNthCalledWith(1, 'SELECT pg_advisory_lock(hashtext($1))', [
'payments_environment_test',
]);
expect(client.query).toHaveBeenNthCalledWith(2, 'SELECT pg_advisory_unlock(hashtext($1))', [
'payments_environment_test',
]);
expect(client.release).toHaveBeenCalledWith();
});
it('destroys the pooled client if unlock fails', async () => {
const unlockError = new Error('unlock failed');
const client = {
query: vi.fn().mockResolvedValueOnce({ rows: [] }).mockRejectedValueOnce(unlockError),
release: vi.fn(),
};
const pool = {
connect: vi.fn().mockResolvedValue(client),
} as unknown as Pool;
await expect(
withPaymentSessionAdvisoryLock(pool, 'payments_environment_test', async () => 'ok')
).rejects.toThrow('unlock failed');
expect(client.query).toHaveBeenNthCalledWith(1, 'SELECT pg_advisory_lock(hashtext($1))', [
'payments_environment_test',
]);
expect(client.query).toHaveBeenNthCalledWith(2, 'SELECT pg_advisory_unlock(hashtext($1))', [
'payments_environment_test',
]);
expect(client.release).toHaveBeenCalledWith(true);
expect(mockLogger.error).toHaveBeenCalledWith(
'Failed to release payments advisory lock',
expect.objectContaining({
lockName: 'payments_environment_test',
mode: 'exclusive',
error: 'unlock failed',
})
);
});
it('preserves the original task error when unlock also fails', async () => {
const taskError = new Error('task failed');
const unlockError = new Error('unlock failed');
const client = {
query: vi.fn().mockResolvedValueOnce({ rows: [] }).mockRejectedValueOnce(unlockError),
release: vi.fn(),
};
const pool = {
connect: vi.fn().mockResolvedValue(client),
} as unknown as Pool;
await expect(
withPaymentSessionAdvisoryLock(pool, 'payments_environment_test', async () => {
throw taskError;
})
).rejects.toThrow('task failed');
expect(client.release).toHaveBeenCalledWith(true);
expect(mockLogger.error).toHaveBeenCalledWith(
'Failed to release payments advisory lock',
expect.objectContaining({
lockName: 'payments_environment_test',
mode: 'exclusive',
error: 'unlock failed',
originalError: 'task failed',
})
);
});
});