File size: 2,515 Bytes
4e23b01 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { startServer, type RunningServer } from '../src';
import { TEST_HOST_IDENTITY } from './helpers/hostIdentity';
import { authHeaders } from './helpers/auth';
const HTTP_METHODS = new Set([
'get',
'put',
'post',
'delete',
'options',
'head',
'patch',
'trace',
]);
const META_ENDPOINTS = ['/openapi.json', '/asyncapi.json', '/'];
describe('API surface snapshot', () => {
let home: string | undefined;
let server: RunningServer | undefined;
beforeAll(async () => {
home = mkdtempSync(join(tmpdir(), 'kimi-server-v2-api-surface-'));
server = await startServer({
hostIdentity: TEST_HOST_IDENTITY,
host: '127.0.0.1',
port: 0,
homeDir: home,
logLevel: 'silent',
debugEndpoints: true,
});
});
afterAll(async () => {
if (server !== undefined) {
try {
await server.close();
} catch {
}
server = undefined;
}
if (home !== undefined) {
rmSync(home, { recursive: true, force: true });
home = undefined;
}
});
it('matches the documented v2 route table and meta endpoints', async () => {
const base = `http://${server!.host}:${server!.port}`;
const openApiRes = await fetch(`${base}/openapi.json`, { headers: authHeaders(server as RunningServer) } as never);
expect(openApiRes.status).toBe(200);
const openApi = (await openApiRes.json()) as {
paths?: Record<string, Record<string, unknown>>;
};
const paths = openApi.paths ?? {};
expect(Object.keys(paths).length).toBeGreaterThan(0);
const routes: Array<[string, string]> = [];
for (const [path, item] of Object.entries(paths)) {
for (const key of Object.keys(item)) {
if (HTTP_METHODS.has(key.toLowerCase())) {
routes.push([key.toUpperCase(), path]);
}
}
}
routes.sort((a, b) => a[0].localeCompare(b[0]) || a[1].localeCompare(b[1]));
const meta: Array<[string, string, number]> = [];
for (const endpoint of META_ENDPOINTS) {
const res = await fetch(`${base}${endpoint}`, { headers: authHeaders(server as RunningServer) } as never);
meta.push(['GET', endpoint, res.status]);
}
meta.sort((a, b) => a[0].localeCompare(b[0]) || a[1].localeCompare(b[1]) || a[2] - b[2]);
expect({ routes, meta }).toMatchSnapshot();
});
});
|