|
| 1 | +// Probe D — Full serve() -> reinitialize() -> close() lifecycle, standalone (no AVA). |
| 2 | +// |
| 3 | +// Mirrors the first subtest of reinitialize.js against the real graph + BuildServer + |
| 4 | +// Supervisor, but as a plain Node process so the exit code is attributable to this flow |
| 5 | +// alone (AVA is not in the picture). After close() resolves it prints a marker, waits |
| 6 | +// briefly, then exits. |
| 7 | +// |
| 8 | +// - If it crashes 0xC0000005 BEFORE "[probe-serve] closed" -> the crash is during |
| 9 | +// destroy()/teardown while JS is still running. |
| 10 | +// - If it prints "[probe-serve] closed" and "[probe-serve] settled" and THEN the |
| 11 | +// process crashes on exit -> the crash is at process exit with a native handle |
| 12 | +// (parcel watch thread / sqlite mmap) not fully released. |
| 13 | +// - Exit 0 clean -> the isolated lifecycle does not reproduce it; the trigger needs |
| 14 | +// the AVA worker environment (e.g. supertest sockets, the loader, concurrent files). |
| 15 | +// |
| 16 | +// Run from packages/server: node test/probes/probe-serve.mjs |
| 17 | +import path from "node:path"; |
| 18 | +import {fileURLToPath} from "node:url"; |
| 19 | + |
| 20 | +process.env.NODE_ENV = "test"; |
| 21 | +const here = path.dirname(fileURLToPath(import.meta.url)); |
| 22 | +const serverRoot = path.resolve(here, "..", ".."); |
| 23 | +process.chdir(serverRoot); // so ./test/fixtures/application.a resolves like the test |
| 24 | + |
| 25 | +const {serve} = await import(path.resolve(serverRoot, "lib/server.js")); |
| 26 | +const {graphFromPackageDependencies} = await import("@ui5/project/graph"); |
| 27 | +const projectWatcher = await import("@ui5/project/internal/graph/ProjectDefinitionWatcher"); |
| 28 | + |
| 29 | +const buildGraph = () => graphFromPackageDependencies({cwd: "./test/fixtures/application.a"}); |
| 30 | + |
| 31 | +const ui5DataDir = path.resolve("test", "tmp", "buildcache", `probe-serve-${process.pid}`); |
| 32 | +console.log(`[probe-serve] serving (ui5DataDir=${ui5DataDir})`); |
| 33 | +const graph = await buildGraph(); |
| 34 | +const server = await serve(graph, { |
| 35 | + port: 3399, // fixed port; changePortIfInUse bumps it if busy |
| 36 | + changePortIfInUse: true, |
| 37 | + liveReload: false, |
| 38 | + ui5DataDir, |
| 39 | +}, undefined, buildGraph, projectWatcher); |
| 40 | +console.log(`[probe-serve] listening on ${server.port}`); |
| 41 | + |
| 42 | +console.log(`[probe-serve] reinitialize`); |
| 43 | +await server.reinitialize(); |
| 44 | +console.log(`[probe-serve] reinitialized`); |
| 45 | + |
| 46 | +await new Promise((resolve) => server.close(resolve)); |
| 47 | +console.log(`[probe-serve] closed`); |
| 48 | + |
| 49 | +// Hold the process open briefly so an exit-time native crash is clearly separated from |
| 50 | +// the in-flight teardown above. |
| 51 | +await new Promise((r) => setTimeout(r, 1000)); |
| 52 | +console.log(`[probe-serve] settled — process exiting`); |
0 commit comments