feat: 플레이 감사 국가 월별 반기 시계열 조회 구현
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
summarizeNationPeriod,
|
||||
type AuditNationData,
|
||||
type NationMonthPoint,
|
||||
} from '../src/router/playAudit/nationSeries.js';
|
||||
|
||||
const population = {
|
||||
count: 0,
|
||||
gold: 0,
|
||||
rice: 0,
|
||||
dex: { dex1: 0, dex2: 0, dex3: 0, dex4: 0, dex5: 0 },
|
||||
averageGold: null,
|
||||
averageRice: null,
|
||||
averageDex: { dex1: null, dex2: null, dex3: null, dex4: null, dex5: null },
|
||||
};
|
||||
const nation = (month: number): AuditNationData => ({
|
||||
id: 1,
|
||||
name: `국가${month}`,
|
||||
color: '#ffffff',
|
||||
gold: month * 100,
|
||||
rice: month * 200,
|
||||
tech: month * 10,
|
||||
appliedRate: 20,
|
||||
incomeGold: month,
|
||||
incomeRice: 0,
|
||||
paidGold: month / 2,
|
||||
paidRice: 0,
|
||||
populations: { human: population, npc: population, troopNpc: population },
|
||||
});
|
||||
const months: NationMonthPoint[] = Array.from({ length: 6 }, (_, index) => ({
|
||||
ordinal: 2400 + index,
|
||||
collected: true,
|
||||
settlementsComplete: true,
|
||||
data: nation(index + 1),
|
||||
}));
|
||||
|
||||
describe('play audit half-year summary', () => {
|
||||
it('sums flows but takes stock, names and population denominators from the last month', () => {
|
||||
const summary = summarizeNationPeriod(2400, 6, months);
|
||||
expect(summary).toMatchObject({
|
||||
year: 200,
|
||||
month: 1,
|
||||
complete: true,
|
||||
stockAsOf: { year: 200, month: 6 },
|
||||
stock: {
|
||||
name: '국가6',
|
||||
gold: 600,
|
||||
rice: 1200,
|
||||
tech: 60,
|
||||
populations: { human: { count: 0, averageGold: null } },
|
||||
},
|
||||
flows: { incomeGold: 21, incomeRice: 0, paidGold: 10.5, paidRice: 0 },
|
||||
});
|
||||
});
|
||||
it('reports partial range independently from complete collection of the requested months', () => {
|
||||
expect(summarizeNationPeriod(2400, 6, months.slice(0, 2))).toMatchObject({
|
||||
complete: false,
|
||||
from: { year: 200, month: 1 },
|
||||
to: { year: 200, month: 2 },
|
||||
flows: { incomeGold: 3 },
|
||||
});
|
||||
});
|
||||
it('does not call a missing month or absent nation zero income', () => {
|
||||
const missing = months.map((point, index) =>
|
||||
index === 1 ? { ...point, collected: false, data: null } : point
|
||||
);
|
||||
expect(summarizeNationPeriod(2400, 6, missing)).toMatchObject({ complete: false, flows: { incomeGold: null } });
|
||||
expect(
|
||||
summarizeNationPeriod(
|
||||
2400,
|
||||
6,
|
||||
months.map((point) => ({ ...point, data: null }))
|
||||
)
|
||||
).toMatchObject({
|
||||
complete: false,
|
||||
stock: null,
|
||||
stockAsOf: null,
|
||||
flows: { incomeRice: null },
|
||||
});
|
||||
});
|
||||
it('keeps incomplete settlement coverage unknown while preserving stock coverage', () => {
|
||||
const partial = months.map((point, index) => ({ ...point, settlementsComplete: index !== 0 }));
|
||||
expect(summarizeNationPeriod(2400, 6, partial)).toMatchObject({ complete: true, flows: { incomeGold: null } });
|
||||
expect(summarizeNationPeriod(2400, 6, [])).toMatchObject({
|
||||
complete: false,
|
||||
stock: null,
|
||||
flows: { incomeGold: null },
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2243,6 +2243,94 @@ integration('game API security over HTTP transport', () => {
|
||||
serverRestrictions: { [profileName]: { blockedFeatures: ['gameplay'] } },
|
||||
});
|
||||
expect((await get('capabilities', blocked)).status).toBe(403);
|
||||
const population = {
|
||||
count: 0,
|
||||
gold: 0,
|
||||
rice: 0,
|
||||
dex: { dex1: 0, dex2: 0, dex3: 0, dex4: 0, dex5: 0 },
|
||||
averageGold: null,
|
||||
averageRice: null,
|
||||
averageDex: { dex1: null, dex2: null, dex3: null, dex4: null, dex5: null },
|
||||
};
|
||||
await db.playAuditMonth.createMany({
|
||||
data: [2, 3, 4, 5, 6].map((month) => ({
|
||||
id: `${seasonId}:190:${month}`,
|
||||
serverId: seasonId,
|
||||
year: 190,
|
||||
month,
|
||||
kind: 'MONTH_END',
|
||||
settlementsComplete: true,
|
||||
hash: 'http-series-fixture',
|
||||
})),
|
||||
});
|
||||
await db.playAuditNation.createMany({
|
||||
data: [1, 2, 3, 4, 5, 6].map((month) => ({
|
||||
sampleId: `${seasonId}:190:${month}`,
|
||||
nationId: ownerNationId,
|
||||
data: {
|
||||
id: ownerNationId,
|
||||
name: `국가${month}`,
|
||||
color: '#ffffff',
|
||||
gold: month * 100,
|
||||
rice: 200,
|
||||
tech: 10,
|
||||
appliedRate: 20,
|
||||
incomeGold: month,
|
||||
incomeRice: 0,
|
||||
paidGold: 0,
|
||||
paidRice: 0,
|
||||
populations: { human: population, npc: population, troopNpc: population },
|
||||
},
|
||||
})),
|
||||
});
|
||||
await db.worldState.update({ where: { id: fixtureWorldId }, data: { currentMonth: 7 } });
|
||||
const series = await get('nationSeries', admin, {
|
||||
nationId: ownerNationId,
|
||||
from: { year: 190, month: 1 },
|
||||
to: { year: 190, month: 6 },
|
||||
});
|
||||
expect(series.status).toBe(200);
|
||||
expect(series.body).toMatchObject({
|
||||
result: {
|
||||
data: {
|
||||
nextCursor: null,
|
||||
items: [
|
||||
{
|
||||
year: 190,
|
||||
month: 1,
|
||||
complete: true,
|
||||
stock: { gold: 600 },
|
||||
flows: { incomeGold: 21, incomeRice: 0 },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
(
|
||||
await get('nationSeries', admin, {
|
||||
nationId: ownerNationId,
|
||||
resolution: 'month',
|
||||
limit: 1,
|
||||
from: { year: 190, month: 1 },
|
||||
to: { year: 190, month: 6 },
|
||||
})
|
||||
).body
|
||||
).toMatchObject({
|
||||
result: { data: { nextCursor: { year: 190, month: 2 }, items: [{ stock: { gold: 100 } }] } },
|
||||
});
|
||||
expect(
|
||||
(
|
||||
await get('nationSeries', admin, {
|
||||
nationId: ownerNationId,
|
||||
from: { year: 190, month: 7 },
|
||||
to: { year: 190, month: 7 },
|
||||
})
|
||||
).body
|
||||
).toMatchObject({
|
||||
result: { data: { items: [{ complete: false, stock: null, flows: { incomeGold: null } }] } },
|
||||
});
|
||||
|
||||
await db.worldState.update({
|
||||
where: { id: fixtureWorldId },
|
||||
data: {
|
||||
|
||||
Reference in New Issue
Block a user