refactor: modularize application domains
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { createHash } from 'node:crypto';
|
||||
import test from 'node:test';
|
||||
import { Hono } from 'hono';
|
||||
import app from './index.js';
|
||||
import {
|
||||
registerElectricMonthlyRoute,
|
||||
registerElectricOverviewRoute,
|
||||
type ElectricDependencies,
|
||||
} from './electric.js';
|
||||
import {
|
||||
registerHydrogenDailyRoute,
|
||||
type HydrogenDailyDependencies,
|
||||
} from './hydrogen-daily.js';
|
||||
import {
|
||||
registerHydrogenOverviewRoute,
|
||||
type HydrogenOverviewDependencies,
|
||||
} from './hydrogen-overview.js';
|
||||
|
||||
interface QueryCall {
|
||||
sql: string;
|
||||
params: unknown;
|
||||
}
|
||||
|
||||
interface CacheCall {
|
||||
key: string;
|
||||
force: boolean | undefined;
|
||||
}
|
||||
|
||||
function createQueryMock(resultSets: unknown[][], calls: QueryCall[]) {
|
||||
return async (sql: string, params?: unknown) => {
|
||||
calls.push({ sql, params });
|
||||
return [resultSets.shift() ?? [], []];
|
||||
};
|
||||
}
|
||||
|
||||
function createCachedMock(calls: CacheCall[]) {
|
||||
return async <T>(
|
||||
key: string,
|
||||
loader: () => Promise<T>,
|
||||
opts: { force?: boolean } = {},
|
||||
): Promise<T> => {
|
||||
calls.push({ key, force: opts.force });
|
||||
return loader();
|
||||
};
|
||||
}
|
||||
|
||||
function sqlHash(sql: string): string {
|
||||
return createHash('sha256').update(sql).digest('hex').slice(0, 12);
|
||||
}
|
||||
|
||||
test('能源路由继续按原顺序注册四个 GET 接口', () => {
|
||||
assert.deepEqual(
|
||||
app.routes.filter(route => route.method === 'GET').map(route => route.path),
|
||||
[
|
||||
'/hydrogen/overview',
|
||||
'/hydrogen/daily',
|
||||
'/electric/overview',
|
||||
'/electric/monthly',
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
test('四个处理器继续使用原缓存语义、数据库、SQL 与参数', async () => {
|
||||
const hydrogenCalls: QueryCall[] = [];
|
||||
const electricCalls: QueryCall[] = [];
|
||||
const cacheCalls: CacheCall[] = [];
|
||||
const cached = createCachedMock(cacheCalls);
|
||||
const hydrogenQuery = createQueryMock([
|
||||
[{ y: 2025 }],
|
||||
[{}],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
{ d: '2025-01-02', stationId: 7, stationName: '测试站', kg: 10, pricePerKg: 35 },
|
||||
],
|
||||
], hydrogenCalls);
|
||||
const electricQuery = createQueryMock([
|
||||
[{ totalKwh: 20, totalFee: 30, monthKwh: 15, monthFee: 25, todayKwh: 10, todayFee: 12 }],
|
||||
[],
|
||||
[{ date: '2025-01-02', kwh: 10, fee: 12 }],
|
||||
[{ kwh: 5 }],
|
||||
[{ date: '2025-01-02', kwh: 10, fee: 12 }],
|
||||
], electricCalls);
|
||||
|
||||
const hydrogenOverviewApp = new Hono();
|
||||
registerHydrogenOverviewRoute(hydrogenOverviewApp, {
|
||||
hydrogenPool: { query: hydrogenQuery },
|
||||
cached,
|
||||
} as unknown as HydrogenOverviewDependencies);
|
||||
const overviewResponse = await hydrogenOverviewApp.request(
|
||||
'/hydrogen/overview?year=2025&force=1',
|
||||
);
|
||||
assert.equal(overviewResponse.status, 200);
|
||||
|
||||
const hydrogenDailyApp = new Hono();
|
||||
registerHydrogenDailyRoute(hydrogenDailyApp, {
|
||||
hydrogenPool: { query: hydrogenQuery },
|
||||
cached,
|
||||
} as unknown as HydrogenDailyDependencies);
|
||||
const dailyResponse = await hydrogenDailyApp.request(
|
||||
'/hydrogen/daily?startDate=2025-01-01&endDate=2025-01-02&customer=external&force=1',
|
||||
);
|
||||
assert.equal(dailyResponse.status, 200);
|
||||
|
||||
const electricApp = new Hono();
|
||||
const electricDependencies = {
|
||||
pool: { query: electricQuery },
|
||||
cached,
|
||||
} as unknown as ElectricDependencies;
|
||||
registerElectricOverviewRoute(electricApp, electricDependencies);
|
||||
registerElectricMonthlyRoute(electricApp, electricDependencies);
|
||||
const electricOverviewResponse = await electricApp.request('/electric/overview?force=1');
|
||||
assert.equal(electricOverviewResponse.status, 200);
|
||||
const electricMonthlyResponse = await electricApp.request(
|
||||
'/electric/monthly?startDate=2025-01-01&endDate=2025-01-02&customer=external&force=1',
|
||||
);
|
||||
assert.equal(electricMonthlyResponse.status, 200);
|
||||
|
||||
assert.deepEqual(cacheCalls, [
|
||||
{ key: 'hydrogen/overview?year=2025', force: true },
|
||||
{ key: 'hydrogen/daily?start=2025-01-01&end=2025-01-02&customer=external', force: true },
|
||||
{ key: 'electric/overview', force: true },
|
||||
{ key: 'electric/monthly?customer=external&start=2025-01-01&end=2025-01-02', force: true },
|
||||
]);
|
||||
|
||||
// 指纹来自拆分前的 13 条 SQL,连空白符变化也会使测试失败。
|
||||
assert.deepEqual(
|
||||
[...hydrogenCalls, ...electricCalls].map(call => sqlHash(call.sql)),
|
||||
[
|
||||
'95f6d99b61c9',
|
||||
'63a63c5f78bb',
|
||||
'1367eddb3b7f',
|
||||
'83a52a7f9336',
|
||||
'f28fa4a3cb08',
|
||||
'dac9e86fc527',
|
||||
'a71da8f05765',
|
||||
'b562668859ce',
|
||||
'226fd8f950a1',
|
||||
'6e4031b10926',
|
||||
'4fc77463294c',
|
||||
'1886d54939d8',
|
||||
'09fc714ec4b2',
|
||||
],
|
||||
);
|
||||
|
||||
assert.deepEqual(hydrogenCalls.map(call => call.params), [
|
||||
['2024-01-01'],
|
||||
[2025, 2025, 2025, 2025, 2025, 2025, 2025, 0, 0, 0, 0, 0, 0, 0, 0, '2024-01-01'],
|
||||
['2024-01-01', 2025],
|
||||
['2024-01-01', 2025],
|
||||
['2024-01-01', 2025],
|
||||
['2024-01-01', 2025],
|
||||
['2024-01-01', 2025],
|
||||
['2025-01-01', '2025-01-02'],
|
||||
]);
|
||||
assert.deepEqual(electricCalls.map(call => call.params), [
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
['2025-01-01', '2025-01-02'],
|
||||
]);
|
||||
});
|
||||
Reference in New Issue
Block a user