test: 시계 릴리스 게이트와 격리 fixture 완성
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
|||||||
const databaseUrl = process.env.INPUT_EVENT_DATABASE_URL;
|
const databaseUrl = process.env.INPUT_EVENT_DATABASE_URL;
|
||||||
const integration = describe.skipIf(!databaseUrl);
|
const integration = describe.skipIf(!databaseUrl);
|
||||||
const journalGeneralIds = [9_980_081, 9_980_082] as const;
|
const journalGeneralIds = [9_980_081, 9_980_082] as const;
|
||||||
|
const clockScenarioCode = 'input-event-boundary';
|
||||||
|
|
||||||
const journalBoundaryRouter = router({
|
const journalBoundaryRouter = router({
|
||||||
mutate: procedure
|
mutate: procedure
|
||||||
@@ -56,6 +57,21 @@ integration('API input event boundary', () => {
|
|||||||
await db.readModelRevision.deleteMany({
|
await db.readModelRevision.deleteMany({
|
||||||
where: { domain: 'front.general', entityId: { in: [...journalGeneralIds] } },
|
where: { domain: 'front.general', entityId: { in: [...journalGeneralIds] } },
|
||||||
});
|
});
|
||||||
|
await db.worldState.deleteMany({ where: { scenarioCode: clockScenarioCode } });
|
||||||
|
const base = new Date('2099-09-03T00:00:00.000Z');
|
||||||
|
await db.worldState.create({
|
||||||
|
data: {
|
||||||
|
scenarioCode: clockScenarioCode,
|
||||||
|
currentYear: 200,
|
||||||
|
currentMonth: 1,
|
||||||
|
tickSeconds: 600,
|
||||||
|
clockBaseTime: base,
|
||||||
|
clockTick: 0n,
|
||||||
|
clockMode: 'realtime',
|
||||||
|
clockWallAnchor: base,
|
||||||
|
clockPhase: 'RUNNING',
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@@ -68,6 +84,7 @@ integration('API input event boundary', () => {
|
|||||||
await db.readModelRevision.deleteMany({
|
await db.readModelRevision.deleteMany({
|
||||||
where: { domain: 'front.general', entityId: { in: [...journalGeneralIds] } },
|
where: { domain: 'front.general', entityId: { in: [...journalGeneralIds] } },
|
||||||
});
|
});
|
||||||
|
await db.worldState.deleteMany({ where: { scenarioCode: clockScenarioCode } });
|
||||||
await close?.();
|
await close?.();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,20 @@ integration('database command queue', () => {
|
|||||||
let close: (() => Promise<void>) | undefined;
|
let close: (() => Promise<void>) | undefined;
|
||||||
let db: GamePrismaClient;
|
let db: GamePrismaClient;
|
||||||
|
|
||||||
|
const cleanupFixtures = async (): Promise<void> => {
|
||||||
|
await db.inputEvent.deleteMany({ where: { requestId: { startsWith: 'integration:engine:' } } });
|
||||||
|
await db.clockProjectionOutbox.deleteMany({
|
||||||
|
where: { suspensionId: { in: ['integration-queue-revision-8-9', 'integration-unification-wait'] } },
|
||||||
|
});
|
||||||
|
await db.clockSuspension.deleteMany({
|
||||||
|
where: { id: { in: ['integration-queue-revision-8-9', 'integration-unification-wait'] } },
|
||||||
|
});
|
||||||
|
await db.message.deleteMany({ where: { mailbox: 991_199 } });
|
||||||
|
await db.worldState.deleteMany({
|
||||||
|
where: { scenarioCode: { in: ['queue-clock-test', 'queue-unification-clock-test'] } },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const connector = createGamePostgresConnector({ url: databaseUrl! });
|
const connector = createGamePostgresConnector({ url: databaseUrl! });
|
||||||
await connector.connect();
|
await connector.connect();
|
||||||
@@ -25,22 +39,10 @@ integration('database command queue', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(cleanupFixtures);
|
||||||
await db.inputEvent.deleteMany({ where: { requestId: { startsWith: 'integration:engine:' } } });
|
|
||||||
await db.clockProjectionOutbox.deleteMany({
|
|
||||||
where: { suspensionId: { in: ['integration-queue-revision-8-9', 'integration-unification-wait'] } },
|
|
||||||
});
|
|
||||||
await db.clockSuspension.deleteMany({
|
|
||||||
where: { id: { in: ['integration-queue-revision-8-9', 'integration-unification-wait'] } },
|
|
||||||
});
|
|
||||||
await db.message.deleteMany({ where: { mailbox: 991_199 } });
|
|
||||||
await db.worldState.updateMany({ data: { clockPhase: 'RUNNING' } });
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await db.inputEvent.deleteMany({
|
await cleanupFixtures();
|
||||||
where: { requestId: { startsWith: 'integration:engine:' } },
|
|
||||||
});
|
|
||||||
await close?.();
|
await close?.();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ export default defineConfig({
|
|||||||
'scenario/gameCancellation': 'src/scenario/gameCancellation.ts',
|
'scenario/gameCancellation': 'src/scenario/gameCancellation.ts',
|
||||||
'scenario/scenarioSeeder': 'src/scenario/scenarioSeeder.ts',
|
'scenario/scenarioSeeder': 'src/scenario/scenarioSeeder.ts',
|
||||||
'scenario/unitSetLoader': 'src/scenario/unitSetLoader.ts',
|
'scenario/unitSetLoader': 'src/scenario/unitSetLoader.ts',
|
||||||
|
'turn/clockProjectionOutbox': 'src/turn/clockProjectionOutbox.ts',
|
||||||
|
'turn/clockReconciliation': 'src/turn/clockReconciliation.ts',
|
||||||
'turn/databaseHooks': 'src/turn/databaseHooks.ts',
|
'turn/databaseHooks': 'src/turn/databaseHooks.ts',
|
||||||
'turn/inMemoryWorld': 'src/turn/inMemoryWorld.ts',
|
'turn/inMemoryWorld': 'src/turn/inMemoryWorld.ts',
|
||||||
'turn/monthlyDisasterAction': 'src/turn/monthlyDisasterAction.ts',
|
'turn/monthlyDisasterAction': 'src/turn/monthlyDisasterAction.ts',
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ mean deployment or production validation.
|
|||||||
|
|
||||||
## Milestone 5 - test-branch release gate
|
## Milestone 5 - test-branch release gate
|
||||||
|
|
||||||
- [ ] Full typecheck, architecture, lint, unit, build, and non-conditional
|
- [x] Full typecheck, architecture, lint, unit, build, and non-conditional
|
||||||
integration suites.
|
integration suites.
|
||||||
- [ ] Dedicated PostgreSQL/Redis conditional integration suite with skip count
|
- [x] Dedicated PostgreSQL/Redis conditional integration suite with skip count
|
||||||
recorded.
|
recorded.
|
||||||
- [x] Recovery runbook exercised from each incomplete status.
|
- [x] Recovery runbook exercised from each incomplete status.
|
||||||
- [x] Admin status/readiness exposes revision, phase, participant checksums, and
|
- [x] Admin status/readiness exposes revision, phase, participant checksums, and
|
||||||
@@ -126,3 +126,16 @@ mean deployment or production validation.
|
|||||||
- The dedicated PostgreSQL/Redis fixture reached `RUNNING@2/2` only after the
|
- The dedicated PostgreSQL/Redis fixture reached `RUNNING@2/2` only after the
|
||||||
Redis projection. DB-wall versus a mocked 12-hour host drift and concurrent
|
Redis projection. DB-wall versus a mocked 12-hour host drift and concurrent
|
||||||
general-access lock acquisition completed without drift or deadlock.
|
general-access lock acquisition completed without drift or deadlock.
|
||||||
|
- `CI=1 TURBO_CONCURRENCY=1 pnpm typecheck` passed 21/21 tasks,
|
||||||
|
`CI=1 TURBO_CONCURRENCY=1 pnpm test` passed 12/12 package tasks,
|
||||||
|
`CI=1 TURBO_CONCURRENCY=1 pnpm build` passed 26/26 tasks, and workspace lint
|
||||||
|
passed. `pnpm check:architecture` registered 22 authoritative clock fields
|
||||||
|
and 18 participants.
|
||||||
|
- Dedicated sequential PostgreSQL/Redis runs passed clock reconciliation 3/3,
|
||||||
|
atomic unification 1/1, command queue 7/7, runtime clock persistence 3/3,
|
||||||
|
API input-event boundary 13/13, and tournament revision 4/4: 31/31 enabled
|
||||||
|
tests with zero skips. The queue and API suites now create and remove their
|
||||||
|
own clock fixtures so a completed file cannot leak phase or initialization
|
||||||
|
state into the next file.
|
||||||
|
- User-test deployment and public runtime evidence remain deliberately open:
|
||||||
|
Git push is not deployment, and no deployment was authorized in this work.
|
||||||
|
|||||||
Reference in New Issue
Block a user