mirror of
https://github.com/ruvnet/RuView.git
synced 2026-10-18 21:00:22 -05:00
test(harness): cover Node 20 WebSocket capability boundary
This commit is contained in:
1 parent
b265454b93
commit
b064acf57c
2 files changed
+31
-4
No files matched your search
@@ -4,6 +4,9 @@ import http from 'node:http';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { readIphoneLidar } from '../src/devices/lidar.js';
|
||||
|
||||
const hasNativeWebSocket = typeof globalThis.WebSocket === 'function';
|
||||
const needsWebSocket = { skip: !hasNativeWebSocket && 'requires the native WebSocket client (Node 22+)' };
|
||||
|
||||
// A real owned loopback WebSocket producer: upgrade, optional depth frame,
|
||||
// close handshake. No injected client event callbacks or hardware.
|
||||
async function relay(t, { frame = true, code = 1000 } = {}) {
|
||||
@@ -28,7 +31,19 @@ async function relay(t, { frame = true, code = 1000 } = {}) {
|
||||
return `ws://127.0.0.1:${server.address().port}/ws/lidar`;
|
||||
}
|
||||
|
||||
test('public iPhone reader completes when a successful relay stream closes', async t => {
|
||||
test('public iPhone reader reports an unavailable WebSocket without connecting', { skip: hasNativeWebSocket && 'native WebSocket is available' }, async t => {
|
||||
const server = http.createServer();
|
||||
let connections = 0;
|
||||
server.on('connection', socket => { connections++; socket.destroy(); });
|
||||
await new Promise(r => server.listen(0, '127.0.0.1', r));
|
||||
t.after(() => new Promise(r => server.close(r)));
|
||||
const result = await readIphoneLidar({ url: `ws://127.0.0.1:${server.address().port}/ws/lidar`, seconds: 2 });
|
||||
assert.deepEqual(result, { ok: false, reason: 'websocket_unavailable', remedy: 'Use Node 22+ (built-in WebSocket client).' });
|
||||
await new Promise(r => setImmediate(r));
|
||||
assert.equal(connections, 0, 'unavailable transport must not open a connection');
|
||||
});
|
||||
|
||||
test('public iPhone reader completes when a successful relay stream closes', needsWebSocket, async t => {
|
||||
const url = await relay(t);
|
||||
const started = performance.now();
|
||||
const result = await readIphoneLidar({ url, seconds: 2 });
|
||||
@@ -38,7 +53,7 @@ test('public iPhone reader completes when a successful relay stream closes', asy
|
||||
assert.ok(performance.now() - started < 1000, 'closed relay must finish before the capture timeout');
|
||||
});
|
||||
|
||||
test('normal empty relay close completes as no_frames', async t => {
|
||||
test('normal empty relay close completes as no_frames', needsWebSocket, async t => {
|
||||
const url = await relay(t, { frame: false });
|
||||
const started = performance.now();
|
||||
const result = await readIphoneLidar({ url, seconds: 2 });
|
||||
@@ -47,7 +62,7 @@ test('normal empty relay close completes as no_frames', async t => {
|
||||
assert.ok(performance.now() - started < 1000, 'empty closed relay must finish before timeout');
|
||||
});
|
||||
|
||||
test('abnormal empty relay close and packet limit controls retain semantics', async t => {
|
||||
test('abnormal empty relay close and packet limit controls retain semantics', needsWebSocket, async t => {
|
||||
const denied = await readIphoneLidar({ url: await relay(t, { frame: false, code: 1008 }), seconds: 2 });
|
||||
assert.equal(denied.reason, 'relay_closed');
|
||||
assert.match(denied.detail, /1008/);
|
||||
|
||||
@@ -10,6 +10,7 @@ const str = (f, s) => { const b = Buffer.from(s); return Buffer.concat([encodeVa
|
||||
const key = (f, n) => { const b = Buffer.alloc(4); b.writeUInt32LE(n); return Buffer.concat([encodeVarint((f << 3) | 5), b]); };
|
||||
const float = (f, v) => { const b = Buffer.alloc(4); b.writeFloatLE(v); return Buffer.concat([encodeVarint((f << 3) | 5), b]); };
|
||||
const pause = ms => new Promise(r => setTimeout(r, ms));
|
||||
const hasNativeWebSocket = typeof globalThis.WebSocket === 'function';
|
||||
|
||||
async function ownServer(t, server) {
|
||||
const sockets = new Set();
|
||||
@@ -57,7 +58,18 @@ test('public SDK accepts spectrum options and returns real UDP amplitude rows',
|
||||
assert.deepEqual(result.spectrum[0].frames, [Array(8).fill(5)]);
|
||||
});
|
||||
|
||||
test('public SDK accepts iPhone max_frames and terminates at the packet cap', async t => {
|
||||
test('public SDK reports unavailable iPhone transport without connecting', { skip: hasNativeWebSocket && 'native WebSocket is available' }, async t => {
|
||||
const server = http.createServer();
|
||||
let connections = 0;
|
||||
server.on('connection', socket => { connections++; socket.destroy(); });
|
||||
const port = await ownServer(t, server);
|
||||
const result = await createRuView().devices.lidar({ source: 'iphone', url: `ws://127.0.0.1:${port}/ws/lidar`, seconds: 2, max_frames: 1 });
|
||||
assert.deepEqual(result, { ok: false, reason: 'websocket_unavailable', remedy: 'Use Node 22+ (built-in WebSocket client).' });
|
||||
await new Promise(r => setImmediate(r));
|
||||
assert.equal(connections, 0, 'unavailable transport must not open a connection');
|
||||
});
|
||||
|
||||
test('public SDK accepts iPhone max_frames and terminates at the packet cap', { skip: !hasNativeWebSocket && 'requires the native WebSocket client (Node 22+)' }, async t => {
|
||||
const server = http.createServer();
|
||||
server.on('upgrade', (req, sock) => {
|
||||
const accept = createHash('sha1').update(req.headers['sec-websocket-key'] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11').digest('base64');
|
||||
|
||||
Reference in new issue
Block a user