From 66120d504fe72f3af998b32e927e3ed155c44b4d Mon Sep 17 00:00:00 2001 From: hided62 Date: Sun, 16 Aug 2026 06:55:52 +0000 Subject: [PATCH] =?UTF-8?q?test(game-engine):=202=EB=B6=84=20=EB=8B=A4?= =?UTF-8?q?=EA=B0=9C=EC=9B=94=20backlog=20=EC=88=9C=EC=84=9C=EB=A5=BC=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/turnDaemonLifecycle.test.ts | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/app/game-engine/test/turnDaemonLifecycle.test.ts b/app/game-engine/test/turnDaemonLifecycle.test.ts index 37151f0f..c26befe6 100644 --- a/app/game-engine/test/turnDaemonLifecycle.test.ts +++ b/app/game-engine/test/turnDaemonLifecycle.test.ts @@ -600,4 +600,68 @@ describe('TurnDaemonLifecycle', () => { await lifecycle.stop('test done'); await loop; }); + + it('catches up a multi-month realtime backlog one 2-minute month at a time', async () => { + const turnTermMinutes = 2; + const initialLastTurnTime = new Date('2026-08-15T07:10:00.000Z'); + const gameNow = addMinutes(initialLastTurnTime, 8); + const clock = new ManualClock(gameNow.getTime()); + const controlQueue = new InMemoryControlQueue(); + let lastTurnTime = new Date(initialLastTurnTime); + let year = 194; + let month = 12; + const observed: Array<{ target: string; year: number; month: number }> = []; + + const lifecycle = new TurnDaemonLifecycle( + { + clock, + controlQueue, + getNextTickTime: (value) => addMinutes(value, turnTermMinutes), + stateStore: { + loadLastTurnTime: async () => new Date(lastTurnTime), + loadNextGeneralTurnTime: async () => addMinutes(lastTurnTime, 1), + saveLastTurnTime: async (value) => { + lastTurnTime = value; + }, + loadCheckpoint: async () => undefined, + saveCheckpoint: async () => {}, + loadGameClock: async () => ({ mode: 'realtime', now: gameNow }), + }, + processor: { + run: async (target): Promise => { + observed.push({ target: target.toISOString(), year, month }); + month += 1; + if (month > 12) { + year += 1; + month = 1; + } + if (observed.length === 4) { + controlQueue.enqueue({ type: 'shutdown', reason: 'verified' }); + } + return { + lastTurnTime: target.toISOString(), + processedGenerals: 1, + processedTurns: 1, + durationMs: 0, + partial: false, + }; + }, + }, + }, + { + profile: 'two-minute-multi-month-backlog', + defaultBudget: { budgetMs: 100, maxGenerals: 200, catchUpCap: 1 }, + } + ); + + await lifecycle.start(); + + expect(observed).toEqual([ + { target: '2026-08-15T07:12:00.000Z', year: 194, month: 12 }, + { target: '2026-08-15T07:14:00.000Z', year: 195, month: 1 }, + { target: '2026-08-15T07:16:00.000Z', year: 195, month: 2 }, + { target: '2026-08-15T07:18:00.000Z', year: 195, month: 3 }, + ]); + expect(lastTurnTime).toEqual(gameNow); + }); });