test(torrents): harden native smoke validation

This commit is contained in:
NimBold
2026-08-01 19:55:42 +03:30
parent 1a492fc4c8
commit 92092e9844
3 changed files with 50 additions and 9 deletions
+6
View File
@@ -71,6 +71,10 @@ jobs:
run: |
cargo test --tests --target ${{ matrix.target }}
cargo test --lib --no-run --target ${{ matrix.target }}
- name: Test Torrent RPC harness on Windows
if: runner.os == 'Windows'
working-directory: src-tauri
run: cargo test torrent_probe::tests::http_rpc_harness --target ${{ matrix.target }} -- --nocapture
- name: Provision locked engines
if: runner.os != 'macOS'
run: node scripts/provision-engines.js --target ${{ matrix.target }}
@@ -78,3 +82,5 @@ jobs:
run: |
node scripts/stage-engines.js --target ${{ matrix.target }}
node scripts/verify-binaries.js --staged --target ${{ matrix.target }}
- name: Run Torrent process smoke
run: node scripts/smoke-torrent.js --binary src-tauri/engine-dist/${{ matrix.target }}/aria2c-${{ matrix.target }}${{ runner.os == 'Windows' && '.exe' || '' }} --failure-paths
+39 -9
View File
@@ -6,7 +6,7 @@ import http from 'node:http';
import net from 'node:net';
import os from 'node:os';
import path from 'node:path';
import { spawn } from 'node:child_process';
import { execFileSync, spawn } from 'node:child_process';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -359,12 +359,30 @@ async function stopDaemon(daemon) {
// The process may already have exited during cleanup.
}
}
if (!await waitForChildExit(child, 3000)) {
child.kill('SIGTERM');
if (!await waitForChildExit(child, 3000) && process.platform !== 'win32') {
child.kill('SIGKILL');
await waitForChildExit(child, 1000);
let exited = await waitForChildExit(child, 3000);
if (!exited) {
if (process.platform === 'win32') {
try {
execFileSync('taskkill', ['/pid', String(child.pid), '/t', '/f'], {
stdio: 'ignore',
timeout: 3000,
});
} catch {
// The process may have exited between the wait and taskkill.
}
} else {
child.kill('SIGTERM');
}
exited = await waitForChildExit(child, 3000);
}
if (!exited) {
if (process.platform !== 'win32') {
child.kill('SIGKILL');
exited = await waitForChildExit(child, 3000);
}
}
if (!exited) {
throw new Error(`Aria2 daemon process ${child.pid} did not exit after forced cleanup`);
}
} finally {
activeDaemons.delete(daemon);
@@ -379,11 +397,13 @@ async function closeServer(server) {
async function cleanupRuntime() {
if (cleanupPromise) return cleanupPromise;
cleanupPromise = (async () => {
let cleanupError;
for (const daemon of [...activeDaemons].reverse()) {
try {
await stopDaemon(daemon);
} catch (error) {
console.error(`[WARN] failed to stop Aria2 daemon: ${error.message}`);
cleanupError ??= error;
console.error(`[FAIL] failed to stop Aria2 daemon: ${error.message}`);
}
}
if (runtimeTracker) {
@@ -394,9 +414,19 @@ async function cleanupRuntime() {
if (runtimeTempRoot) {
const tempRoot = runtimeTempRoot;
runtimeTempRoot = undefined;
if (keepTemp) console.log(`[INFO] retained smoke-test directory: ${tempRoot}`);
else fs.rmSync(tempRoot, { recursive: true, force: true });
if (keepTemp || cleanupError) {
console.log(`[INFO] retained smoke-test directory: ${tempRoot}`);
} else {
try {
fs.rmSync(tempRoot, { recursive: true, force: true });
} catch (error) {
cleanupError ??= error;
console.error(`[FAIL] failed to remove smoke-test directory: ${error.message}`);
console.log(`[INFO] retained smoke-test directory: ${tempRoot}`);
}
}
}
if (cleanupError) throw cleanupError;
})();
return cleanupPromise;
}
+5
View File
@@ -49,3 +49,8 @@ Run the deterministic unavailable-tracker and Aria2-daemon-exit checks with:
```sh
npm run smoke:torrent:failure-paths
```
Native CI runs this failure-path smoke after staging the target-specific
bundled engines on macOS, Windows, and Linux. Windows also runs the filtered
HTTP-boundary RPC harness explicitly because its general Rust job compiles the
library tests without executing them.