From 6ee1374186b336a3968344fe72e41386933589e0 Mon Sep 17 00:00:00 2001 From: mlischetti Date: Tue, 21 Jul 2026 13:00:13 -0300 Subject: [PATCH] W-23517830 test(native-lib): isolated-process bad-library-path init test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cover the bad-library-path initialize() case that could not be asserted in the shared integration lane. A bad/nonexistent dwlib path makes initialize() throw a DataWeaveError only as the FIRST native init in a process (the runtime is loaded process-globally / ref-counted), so this runs in a dedicated child process — order- and vitest-pool-independent. - tests/integration/fixtures/bad-lib-init.cjs: child fixture that requires the built dist/ entry, asserts the DataWeaveError, and signals via stdout sentinel + exit code (a no-throw / wrong-error / native crash all surface as a non-zero child exit). - tests/integration/init-bad-path.test.ts: spawns the fixture with execFileSync (throws on non-zero exit) and asserts the OK sentinel; guards on the built entry existing with a clear message. - edge-cases.test.ts: update the NOTE to point at the new test instead of describing it as an open follow-up. Verified: tsc clean, 70 unit tests pass, 35 integration tests pass (deterministic across repeated runs) against the real native library. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../node/tests/integration/edge-cases.test.ts | 5 ++- .../integration/fixtures/bad-lib-init.cjs | 33 +++++++++++++++++++ .../tests/integration/init-bad-path.test.ts | 31 +++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 native-lib/node/tests/integration/fixtures/bad-lib-init.cjs create mode 100644 native-lib/node/tests/integration/init-bad-path.test.ts diff --git a/native-lib/node/tests/integration/edge-cases.test.ts b/native-lib/node/tests/integration/edge-cases.test.ts index cfb385e..d1077e6 100644 --- a/native-lib/node/tests/integration/edge-cases.test.ts +++ b/native-lib/node/tests/integration/edge-cases.test.ts @@ -108,9 +108,8 @@ describe("multi-instance lifecycle", () => { // runtime is loaded process-globally (ref-counted, see g_ref_count in // addon.c), so once any good init has run, a later bad-path init is tolerated // rather than re-dlopen'd. Because this shared suite loads dwlib in earlier - // tests, that path can't be asserted here without a dedicated isolated process - // (a follow-up: run it via a separate vitest pool/child so no prior init has - // happened). Verified manually: in a fresh process it throws DataWeaveError. + // tests, that path can't be asserted here; it is covered in a dedicated child + // process in init-bad-path.test.ts. }); describe("concurrent execution", () => { diff --git a/native-lib/node/tests/integration/fixtures/bad-lib-init.cjs b/native-lib/node/tests/integration/fixtures/bad-lib-init.cjs new file mode 100644 index 0000000..e2e4bb4 --- /dev/null +++ b/native-lib/node/tests/integration/fixtures/bad-lib-init.cjs @@ -0,0 +1,33 @@ +// Child-process fixture for the bad-library-path initialization test. +// +// Runs in a FRESH process (spawned by init-bad-path.test.ts) so that no prior +// good initialization has loaded dwlib — the only condition under which a +// bad-path initialize() reliably throws (the native runtime is loaded +// process-globally / ref-counted; see the NOTE in edge-cases.test.ts). +// +// Contract with the parent: +// - Requires the built CommonJS entry at ../../../dist/index.js. +// - On the expected DataWeaveError, prints "OK:" and exits 0. +// - On any other outcome (no throw, wrong error type), prints "FAIL:..." and +// exits 1. A native crash would surface as a non-zero signal exit, which +// the parent also treats as failure. +const path = require("node:path"); + +const { DataWeave, DataWeaveError } = require(path.join(__dirname, "..", "..", "..", "dist", "index.js")); + +const BAD_PATH = process.argv[2] || "/no/such/dwlib-does-not-exist.dylib"; + +try { + const dw = new DataWeave(BAD_PATH); + dw.initialize(); + // Should be unreachable: a bad path in a fresh process must not initialize. + console.log("FAIL:no-throw"); + process.exit(1); +} catch (e) { + if (e instanceof DataWeaveError) { + console.log("OK:" + e.name + ":" + String(e.message)); + process.exit(0); + } + console.log("FAIL:wrong-error:" + (e && e.constructor && e.constructor.name)); + process.exit(1); +} \ No newline at end of file diff --git a/native-lib/node/tests/integration/init-bad-path.test.ts b/native-lib/node/tests/integration/init-bad-path.test.ts new file mode 100644 index 0000000..367a1c5 --- /dev/null +++ b/native-lib/node/tests/integration/init-bad-path.test.ts @@ -0,0 +1,31 @@ +// Asserts that DataWeave.initialize() with a bad/nonexistent dwlib path throws +// a DataWeaveError. This is only reliably observable as the FIRST native +// initialization in a process (the runtime is loaded process-globally and +// ref-counted — see the NOTE in edge-cases.test.ts), so it is verified in a +// dedicated child process rather than in-lane, making it order- and +// pool-configuration-independent. (W-23517830, follow-up from W-23517404.) +import { describe, it, expect } from "vitest"; +import { execFileSync } from "node:child_process"; +import { join } from "node:path"; +import { existsSync } from "node:fs"; + +const FIXTURE = join(__dirname, "fixtures", "bad-lib-init.cjs"); +const DIST_ENTRY = join(__dirname, "..", "..", "dist", "index.js"); + +describe("bad library path initialization (isolated process)", () => { + it("initialize() with a nonexistent library path throws a DataWeaveError", () => { + // The fixture requires the built dist/ entry; nodeTest runs tsc first, but + // guard so a source-only run fails with a clear message instead of a + // confusing child error. + expect(existsSync(DIST_ENTRY), `built entry missing at ${DIST_ENTRY} — run \`npm run build:ts\``).toBe(true); + + // execFileSync throws on a non-zero exit, so a "no throw" / wrong-error / + // native-crash outcome in the child fails this test. + const stdout = execFileSync(process.execPath, [FIXTURE, "/no/such/dwlib-xyz.dylib"], { + encoding: "utf-8", + }); + + expect(stdout).toContain("OK:DataWeaveError"); + expect(stdout).toContain("Failed to"); + }); +}); \ No newline at end of file