diff --git a/package-lock.json b/package-lock.json index a5b8c017e..013d739ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ ], "dependencies": { "@golem-sdk/pino-logger": "^1.1.0", - "@rollup/rollup-win32-x64-msvc": "^4", "async-lock": "^1.4.1", "async-retry": "^1.3.3", "axios": "^1.6.7", @@ -56,6 +55,7 @@ "@types/tmp": "^0.2.6", "@types/uuid": "^10.0.0", "@types/ws": "^8.5.10", + "@types/wtfnode": "^0.7.3", "@typescript-eslint/eslint-plugin": "^7.1.0", "@typescript-eslint/parser": "^7.1.0", "buffer": "^6.0.3", @@ -85,7 +85,8 @@ "typedoc-plugin-markdown": "^3.17.1", "typedoc-plugin-merge-modules": "^5.1.0", "typedoc-theme-hierarchy": "4.1.2", - "typescript": "^5.3.3" + "typescript": "^5.3.3", + "wtfnode": "^0.9.3" }, "engines": { "node": ">=18.0.0" @@ -3940,6 +3941,12 @@ "@types/node": "*" } }, + "node_modules/@types/wtfnode": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@types/wtfnode/-/wtfnode-0.7.3.tgz", + "integrity": "sha512-UMkHpx+o2xRWLJ7PmT3bBzvIA9/0oFw80oPtY/xO4jfdq+Gznn4wP7K9B/JjMxyxy+wF+5oRPIykxeBbEDjwRg==", + "dev": true + }, "node_modules/@types/yargs": { "version": "17.0.32", "dev": true, @@ -18974,6 +18981,15 @@ } } }, + "node_modules/wtfnode": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/wtfnode/-/wtfnode-0.9.3.tgz", + "integrity": "sha512-MXjgxJovNVYUkD85JBZTKT5S5ng/e56sNuRZlid7HcGTNrIODa5UPtqE3i0daj7fJ2SGj5Um2VmiphQVyVKK5A==", + "dev": true, + "bin": { + "wtfnode": "proxy.js" + } + }, "node_modules/xml": { "version": "1.0.1", "dev": true, diff --git a/package.json b/package.json index cdaaf7888..544345c8b 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,9 @@ "typedoc-plugin-markdown": "^3.17.1", "typedoc-plugin-merge-modules": "^5.1.0", "typedoc-theme-hierarchy": "4.1.2", - "typescript": "^5.3.3" + "typescript": "^5.3.3", + "@types/wtfnode": "^0.7.3", + "wtfnode": "^0.9.3" }, "optionalDependencies": { "@rollup/rollup-darwin-x64": "^4", diff --git a/src/golem-network/golem-network.ts b/src/golem-network/golem-network.ts index acdb784db..076735c19 100644 --- a/src/golem-network/golem-network.ts +++ b/src/golem-network/golem-network.ts @@ -1,3 +1,4 @@ +import * as wtf from "wtfnode"; import { anyAbortSignal, createAbortSignalFromTimeout, defaultLogger, isNode, Logger, YagnaApi } from "../shared/utils"; import { Demand, @@ -362,6 +363,9 @@ export class GolemNetwork { * @return Resolves when all shutdown steps are completed */ async disconnect() { + setTimeout(() => { + wtf.dump(); + }, 33_333); if (this.disconnectPromise) { return this.disconnectPromise; } diff --git a/tests/examples/examples.test.ts b/tests/examples/examples.test.ts index b49898c74..bd09c4d85 100644 --- a/tests/examples/examples.test.ts +++ b/tests/examples/examples.test.ts @@ -2,7 +2,6 @@ import { spawn } from "child_process"; import { dirname, basename, resolve } from "path"; import chalk from "chalk"; import testExamples from "./examples.json"; - const criticalLogsRegExp = [ /GolemInternalError/, /GolemPlatformError/, @@ -25,15 +24,43 @@ async function test(cmd: string, path: string, args: string[] = [], timeout = 36 const file = basename(path); const cwd = dirname(path); const env = { ...process.env, DEBUG: "golem-js:*" }; - const spawnedExample = spawn(cmd, [file, ...args], { cwd, env }); + const spawnedExample = spawn(cmd, [file, ...args], { cwd, env, stdio: ["ignore", "pipe", "pipe"] }); spawnedExample.stdout?.setEncoding("utf-8"); spawnedExample.stderr?.setEncoding("utf-8"); let error = ""; const timeoutId = setTimeout(() => { error = `Test timeout was reached after ${timeout} seconds.`; + console.log({ + error, + connected: spawnedExample.connected, + code: spawnedExample.exitCode, + signal: spawnedExample.signalCode, + pid: spawnedExample.pid, + eventNames: spawnedExample.eventNames(), + }); spawnedExample.kill(); }, timeout * 1000); return new Promise((res, rej) => { + let isFinishing = false; + const finishTest = (code?: number, signal?: string) => { + if (isFinishing) { + console.log("Test finishing has already been triggered by another event"); + return; + } + console.log(`Subprocess with test "${file}" exited with code ${code}, signal ${signal}`); + isFinishing = true; + spawnedExample.removeAllListeners(); + spawnedExample.stdout.removeAllListeners(); + spawnedExample.stderr.removeAllListeners(); + clearTimeout(timeoutId); + if (!error && !code) return res(true); + rej(`Test example "${file}" failed. ${error}`); + }; + spawnedExample.on("exit", finishTest); + spawnedExample.on("error", (err) => { + error = `The test ended with an error: ${err}`; + spawnedExample.kill(); + }); const assertLogs = (data: string) => { console.log(data.trim()); const logWithoutColors = data.replace( @@ -47,10 +74,6 @@ async function test(cmd: string, path: string, args: string[] = [], timeout = 36 }; spawnedExample.stdout?.on("data", assertLogs); spawnedExample.stderr?.on("data", assertLogs); - spawnedExample.on("close", (code) => { - if (!error && !code) return res(true); - rej(`Test example "${file}" failed. ${error}`); - }); }).finally(() => { clearTimeout(timeoutId); spawnedExample.kill("SIGKILL");