diff --git a/packages/cultnet-ts/package.json b/packages/cultnet-ts/package.json index 5f87eccc..f94f0bfa 100644 --- a/packages/cultnet-ts/package.json +++ b/packages/cultnet-ts/package.json @@ -26,7 +26,7 @@ "prepack": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json", "typecheck": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json --pretty false", "test": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test dist-test/test/*.test.js", - "test:interop": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test dist-test/test/interop/*.test.js" + "test:interop": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test --test-force-exit dist-test/test/interop/*.test.js" }, "keywords": [ "messagepack", diff --git a/packages/cultnet-ts/test/interop/cultnet-interop.test.ts b/packages/cultnet-ts/test/interop/cultnet-interop.test.ts index bec86942..4353e132 100644 --- a/packages/cultnet-ts/test/interop/cultnet-interop.test.ts +++ b/packages/cultnet-ts/test/interop/cultnet-interop.test.ts @@ -414,6 +414,12 @@ test("CultNet TS/Rust/C#/Python peers discover each other and exchange raw state const advertiseHost = findAdvertiseHost(); const servers: RunningServeProcess[] = []; + // Registered before anything is spawned. A peer whose readiness rejects + // would otherwise skip this and strand every peer already running. + t.after(async () => { + await Promise.all(servers.map(stopProcess)); + }); + logInteropPhase("schema-v0", "start rust peer"); servers.push(await spawnServeProcess("rust", { command: rustBinaryPath, @@ -498,10 +504,6 @@ test("CultNet TS/Rust/C#/Python peers discover each other and exchange raw state })); await servers[servers.length - 1].ready; - t.after(async () => { - await Promise.all(servers.map(stopProcess)); - }); - logInteropPhase("schema-v0", "typescript dials rust"); const tsDial = await runJsonCommand("ts-dial", process.execPath, [ tsPeerScript, @@ -989,6 +991,12 @@ test("CultNet TypeScript and Rust full interop peers exchange schema-v0 over RUD const discoveryPort = await getFreePort(); const advertiseHost = findAdvertiseHost(); const servers: RunningServeProcess[] = []; + // Registered before anything is spawned. A peer whose readiness rejects + // would otherwise skip this and strand every peer already running. + t.after(async () => { + await Promise.all(servers.map(stopProcess)); + }); + servers.push(await spawnServeProcess("rust-rudp", { command: rustBinaryPath, args: [ @@ -1030,10 +1038,6 @@ test("CultNet TypeScript and Rust full interop peers exchange schema-v0 over RUD })); await servers[servers.length - 1].ready; - t.after(async () => { - await Promise.all(servers.map(stopProcess)); - }); - logInteropPhase("ts-rust-full-rudp", "typescript dials rust over rudp"); const tsRudpDial = await runJsonCommand("ts-rust-rudp-dial", process.execPath, [ tsPeerScript, @@ -1139,6 +1143,7 @@ test("CultNet Python and TypeScript exchange schema frames when Python dials a T assert.equal(exitCode, 0, pythonClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (pythonClient.child.exitCode === null && !pythonClient.child.killed) { pythonClient.child.kill("SIGTERM"); await once(pythonClient.child, "exit").catch(() => undefined); @@ -1246,6 +1251,7 @@ test("CultNet Python and TypeScript exchange schema-v0 MessagePack messages over assert.equal(exitCode, 0, pythonClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (pythonClient.child.exitCode === null && !pythonClient.child.killed) { pythonClient.child.kill("SIGTERM"); await once(pythonClient.child, "exit").catch(() => undefined); @@ -1322,6 +1328,7 @@ test("CultNet Rust and TypeScript exchange schema frames when Rust dials a TypeS assert.equal(exitCode, 0, rustClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (rustClient.child.exitCode === null && !rustClient.child.killed) { rustClient.child.kill("SIGTERM"); await once(rustClient.child, "exit").catch(() => undefined); @@ -1431,6 +1438,7 @@ test("CultNet Rust and TypeScript exchange schema-v0 MessagePack messages over R assert.equal(exitCode, 0, rustClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (rustClient.child.exitCode === null && !rustClient.child.killed) { rustClient.child.kill("SIGTERM"); await once(rustClient.child, "exit").catch(() => undefined); @@ -1507,6 +1515,7 @@ test("CultNet C# and TypeScript exchange schema frames when C# dials a TypeScrip assert.equal(exitCode, 0, csharpClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (csharpClient.child.exitCode === null && !csharpClient.child.killed) { csharpClient.child.kill("SIGTERM"); await once(csharpClient.child, "exit").catch(() => undefined); @@ -1616,6 +1625,7 @@ test("CultNet C# and TypeScript exchange schema-v0 MessagePack messages over RUD assert.equal(exitCode, 0, csharpClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (csharpClient.child.exitCode === null && !csharpClient.child.killed) { csharpClient.child.kill("SIGTERM"); await once(csharpClient.child, "exit").catch(() => undefined); @@ -1692,6 +1702,7 @@ test("CultNet Kotlin and TypeScript exchange schema frames when Kotlin dials a T assert.equal(exitCode, 0, kotlinClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (kotlinClient.child.exitCode === null && !kotlinClient.child.killed) { kotlinClient.child.kill("SIGTERM"); await once(kotlinClient.child, "exit").catch(() => undefined); @@ -1801,6 +1812,7 @@ test("CultNet Kotlin and TypeScript exchange schema-v0 MessagePack messages over assert.equal(exitCode, 0, kotlinClient.stderr.join("")); } finally { server.close(); + closeUdpSocket(serverSocket); if (kotlinClient.child.exitCode === null && !kotlinClient.child.killed) { kotlinClient.child.kill("SIGTERM"); await once(kotlinClient.child, "exit").catch(() => undefined); @@ -1823,6 +1835,12 @@ test("CultNet TypeScript and C# full interop peers exchange schema-v0 over RUDP" const discoveryPort = await getFreePort(); const advertiseHost = findAdvertiseHost(); const servers: RunningServeProcess[] = []; + // Registered before anything is spawned. A peer whose readiness rejects + // would otherwise skip this and strand every peer already running. + t.after(async () => { + await Promise.all(servers.map(stopProcess)); + }); + servers.push(await spawnServeProcess("csharp-rudp", { command: dotnetCommand, args: [ @@ -1865,10 +1883,6 @@ test("CultNet TypeScript and C# full interop peers exchange schema-v0 over RUDP" })); await servers[servers.length - 1].ready; - t.after(async () => { - await Promise.all(servers.map(stopProcess)); - }); - logInteropPhase("ts-csharp-full-rudp", "typescript dials csharp over rudp"); const tsRudpDial = await runJsonCommand("ts-csharp-rudp-dial", process.execPath, [ tsPeerScript, @@ -1923,6 +1937,12 @@ test("CultNet TypeScript and Kotlin full interop peers exchange schema-v0 over R const discoveryPort = await getFreePort(); const advertiseHost = findAdvertiseHost(); const servers: RunningServeProcess[] = []; + // Registered before anything is spawned. A peer whose readiness rejects + // would otherwise skip this and strand every peer already running. + t.after(async () => { + await Promise.all(servers.map(stopProcess)); + }); + servers.push(await spawnServeProcess("kotlin-rudp", { command: kotlinJavaCommand, args: [ @@ -1966,10 +1986,6 @@ test("CultNet TypeScript and Kotlin full interop peers exchange schema-v0 over R })); await servers[servers.length - 1].ready; - t.after(async () => { - await Promise.all(servers.map(stopProcess)); - }); - logInteropPhase("ts-kotlin-full-rudp", "typescript dials kotlin over rudp"); const tsRudpDial = await runJsonCommand("ts-kotlin-rudp-dial", process.execPath, [ tsPeerScript, @@ -3160,6 +3176,20 @@ function spawnRustRudpMessageClient(remotePort: number): Omit { const socket = dgram.createSocket("udp4"); await new Promise((resolveBind, rejectBind) => {