mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
* reland(sidecar): converge product clients after weekly release
Restore the sidecar convergence from #7244 after the release-scheduling revert in #7634. This tree matches the previously reviewed and cross-platform QA-accepted implementation at d83d4e032f.
* fix(sidecar): clarify identity and cache witnesses
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* fix(packaged): probe cross-source desktop owners
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* fix(sidecar): preserve cross-source launch ownership
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* test(pack): assert cross-source Windows launch ownership
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* fix(sidecar): align HyperFrames with client boundary
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* fix(e2e): keep HyperFrames fixture in helper lane
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* docs(sidecar): restore review and handoff contracts
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* fix(sidecar): restore cache and daemon boundaries
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* fix(pack): restore sourcemaps and Linux smoke discovery
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* fix(sidecar): make payload handoff generation-atomic
* fix(sidecar): preserve packaged action and mode parity
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* test(pack): align Linux cleanup resource count
Generated-By: looper 0.11.2 (runner=fixer, agent=codex)
* fix(packaged): preserve headless sidecar mode
* test: normalize source line endings
* fix(daemon): launch Codex cmd shims on Windows
---------
Co-authored-by: Looper <looper@noreply.github.com>
91 lines
3.2 KiB
TypeScript
91 lines
3.2 KiB
TypeScript
import { createServer as createHttpServer } from 'node:http';
|
|
import { createConnection, type AddressInfo } from 'node:net';
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
import { createWebHttpServerShutdown } from '../sidecar/server';
|
|
|
|
describe('web sidecar HTTP shutdown', () => {
|
|
it('force-closes a long-lived connection after the bounded drain window', async () => {
|
|
const server = createHttpServer((_request, response) => {
|
|
response.writeHead(200, {
|
|
connection: 'keep-alive',
|
|
'content-type': 'text/event-stream',
|
|
});
|
|
response.write('event: ready\ndata: {}\n\n');
|
|
});
|
|
const closeServer = createWebHttpServerShutdown(server, 25);
|
|
|
|
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
const port = (server.address() as AddressInfo).port;
|
|
const socket = createConnection(port, '127.0.0.1');
|
|
await new Promise<void>((resolve, reject) => {
|
|
socket.once('error', reject);
|
|
socket.once('connect', () => {
|
|
socket.write([
|
|
'GET /events HTTP/1.1',
|
|
`Host: 127.0.0.1:${port}`,
|
|
'Connection: keep-alive',
|
|
'',
|
|
'',
|
|
].join('\r\n'));
|
|
});
|
|
socket.once('data', () => resolve());
|
|
});
|
|
|
|
const socketClosed = new Promise<void>((resolve) => socket.once('close', () => resolve()));
|
|
await expect(Promise.race([
|
|
closeServer().then(() => 'closed'),
|
|
new Promise<string>((resolve) => setTimeout(() => resolve('timed-out'), 500)),
|
|
])).resolves.toBe('closed');
|
|
await expect(socketClosed).resolves.toBeUndefined();
|
|
expect(server.listening).toBe(false);
|
|
});
|
|
|
|
it('is idempotent after a fast idle shutdown', async () => {
|
|
const server = createHttpServer((_request, response) => response.end('ok'));
|
|
const closeServer = createWebHttpServerShutdown(server, 25);
|
|
|
|
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
await closeServer();
|
|
await expect(closeServer()).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('retires upgraded sockets even when the HTTP server closes immediately', async () => {
|
|
const server = createHttpServer();
|
|
server.on('upgrade', (_request, socket) => {
|
|
socket.write([
|
|
'HTTP/1.1 101 Switching Protocols',
|
|
'Connection: Upgrade',
|
|
'Upgrade: test',
|
|
'',
|
|
'',
|
|
].join('\r\n'));
|
|
});
|
|
const closeServer = createWebHttpServerShutdown(server, 250);
|
|
|
|
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
const port = (server.address() as AddressInfo).port;
|
|
const socket = createConnection(port, '127.0.0.1');
|
|
await new Promise<void>((resolve, reject) => {
|
|
socket.once('error', reject);
|
|
socket.once('connect', () => {
|
|
socket.write([
|
|
'GET /upgrade HTTP/1.1',
|
|
`Host: 127.0.0.1:${port}`,
|
|
'Connection: Upgrade',
|
|
'Upgrade: test',
|
|
'',
|
|
'',
|
|
].join('\r\n'));
|
|
});
|
|
socket.once('data', () => resolve());
|
|
});
|
|
|
|
const socketClosed = new Promise<void>((resolve) => socket.once('close', () => resolve()));
|
|
await closeServer();
|
|
await expect(socketClosed).resolves.toBeUndefined();
|
|
expect(server.listening).toBe(false);
|
|
});
|
|
});
|