Initial commit: ssessesse ki battle

This commit is contained in:
2026-10-13 11:15:26 +09:00
commit 4f24129e29
104 changed files with 10520 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { randomBytes, randomUUID } from 'node:crypto';
import { MongoClient } from 'mongodb';
import { createGameServer } from '../src/server/create-server.js';
import { ManualClock } from './helpers.js';
test('admin keeps auth, visitor metadata and current game sessions without historical matches', { skip: !process.env.TEST_MONGODB_URI }, async () => {
const databaseName = 'dragon_ball_test_admin_' + randomUUID().replaceAll('-', ''), clock = new ManualClock();
const app = await createGameServer({ mongoUri: process.env.TEST_MONGODB_URI!, databaseName, clientDirectory: 'dist/client', adminUser: 'operator', adminPassword: 'test-password-long', clock });
const client = await new MongoClient(process.env.TEST_MONGODB_URI!).connect();
const headers = { authorization: 'Basic ' + Buffer.from('operator:test-password-long').toString('base64') };
try {
assert.equal((await app.inject('/api/admin/analytics/report')).statusCode, 401);
assert.equal((await app.inject('/admin/analytics')).statusCode, 401);
assert.equal((await app.inject('/admin/analytics/index.html')).statusCode, 404);
assert.equal((await app.inject({ url: '/api/admin/analytics/report?start=bad', headers })).statusCode, 400);
const create = async () => (await app.inject({ method: 'POST', url: '/api/game-sessions', payload: { createRequestId: randomBytes(32).toString('base64url') } })).json().data;
const a = await create(), b = await create();
const post = (s: typeof a, url: string, payload: any) => app.inject({ method: 'POST', url, headers: { authorization: 'Bearer ' + s.token, 'x-game-session': s.gameSessionId }, payload });
const data = { eventId: 'page', eventType: 'page_view', screen: 'home', metadata: { device: 'mobile', browser: 'Safari 18', referrer: 'https://example.com/a?guestToken=secret', source: 'made-up' } };
await post(a, '/api/analytics/activity', { visible: true });
for (const s of [a, a, b]) assert.equal((await post(s, '/api/analytics/events', { events: [data] })).statusCode, 200);
assert.equal((await post(a, '/api/analytics/events', { events: [{ ...data, eventId: 'bad', code: 'free-text-secret' }] })).statusCode, 400);
await post(a, '/api/analytics/events', { events: [{ eventId: 'start', eventType: 'game_started', matchId: 'local-game', mode: 'bot' }] });
const match = (await post(a, '/api/game-session/matches', { requestId: 'register', matchId: 'local-game', mode: 'bot', expectedPreviousSeq: 0 })).json().data;
await post(a, '/api/game-session/results', { ...match, outcome: 'win', reason: 'hit' });
clock.time += 100;
const report = (await app.inject({ url: '/api/admin/analytics/report', headers })).json();
assert.equal(report.overview.visitors, 2); assert.equal(report.overview.pageViews, 2);
assert.equal(report.clientGameplay.players, 1); assert.equal(report.clientGameplay.startedMatches, 1);
assert.ok(!('gameplay' in report));
assert.equal(report.live.active, 2); assert.equal(report.live.connected, null);
assert.equal(report.live.matches, null); assert.equal(report.live.playingPeople, null);
assert.equal(report.live.source, 'activity_reports'); assert.ok(report.live.observedAt);
await post(b, '/api/analytics/activity', { visible: false });
assert.equal((await app.inject({ url: '/api/admin/analytics/live', headers })).json().live.active, 1);
const detail = (await app.inject({ url: '/api/admin/analytics/users/' + a.playerId, headers })).json();
assert.equal(detail.gameSessions.length, 1); assert.equal(detail.gameSessions[0].stats.bot.wins, 1);
assert.ok(!('stats' in detail)); assert.ok(!('matches' in detail)); assert.ok(!('firstMatchAt' in detail));
const body = JSON.stringify(detail); assert.ok(!body.includes(a.token)); assert.ok(!body.includes('tokenHash')); assert.ok(!body.includes('guestTokenHash'));
const events = JSON.stringify(await client.db(databaseName).collection('analytics_events').find().toArray());
assert.ok(!events.includes('guestToken')); assert.ok(!events.includes('made-up'));
assert.ok(events.includes('example.com')); assert.ok(events.includes('other'));
} finally { await app.close(); try { await client.db(databaseName).dropDatabase(); } finally { await client.close(); } }
});