Skip to content

Commit dc65294

Browse files
sirtimidclaude
andcommitted
fix: address review findings — dedup helpers, fix tests, fix error handler
- Fix uncaughtException handler to use console.error + exitCode instead of re-throwing (which hard-kills the process without Vitest diagnostics) - Add missing IPv6 test case for getHost in multiaddr.test.ts - Add missing empty-string edge case for isPrivateAddress in network.test.ts - Extract stopWithTimeout to test/helpers/stop-with-timeout.ts (was duplicated across 3 e2e test files) - Extract getRemoteCommsPeerId to test/helpers/remote-comms.ts (was duplicated in relay-connectivity and bip39 tests) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 245a441 commit dc65294

9 files changed

Lines changed: 58 additions & 100 deletions

File tree

packages/kernel-node-runtime/test/e2e/bip39-identity-recovery.test.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { makeSQLKernelDatabase } from '@metamask/kernel-store/sqlite/nodejs';
22
import { Kernel } from '@metamask/ocap-kernel';
3-
import type { KernelStatus } from '@metamask/ocap-kernel';
43
import { mkdtemp, rm } from 'node:fs/promises';
54
import { tmpdir } from 'node:os';
65
import { join } from 'node:path';
76
import { describe, it, expect } from 'vitest';
87

98
import { makeTestKernel } from '../helpers/kernel.ts';
9+
import { getRemoteCommsPeerId } from '../helpers/remote-comms.ts';
1010

1111
// Valid 12-word test mnemonic (DO NOT use in production)
1212
const TEST_MNEMONIC =
@@ -23,21 +23,6 @@ const DUMMY_RELAYS = [
2323
'/ip4/127.0.0.1/tcp/19001/ws/p2p/12D3KooWBTf3S95YAsh6fi5rhohMsk8qaTy19rrpW8X9G69vn6GP',
2424
];
2525

26-
/**
27-
* Extract peerId from remoteComms status, returning undefined for disconnected state.
28-
*
29-
* @param remoteComms - The remote comms status object.
30-
* @returns The peer ID string or undefined.
31-
*/
32-
function getRemoteCommsPeerId(
33-
remoteComms: KernelStatus['remoteComms'],
34-
): string | undefined {
35-
if (remoteComms && remoteComms.state !== 'disconnected') {
36-
return remoteComms.peerId;
37-
}
38-
return undefined;
39-
}
40-
4126
// Tests for identity recovery using mnemonic
4227
// Note: These tests verify that the same mnemonic produces the same peer ID
4328
// The peer ID is derived locally from the mnemonic

packages/kernel-node-runtime/test/e2e/quic-transport.test.ts

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,11 @@ import {
1010
makeRemoteVatConfig,
1111
sendRemoteMessage,
1212
} from '../helpers/remote-comms.ts';
13+
import { stopWithTimeout } from '../helpers/stop-with-timeout.ts';
1314

1415
// Increase timeout for network operations
1516
const NETWORK_TIMEOUT = 30_000;
1617

17-
/**
18-
* Stop an operation with a timeout to prevent hangs during cleanup.
19-
*
20-
* @param stopFn - The stop function to call.
21-
* @param timeoutMs - The timeout in milliseconds.
22-
* @param label - A label for logging.
23-
*/
24-
async function stopWithTimeout(
25-
stopFn: () => Promise<unknown>,
26-
timeoutMs: number,
27-
label: string,
28-
): Promise<void> {
29-
try {
30-
await Promise.race([
31-
stopFn(),
32-
new Promise<never>((_resolve, reject) =>
33-
setTimeout(() => reject(new Error(`${label} timed out`)), timeoutMs),
34-
),
35-
]);
36-
} catch {
37-
// Ignore timeout errors during cleanup
38-
}
39-
}
40-
4118
// Listen addresses for each kernel (port 0 = OS-assigned)
4219
const quicListenAddress = '/ip4/127.0.0.1/udp/0/quic-v1';
4320
const tcpListenAddress = '/ip4/127.0.0.1/tcp/0';

packages/kernel-node-runtime/test/e2e/relay-connectivity.test.ts

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,18 @@ import type { Libp2p } from '@libp2p/interface';
22
import { makeSQLKernelDatabase } from '@metamask/kernel-store/sqlite/nodejs';
33
import { startRelay } from '@metamask/kernel-utils/libp2p';
44
import { Kernel } from '@metamask/ocap-kernel';
5-
import type { KernelStatus } from '@metamask/ocap-kernel';
65
import { createConnection } from 'node:net';
76
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
87

98
import { makeTestKernel } from '../helpers/kernel.ts';
9+
import { getRemoteCommsPeerId } from '../helpers/remote-comms.ts';
10+
import { stopWithTimeout } from '../helpers/stop-with-timeout.ts';
1011

1112
const STOP_TIMEOUT = 5_000;
1213
const TEST_TIMEOUT = 30_000;
1314
const RELAY_PEER_ID = '12D3KooWJBDqsyHQF2MWiCdU4kdqx4zTsSTLRdShg7Ui6CRWB4uc';
1415
const RELAY_WS_PORT = 9001;
1516

16-
/**
17-
* Stop an operation with a timeout to prevent hangs during cleanup.
18-
*
19-
* @param stopFn - The stop function to call.
20-
* @param timeoutMs - The timeout in milliseconds.
21-
* @param label - A label for logging.
22-
*/
23-
async function stopWithTimeout(
24-
stopFn: () => Promise<unknown>,
25-
timeoutMs: number,
26-
label: string,
27-
): Promise<void> {
28-
try {
29-
await Promise.race([
30-
stopFn(),
31-
new Promise<never>((_resolve, reject) =>
32-
setTimeout(() => reject(new Error(`${label} timed out`)), timeoutMs),
33-
),
34-
]);
35-
} catch {
36-
// Ignore timeout errors during cleanup
37-
}
38-
}
39-
40-
function getRemoteCommsPeerId(
41-
remoteComms: KernelStatus['remoteComms'],
42-
): string | undefined {
43-
if (remoteComms && remoteComms.state !== 'disconnected') {
44-
return remoteComms.peerId;
45-
}
46-
return undefined;
47-
}
48-
4917
/**
5018
* Check if a TCP port is already in use.
5119
*

packages/kernel-node-runtime/test/e2e/remote-comms.test.ts

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,33 +22,10 @@ import {
2222
sendRemoteMessage,
2323
setupAliceAndBob,
2424
} from '../helpers/remote-comms.ts';
25+
import { stopWithTimeout } from '../helpers/stop-with-timeout.ts';
2526

2627
// Increase timeout for network operations
2728
const NETWORK_TIMEOUT = 30_000;
28-
29-
/**
30-
* Stop an operation with a timeout to prevent hangs during cleanup.
31-
*
32-
* @param stopFn - The stop function to call.
33-
* @param timeoutMs - The timeout in milliseconds.
34-
* @param label - A label for logging.
35-
*/
36-
async function stopWithTimeout(
37-
stopFn: () => Promise<unknown>,
38-
timeoutMs: number,
39-
label: string,
40-
): Promise<void> {
41-
try {
42-
await Promise.race([
43-
stopFn(),
44-
new Promise<never>((_resolve, reject) =>
45-
setTimeout(() => reject(new Error(`${label} timed out`)), timeoutMs),
46-
),
47-
]);
48-
} catch {
49-
// Ignore timeout errors during cleanup
50-
}
51-
}
5229
// Test relay configuration
5330
// The relay peer ID is deterministic based on RELAY_LOCAL_ID = 200 in relay.ts
5431
const relayPeerId = '12D3KooWJBDqsyHQF2MWiCdU4kdqx4zTsSTLRdShg7Ui6CRWB4uc';

packages/kernel-node-runtime/test/e2e/setup-suppress-datachannel-error.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ process.on('uncaughtException', (error: Error) => {
1717
// Benign: native WebRTC module fires async error after channel teardown.
1818
return;
1919
}
20-
// Re-throw anything else so Vitest still catches real errors.
21-
throw error;
20+
// For non-datachannel errors, log and set exit code so Vitest reports
21+
// the failure. Re-throwing inside uncaughtException would hard-kill the
22+
// process without Vitest diagnostics.
23+
console.error('Uncaught exception in e2e test:', error);
24+
process.exitCode = 1;
2225
});

packages/kernel-node-runtime/test/helpers/remote-comms.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,28 @@ import { Kernel, kunser, makeKernelStore } from '@metamask/ocap-kernel';
44
import type {
55
ClusterConfig,
66
KRef,
7+
KernelStatus,
78
RemoteCommsOptions,
89
} from '@metamask/ocap-kernel';
910

1011
import { makeTestKernel } from './kernel.ts';
1112

13+
/**
14+
* Extract peerId from remoteComms status, returning undefined for
15+
* disconnected state.
16+
*
17+
* @param remoteComms - The remote comms status object.
18+
* @returns The peer ID string or undefined.
19+
*/
20+
export function getRemoteCommsPeerId(
21+
remoteComms: KernelStatus['remoteComms'],
22+
): string | undefined {
23+
if (remoteComms && remoteComms.state !== 'disconnected') {
24+
return remoteComms.peerId;
25+
}
26+
return undefined;
27+
}
28+
1229
/**
1330
* Helper to create a vat configuration for a remote vat.
1431
*
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Stop an operation with a timeout to prevent hangs during cleanup.
3+
*
4+
* @param stopFn - The stop function to call.
5+
* @param timeoutMs - The timeout in milliseconds.
6+
* @param label - A label for logging.
7+
*/
8+
export async function stopWithTimeout(
9+
stopFn: () => Promise<unknown>,
10+
timeoutMs: number,
11+
label: string,
12+
): Promise<void> {
13+
try {
14+
await Promise.race([
15+
stopFn(),
16+
new Promise<never>((_resolve, reject) =>
17+
setTimeout(() => reject(new Error(`${label} timed out`)), timeoutMs),
18+
),
19+
]);
20+
} catch {
21+
// Ignore timeout errors during cleanup
22+
}
23+
}

packages/ocap-kernel/src/utils/multiaddr.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ describe('getHost', () => {
3737
addr: '/dns4/relay.example.com/tcp/443/wss',
3838
expected: 'relay.example.com',
3939
},
40+
{
41+
desc: 'extracts IPv6 host',
42+
addr: '/ip6/::1/tcp/9001/ws',
43+
expected: '::1',
44+
},
4045
{
4146
desc: 'extracts dns6 host',
4247
addr: '/dns6/relay.example.com/tcp/443/wss',

packages/ocap-kernel/src/utils/network.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ describe('isPrivateAddress', () => {
4747
{ host: 'relay.example.com', expected: false },
4848
{ host: 'google.com', expected: false },
4949

50+
// Empty string (from getHost() ?? '' fallback)
51+
{ host: '', expected: false },
52+
5053
// Invalid IPv4 (octets > 255)
5154
{ host: '256.0.0.1', expected: false },
5255
])('isPrivateAddress("$host") → $expected', ({ host, expected }) => {

0 commit comments

Comments
 (0)