(opts: BootOptions = {})
| 133 | * binds to `127.0.0.1:0` by default, and tracks the result for `closeAll()`. |
| 134 | */ |
| 135 | export async function boot(opts: BootOptions = {}): Promise<ServerHarness> { |
| 136 | const token = opts.token ?? DEFAULT_TOKEN; |
| 137 | const host = opts.host ?? '127.0.0.1'; |
| 138 | const port = opts.port ?? 0; |
| 139 | // Inject a fixed-token `IAuthTokenService` by default so harness-based tests |
| 140 | // stay transparent (`authedFetch` / `authedWs` already carry `test-token`). |
| 141 | // The fixed impl is placed FIRST so an explicit caller-supplied |
| 142 | // `IAuthTokenService` override still wins (serviceOverrides are last-wins). |
| 143 | const serviceOverrides: ServerStartOptions['serviceOverrides'] = [ |
| 144 | fixedTokenAuth(token), |
| 145 | ...(opts.serviceOverrides ?? []), |
| 146 | ]; |
| 147 | |
| 148 | const tmpDir = mkdtempSync(join(tmpdir(), 'kimi-server-harness-')); |
| 149 | const homeDir = mkdtempSync(join(tmpdir(), 'kimi-server-harness-home-')); |
| 150 | const lockPath = join(tmpDir, 'lock'); |
| 151 | |
| 152 | const server = await startServer({ |
| 153 | host, |
| 154 | port, |
| 155 | lockPath, |
| 156 | serviceOverrides, |
| 157 | logger: pino({ level: 'silent' }), |
| 158 | coreProcessOptions: { homeDir }, |
| 159 | }); |
| 160 | |
| 161 | const httpPort = deriveHttpPort(server.address); |
| 162 | const baseUrl = `http://${host}:${httpPort}`; |
| 163 | const wsUrl = `ws://${host}:${httpPort}/api/v1/ws`; |
| 164 | |
| 165 | const sockets = new Set<WebSocket>(); |
| 166 | let closed = false; |
| 167 | |
| 168 | const harness: ServerHarness = { |
| 169 | server, |
| 170 | address: server.address, |
| 171 | baseUrl, |
| 172 | wsUrl, |
| 173 | token, |
| 174 | |
| 175 | authedFetch(path: string, init: RequestInit = {}): Promise<Response> { |
| 176 | const headers = new Headers(init.headers); |
| 177 | // Caller-supplied Authorization wins on conflict. |
| 178 | if (!headers.has('Authorization')) { |
| 179 | headers.set('Authorization', `Bearer ${token}`); |
| 180 | } |
| 181 | return fetch(`${baseUrl}${path}`, { ...init, headers }); |
| 182 | }, |
| 183 | |
| 184 | authedWs(): WebSocket { |
| 185 | const ws = new WebSocket(wsUrl, [`${WS_BEARER_PROTOCOL_PREFIX}${token}`], { |
| 186 | headers: { Authorization: `Bearer ${token}` }, |
| 187 | }); |
| 188 | sockets.add(ws); |
| 189 | const drop = (): void => { |
| 190 | sockets.delete(ws); |
| 191 | }; |
| 192 | ws.once('close', drop); |
no test coverage detected