156 lines
5.3 KiB
JavaScript
156 lines
5.3 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import test from 'node:test';
|
|
import express from 'express';
|
|
import { initDb } from '../src/db.js';
|
|
import { createStatsRouter } from '../src/routes/stats.js';
|
|
|
|
/**
|
|
* 테스트용 카드 데이터 파일을 생성한다.
|
|
* @param {string} datasPath
|
|
* @returns {void}
|
|
*/
|
|
function writeTestDatas(datasPath) {
|
|
fs.mkdirSync(datasPath, { recursive: true });
|
|
fs.writeFileSync(
|
|
path.join(datasPath, 'ua01.js'),
|
|
`
|
|
export const cardList = [
|
|
{ imgSrc: '/ua01/001.png', Number: 'UA01-001', parallel: false },
|
|
{ imgSrc: '/ua01/001_p1.png', Number: 'UA01-001', parallel: true },
|
|
{ imgSrc: '/ua01/002.png', Number: 'UA01-002', parallel: false },
|
|
];
|
|
`,
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(datasPath, 'uapr.js'),
|
|
`
|
|
export const cardList = [
|
|
{ imgSrc: '/uapr/001.png', Number: 'UAPR-001', parallel: false },
|
|
];
|
|
`,
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(datasPath, 'ua99 sample.js'),
|
|
`
|
|
export const cardList = [
|
|
{ imgSrc: '/sample/001.png', Number: 'SAMPLE-001', parallel: false },
|
|
];
|
|
`,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 테스트 중 바꾼 환경변수를 원래 상태로 되돌린다.
|
|
* @param {string} key
|
|
* @param {string | undefined} value
|
|
* @returns {void}
|
|
*/
|
|
function restoreEnv(key, value) {
|
|
if (value === undefined) {
|
|
delete process.env[key];
|
|
} else {
|
|
process.env[key] = value;
|
|
}
|
|
}
|
|
|
|
test('통계 API가 DB와 카드 데이터 운영 지표를 반환한다', async () => {
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'uniare-stats-'));
|
|
const dbPath = path.join(tempDir, 'test.db');
|
|
const datasPath = path.join(tempDir, 'datas');
|
|
const previousDatasPath = process.env.DATAS_PATH;
|
|
const previousToken = process.env.STATS_API_TOKEN;
|
|
process.env.DATAS_PATH = datasPath;
|
|
delete process.env.STATS_API_TOKEN;
|
|
writeTestDatas(datasPath);
|
|
|
|
const db = initDb(dbPath);
|
|
db.prepare(`
|
|
INSERT INTO users (
|
|
email, username, password_hash, display_name, email_verified_at, last_login_at
|
|
)
|
|
VALUES
|
|
('active@example.com', 'active', 'hash', 'active', datetime('now'), datetime('now')),
|
|
('pending@example.com', 'pending', 'hash', 'pending', NULL, NULL)
|
|
`).run();
|
|
db.prepare(`
|
|
INSERT INTO decks (
|
|
share_code, share_type, user_id, series, series_name, name, cards_json, is_public, view_count
|
|
)
|
|
VALUES
|
|
('PUBLIC01', 'user', 1, 'ua01', '테스트', '공개 덱', '[]', 1, 3),
|
|
('PRIVATE1', 'user', 1, 'ua01', '테스트', '비공개 덱', '[]', 0, 2),
|
|
('PRESET01', 'preset', NULL, 'uapr', '프로모', '프리셋', '[]', 1, 5)
|
|
`).run();
|
|
|
|
const app = express();
|
|
app.use('/api/stats', createStatsRouter(db, '4.0.test'));
|
|
const server = app.listen(0);
|
|
|
|
try {
|
|
await new Promise((resolve) => server.once('listening', resolve));
|
|
const address = server.address();
|
|
const response = await fetch(`http://127.0.0.1:${address.port}/api/stats`);
|
|
assert.equal(response.status, 200);
|
|
const body = await response.json();
|
|
|
|
assert.equal(body.status, 'online');
|
|
assert.equal(body.version, '4.0.test');
|
|
assert.equal(body.members.total, 2);
|
|
assert.equal(body.members.verified, 1);
|
|
assert.equal(body.members.unverified, 1);
|
|
assert.equal(body.decks.total, 3);
|
|
assert.equal(body.decks.publicTotal, 2);
|
|
assert.equal(body.decks.privateTotal, 1);
|
|
assert.equal(body.decks.totalViews, 10);
|
|
assert.equal(body.cards.seriesTotal, 2);
|
|
assert.equal(body.cards.cardTypesTotal, 3);
|
|
assert.equal(body.cards.cardPrintsTotal, 4);
|
|
assert.equal(body.cards.parallelPrintsTotal, 1);
|
|
} finally {
|
|
server.close();
|
|
db.close();
|
|
restoreEnv('DATAS_PATH', previousDatasPath);
|
|
restoreEnv('STATS_API_TOKEN', previousToken);
|
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test('통계 API 토큰이 설정되면 인증 헤더를 요구한다', async () => {
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'uniare-stats-token-'));
|
|
const dbPath = path.join(tempDir, 'test.db');
|
|
const datasPath = path.join(tempDir, 'datas');
|
|
const previousDatasPath = process.env.DATAS_PATH;
|
|
const previousToken = process.env.STATS_API_TOKEN;
|
|
process.env.DATAS_PATH = datasPath;
|
|
process.env.STATS_API_TOKEN = 'dashboard-secret';
|
|
writeTestDatas(datasPath);
|
|
|
|
const db = initDb(dbPath);
|
|
const app = express();
|
|
app.use('/api/stats', createStatsRouter(db, '4.0.test'));
|
|
const server = app.listen(0);
|
|
|
|
try {
|
|
await new Promise((resolve) => server.once('listening', resolve));
|
|
const address = server.address();
|
|
const baseUrl = `http://127.0.0.1:${address.port}/api/stats`;
|
|
|
|
const denied = await fetch(baseUrl);
|
|
assert.equal(denied.status, 401);
|
|
|
|
const allowed = await fetch(baseUrl, {
|
|
headers: { Authorization: 'Bearer dashboard-secret' },
|
|
});
|
|
assert.equal(allowed.status, 200);
|
|
} finally {
|
|
server.close();
|
|
db.close();
|
|
restoreEnv('DATAS_PATH', previousDatasPath);
|
|
restoreEnv('STATS_API_TOKEN', previousToken);
|
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
}
|
|
});
|