75 lines
3.2 KiB
TypeScript
75 lines
3.2 KiB
TypeScript
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
import { createGamePostgresConnector, type GamePrismaClient } from '@sammo-ts/infra';
|
|
import { persistAuditMonth, type PendingAuditMonth } from '../src/playAudit/persistence.js';
|
|
import { buildAuditSnapshot } from '../src/playAudit/snapshot.js';
|
|
|
|
const databaseUrl = process.env.INPUT_EVENT_DATABASE_URL;
|
|
const integration = describe.skipIf(!databaseUrl);
|
|
const serverId = 'play-audit-persistence-fixture-20260916';
|
|
|
|
integration('play audit transactional month persistence', () => {
|
|
let db: GamePrismaClient;
|
|
let close: () => Promise<void>;
|
|
const snapshot: PendingAuditMonth = {
|
|
serverId,
|
|
year: 200,
|
|
month: 1,
|
|
tick: 10,
|
|
kind: 'MONTH_END',
|
|
settlementsComplete: true,
|
|
...buildAuditSnapshot({
|
|
nations: [
|
|
{
|
|
id: 1,
|
|
name: '감사국',
|
|
color: '#ffffff',
|
|
capitalCityId: null,
|
|
chiefGeneralId: null,
|
|
gold: 100,
|
|
rice: 200,
|
|
power: 0,
|
|
level: 1,
|
|
typeCode: 'che_중립',
|
|
meta: {},
|
|
},
|
|
],
|
|
cities: [],
|
|
generals: [],
|
|
settlements: [],
|
|
settlementsComplete: true,
|
|
}),
|
|
};
|
|
beforeAll(async () => {
|
|
const connector = createGamePostgresConnector({ url: databaseUrl! });
|
|
await connector.connect();
|
|
db = connector.prisma;
|
|
close = () => connector.disconnect();
|
|
});
|
|
afterAll(async () => {
|
|
await db.playAuditMonth.deleteMany({ where: { serverId } });
|
|
await close();
|
|
});
|
|
it('rolls back all audit rows, reloads exact data, rejects conflicting replay and deduplicates retries', async () => {
|
|
await expect(
|
|
db.$transaction(async (tx) => {
|
|
await tx.nation.create({ data: { id: 999_916, name: 'rollback audit', color: '#ffffff' } });
|
|
await persistAuditMonth(tx, snapshot);
|
|
throw new Error('fixture rollback');
|
|
})
|
|
).rejects.toThrow('fixture rollback');
|
|
expect(await db.playAuditMonth.count({ where: { serverId } })).toBe(0);
|
|
expect(await db.nation.findUnique({ where: { id: 999_916 } })).toBeNull();
|
|
await db.$transaction((tx) => persistAuditMonth(tx, snapshot));
|
|
await db.$transaction((tx) => persistAuditMonth(tx, snapshot));
|
|
const saved = await db.playAuditMonth.findFirstOrThrow({ where: { serverId }, include: { nations: true } });
|
|
expect(saved.nations.map((row) => row.data)).toEqual(snapshot.nations);
|
|
expect(await db.playAuditMonth.count({ where: { serverId } })).toBe(1);
|
|
await expect(db.$transaction((tx) => persistAuditMonth(tx, { ...snapshot, tick: 11 }))).rejects.toThrow(
|
|
'replay payload conflict'
|
|
);
|
|
expect((await db.playAuditMonth.findUniqueOrThrow({ where: { id: saved.id } })).tick).toBe(10);
|
|
await db.playAuditMonth.delete({ where: { id: saved.id } });
|
|
expect(await db.playAuditNation.count({ where: { sampleId: saved.id } })).toBe(0);
|
|
});
|
|
});
|