test(game-engine): persist invader monthly lifecycle

This commit is contained in:
2026-07-25 23:20:28 +00:00
parent d7e31f6859
commit 02a1642df7
@@ -4,7 +4,11 @@ import type { City, Nation } from '@sammo-ts/logic';
import { createDatabaseTurnHooks } from '../src/turn/databaseHooks.js';
import { InMemoryTurnWorld } from '../src/turn/inMemoryWorld.js';
import { createRaiseInvaderHandler } from '../src/turn/monthlyInvaderAction.js';
import {
createAutoDeleteInvaderHandler,
createInvaderEndingHandler,
createRaiseInvaderHandler,
} from '../src/turn/monthlyInvaderAction.js';
import { createMonthlyEventHandler } from '../src/turn/monthlyEventHandler.js';
import { InMemoryReservedTurnStore } from '../src/turn/reservedTurnStore.js';
import { buildCommandEnv } from '../src/turn/reservedTurnCommands.js';
@@ -111,7 +115,7 @@ integration('RaiseInvader database persistence', () => {
const clean = async () => {
const createdGeneralIds = Array.from({ length: 10 }, (_, index) => firstCreatedGeneralId + index);
await db.logEntry.deleteMany({
where: { year: 200, month: 1, text: { contains: '【이벤트】' } },
where: { year: 200, text: { contains: '【이벤트】' } },
});
await db.generalTurn.deleteMany({
where: { generalId: { in: [existingGeneralId, ...createdGeneralIds] } },
@@ -245,6 +249,7 @@ integration('RaiseInvader database persistence', () => {
lastGeneralId: firstCreatedGeneralId - 1,
lastNationId: createdNationId - 1,
serverId: 'raise-invader-persistence',
refreshLimit: 3,
},
},
});
@@ -259,6 +264,7 @@ integration('RaiseInvader database persistence', () => {
lastGeneralId: firstCreatedGeneralId - 1,
lastNationId: createdNationId - 1,
serverId: 'raise-invader-persistence',
refreshLimit: 3,
},
};
const snapshot: TurnWorldSnapshot = {
@@ -286,12 +292,21 @@ integration('RaiseInvader database persistence', () => {
env: buildCommandEnv(snapshot.scenarioConfig),
loadArchivedNationMaxId: async () => 0,
});
const autoDelete = createAutoDeleteInvaderHandler({
getWorld: () => world,
reservedTurns,
});
const ending = createInvaderEndingHandler({ getWorld: () => world });
world = new InMemoryTurnWorld(state, snapshot, {
schedule: { entries: [{ startMinute: 0, tickMinutes: 10 }] },
calendarHandler: createMonthlyEventHandler({
getWorld: () => world,
startYear: 190,
actions: new Map([['RaiseInvader', handler]]),
actions: new Map([
['RaiseInvader', handler],
['AutoDeleteInvader', autoDelete],
['InvaderEnding', ending],
]),
}),
});
const dbHooks = await createDatabaseTurnHooks(databaseUrl!, world, { reservedTurns });
@@ -382,6 +397,64 @@ integration('RaiseInvader database persistence', () => {
});
expect(sequenceProbe.id).toBeGreaterThan(createdEventIds[1]!);
await db.event.delete({ where: { id: sequenceProbe.id } });
expect(world.removeEvent(sourceEventId)).toBe(true);
world.applyDiplomacyPatch({
srcNationId: createdNationId,
destNationId: existingNationId,
patch: { state: 2, term: 0 },
});
world.applyDiplomacyPatch({
srcNationId: existingNationId,
destNationId: createdNationId,
patch: { state: 2, term: 0 },
});
await world.advanceMonth(new Date('0200-02-01T00:00:00.000Z'));
await dbHooks.hooks.flushChanges?.({
lastTurnTime: world.getState().lastTurnTime.toISOString(),
processedGenerals: 0,
processedTurns: 1,
durationMs: 0,
partial: false,
});
expect(await db.event.findUnique({ where: { id: createdEventIds[0]! } })).toBeNull();
expect(
await db.generalTurn.findMany({
where: { generalId: firstCreatedGeneralId },
select: { actionCode: true },
})
).toEqual(Array.from({ length: 30 }, () => ({ actionCode: 'che_방랑' })));
expect(await db.event.findUnique({ where: { id: createdEventIds[1]! } })).not.toBeNull();
for (const generalId of createdGeneralIds) {
expect(world.removeGeneral(generalId)).toBe(true);
}
expect(world.removeNation(createdNationId)).toBe(true);
world.updateCity(invaderCityId, { nationId: existingNationId });
await world.advanceMonth(new Date('0200-03-01T00:00:00.000Z'));
await dbHooks.hooks.flushChanges?.({
lastTurnTime: world.getState().lastTurnTime.toISOString(),
processedGenerals: 0,
processedTurns: 1,
durationMs: 0,
partial: false,
});
expect(await db.event.findUnique({ where: { id: createdEventIds[1]! } })).toBeNull();
expect(await db.worldState.findUniqueOrThrow({ where: { id: stateRow.id } })).toMatchObject({
meta: expect.objectContaining({ isunited: 3, refreshLimit: 300 }),
});
expect(
await db.logEntry.findMany({
where: { year: 200, month: 3, text: { contains: '【이벤트】' } },
orderBy: { id: 'asc' },
select: { text: true },
})
).toEqual([
{ text: '<R>★</>200년 3월:<L><b>【이벤트】</b></>이민족을 모두 소탕했습니다!' },
{ text: '<R>★</>200년 3월:<L><b>【이벤트】</b></>중원은 당분간 태평성대를 누릴 것입니다.' },
]);
} finally {
await dbHooks.close();
}