150 lines
4.9 KiB
TypeScript
150 lines
4.9 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import type { RedisConnector } from '@sammo-ts/infra';
|
|
|
|
import { RedisAccessTokenStore } from '../src/auth/accessTokenStore.js';
|
|
import { InMemoryFlushStore } from '../src/auth/flushStore.js';
|
|
import { InMemoryBattleSimTransport } from '../src/battleSim/inMemoryTransport.js';
|
|
import type { DatabaseClient, GameApiContext, GameProfile } from '../src/context.js';
|
|
import { InMemoryTurnDaemonTransport } from '../src/daemon/inMemoryTransport.js';
|
|
import { appRouter } from '../src/router.js';
|
|
|
|
const profile: GameProfile = {
|
|
id: 'che',
|
|
scenario: 'default',
|
|
name: 'che:default',
|
|
};
|
|
|
|
const buildContext = (): GameApiContext => {
|
|
const db = {
|
|
worldState: {
|
|
findFirst: async () => ({
|
|
id: 1,
|
|
currentYear: 185,
|
|
currentMonth: 3,
|
|
tickSeconds: 600,
|
|
config: {},
|
|
meta: {
|
|
lastTurnTime: '2026-07-26T03:00:00.000Z',
|
|
refresh: 12,
|
|
maxrefresh: 30,
|
|
maxonline: 5,
|
|
recentTraffic: [
|
|
{
|
|
year: 185,
|
|
month: 2,
|
|
refresh: 30,
|
|
online: 5,
|
|
date: '2026-07-26 02:50:00',
|
|
},
|
|
],
|
|
},
|
|
}),
|
|
},
|
|
generalAccessLog: {
|
|
aggregate: async () => ({
|
|
_sum: {
|
|
refreshScoreTotal: 21,
|
|
},
|
|
}),
|
|
findMany: async () => [
|
|
{ generalId: 7, refreshScoreTotal: 15 },
|
|
{ generalId: 8, refreshScoreTotal: 6 },
|
|
],
|
|
},
|
|
trafficPeriod: {
|
|
findUnique: async () => ({
|
|
id: 12,
|
|
worldStateId: 1,
|
|
year: 185,
|
|
month: 3,
|
|
startedAt: new Date('2026-07-26T03:00:00.000Z'),
|
|
lastRefresh: new Date('2026-07-26T03:05:00.000Z'),
|
|
refresh: 12,
|
|
online: 0,
|
|
_count: { generals: 2 },
|
|
}),
|
|
findMany: async () => [
|
|
{
|
|
id: 11,
|
|
worldStateId: 1,
|
|
year: 185,
|
|
month: 2,
|
|
startedAt: new Date('2026-07-26T02:50:00.000Z'),
|
|
lastRefresh: new Date('2026-07-26T02:50:00.000Z'),
|
|
refresh: 30,
|
|
online: 5,
|
|
_count: { generals: 0 },
|
|
},
|
|
],
|
|
aggregate: async () => ({
|
|
_max: {
|
|
refresh: 30,
|
|
online: 5,
|
|
},
|
|
}),
|
|
},
|
|
trafficPeriodGeneral: {
|
|
findMany: async () => [
|
|
{ generalId: 7, refresh: 9 },
|
|
{ generalId: 8, refresh: 3 },
|
|
],
|
|
},
|
|
general: {
|
|
findMany: async () => [
|
|
{ id: 7, name: '갑' },
|
|
{ id: 8, name: '을' },
|
|
],
|
|
},
|
|
};
|
|
const redis = {
|
|
get: async () => null,
|
|
set: async () => null,
|
|
} as unknown as RedisConnector['client'];
|
|
|
|
return {
|
|
db: db as unknown as DatabaseClient,
|
|
turnDaemon: new InMemoryTurnDaemonTransport(),
|
|
battleSim: new InMemoryBattleSimTransport(),
|
|
profile,
|
|
auth: null,
|
|
uploadDir: 'uploads',
|
|
uploadPath: '/uploads',
|
|
uploadPublicUrl: null,
|
|
redis,
|
|
accessTokenStore: new RedisAccessTokenStore(redis, profile.name),
|
|
flushStore: new InMemoryFlushStore(),
|
|
gameTokenSecret: 'test-secret',
|
|
};
|
|
};
|
|
|
|
describe('public.getTraffic', () => {
|
|
it('is public and returns only aggregate traffic plus allowlisted general names', async () => {
|
|
const result = await appRouter.createCaller(buildContext()).public.getTraffic();
|
|
|
|
expect(result.history).toHaveLength(2);
|
|
expect(result.history[0]).toEqual({
|
|
year: 185,
|
|
month: 2,
|
|
refresh: 30,
|
|
online: 5,
|
|
date: '2026-07-26T02:50:00.000Z',
|
|
});
|
|
expect(result.history[1]).toMatchObject({
|
|
year: 185,
|
|
month: 3,
|
|
refresh: 12,
|
|
online: 2,
|
|
date: '2026-07-26T03:05:00.000Z',
|
|
});
|
|
expect(result.maxRefresh).toBe(30);
|
|
expect(result.maxOnline).toBe(5);
|
|
expect(result.suspects).toEqual([
|
|
{ generalId: null, name: '접속자 총합', refresh: 12, refreshScoreTotal: 21 },
|
|
{ generalId: 7, name: '갑', refresh: 9, refreshScoreTotal: 15 },
|
|
{ generalId: 8, name: '을', refresh: 3, refreshScoreTotal: 6 },
|
|
]);
|
|
expect(JSON.stringify(result)).not.toContain('userId');
|
|
});
|
|
});
|