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