From e3fcf82df18e7ee6e172575063544ba9dcfc7099 Mon Sep 17 00:00:00 2001 From: ndrpp Date: Mon, 12 Jan 2026 13:32:29 +0200 Subject: [PATCH 1/2] feat: display stderr logs in unit tests --- src/commands.ts | 77 ++++++++++++++++++++-------------- test/interactivePublishFlow.ts | 17 +++++--- test/setup.test.ts | 15 ++++--- test/util.ts | 5 ++- 4 files changed, 70 insertions(+), 44 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 112e8e2..c25d3e0 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -246,6 +246,7 @@ export class Commands { } } + public async initializeCompute(args: string[]) { const inputDatasetsString = args[1]; let inputDatasets = []; @@ -294,7 +295,6 @@ export class Commands { if (ddos.length > 0) { providerURI = ddos[0].services[0].serviceEndpoint; } - const algoDdo = await this.aquarius.waitForIndexer( args[2], null, @@ -517,7 +517,7 @@ export class Commands { inputDatasets.length > 0 && (ddos.length <= 0 || ddos.length != inputDatasets.length) ) { - console.error("Not all the data ddos are available."); + console.error(`DDO count mismatch. Expected: ${inputDatasets.length}, Got: ${ddos.length}`); return; } let providerURI = this.oceanNodeUrl; @@ -532,8 +532,7 @@ export class Commands { this.indexingParams.maxRetries ); if (!algoDdo) { - console.error( - "Error fetching DDO " + args[1] + ". Does this asset exists?" + console.error( "FAILED to fetch algorithm DDO " + args[2] + ". Does this asset exists?" ); return; } @@ -544,10 +543,11 @@ export class Commands { if (!computeEnvs || computeEnvs.length < 1) { console.error( - "Error fetching compute environments. No compute environments available." + "FAILED - No compute environments available from provider" ); return; } + const computeEnvID = args[3]; // NO chainId needed anymore (is not part of ComputeEnvironment spec anymore) // const chainComputeEnvs = computeEnvs[computeEnvID]; // was algoDdo.chainId @@ -563,9 +563,9 @@ export class Commands { } if (!computeEnv || !computeEnvID) { console.error( - "Error fetching compute environment. No compute environment matches id: ", - computeEnvID + "FAILED - No compute environment matches id: " + computeEnvID ); + console.error("Available environment IDs: ", computeEnvs.map(e => e.id)); return; } @@ -615,7 +615,7 @@ export class Commands { ); if (!algo.transferTxId) { console.error( - "Error ordering compute for algorithm with DID: " + + "FAILED - Error ordering compute for algorithm with DID: " + args[2] + ". Do you have enough tokens?" ); @@ -637,8 +637,8 @@ export class Commands { ); if (!assets[i].transferTxId) { console.error( - "Error ordering dataset with DID: " + - assets[i] + + "FAILED - Error ordering dataset with DID: " + + ddos[i].id + ". Do you have enough tokens?" ); return; @@ -729,7 +729,7 @@ export class Commands { getAddress(parsedProviderInitializeComputeJob.payment.escrowAddress), this.signer ) - console.log("Verifying payment..."); + console.log("Verifying escrow payment..."); await new Promise(resolve => setTimeout(resolve, 3000)) const validationEscrow = await escrow.verifyFundsForEscrowPayment( @@ -742,16 +742,15 @@ export class Commands { ) if (validationEscrow.isValid === false) { console.error( - "Error starting compute job dataset DID " + + "FAILED - Escrow funds check failed for dataset DID " + args[1] + " and algorithm DID " + args[2] + - " because escrow funds check failed: " + " because: " + validationEscrow.message ); return; } - console.log("Starting compute job using provider: ", providerURI); const additionalDatasets = assets.length > 1 ? assets.slice(1) : null; @@ -781,23 +780,37 @@ export class Commands { metadataUri: await getMetadataURI(), }; - const computeJobs = await ProviderInstance.computeStart( - providerURI, - this.signer, - computeEnv.id, - assets, // assets[0] // only c2d v1, - algo, - supportedMaxJobDuration, - paymentToken, - JSON.parse(resources), - Number((await this.signer.provider.getNetwork()).chainId), - null, - null, - // additionalDatasets, only c2d v1 - output - ); + let computeJobs; + try { + computeJobs = await ProviderInstance.computeStart( + providerURI, + this.signer, + computeEnv.id, + assets, // assets[0] // only c2d v1, + algo, + supportedMaxJobDuration, + paymentToken, + JSON.parse(resources), + Number((await this.signer.provider.getNetwork()).chainId), + null, + null, + // additionalDatasets, only c2d v1 + output + ); + } catch (error) { + // Check for specific error types + if ((error as any)?.code === 'ECONNREFUSED') { + console.log("DEBUG: ⚠️ CONNECTION REFUSED - Ocean node may not be running at: ", providerURI); + } else if ((error as any)?.code === 'ETIMEDOUT') { + console.log("DEBUG: ⚠️ TIMEOUT - Ocean node did not respond in time"); + } else if (error?.message?.includes('fetch')) { + console.log("DEBUG: ⚠️ NETWORK ERROR - Failed to make HTTP request"); + } - console.log("computeJobs: ", computeJobs); + console.log("Error calling ProviderInstance.computeStart: ", error); + return; + } + console.log("DEBUG: Full response: ", JSON.stringify(computeJobs, null, 2)); if (computeJobs && computeJobs[0]) { const { jobId, payment } = computeJobs[0]; @@ -1466,13 +1479,13 @@ export class Commands { const initialUsers = args[3] ? args[3].split(',').map(u => u.trim()) : []; if (!name || !symbol) { - console.error(chalk.red('Name and symbol are required')); + console.error('Name and symbol are required'); return; } const config = await getConfigByChainId(Number(this.config.chainId)); if (!config.AccessListFactory) { - console.error(chalk.red('Access list factory not found. Check local address.json file')); + console.error('Access list factory not found. Check local address.json file'); return; } const accessListFactory = new AccesslistFactory( diff --git a/test/interactivePublishFlow.ts b/test/interactivePublishFlow.ts index b8cd82e..8ca1578 100644 --- a/test/interactivePublishFlow.ts +++ b/test/interactivePublishFlow.ts @@ -7,13 +7,13 @@ import { fileURLToPath } from 'url' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) -describe("Ocean CLI Interactive Publishing", function() { +describe("Ocean CLI Interactive Publishing", function () { this.timeout(120000); // Set a longer timeout to allow for user input simulation const projectRoot = path.resolve(__dirname, ".."); let publishedDid: string; - it("should publish an asset using 'npm run cli start' interactive flow", function(done) { + it("should publish an asset using 'npm run cli start' interactive flow", function (done) { process.env.PRIVATE_KEY = "0x1d751ded5a32226054cd2e71261039b65afb9ee1c746d055dd699b1150a5befc"; process.env.RPC = "http://127.0.0.1:8545"; process.env.NODE_URL = "http://127.0.0.1:8001"; @@ -56,12 +56,16 @@ describe("Ocean CLI Interactive Publishing", function() { fullOutput += data.toString(); }); + child.stderr?.on('data', (data) => { + console.error(data.toString()); + }); + child.on('close', (code) => { try { expect(code).to.equal(0); expect(fullOutput).to.contain("Asset successfully published with DID:"); expect(fullOutput).to.contain("Metadata successfully updated for DID:"); - + const match = fullOutput.match(/did:op:[a-f0-9]{64}/); if (match) { publishedDid = match[0]; @@ -77,8 +81,11 @@ describe("Ocean CLI Interactive Publishing", function() { }); }); - it("should get DDO using 'npm run cli getDDO' for the published asset", function(done) { - exec(`npm run cli getDDO ${publishedDid}`, { cwd: projectRoot }, (error, stdout) => { + it("should get DDO using 'npm run cli getDDO' for the published asset", function (done) { + exec(`npm run cli getDDO ${publishedDid}`, { cwd: projectRoot }, (error, stdout, stderr) => { + if (stderr) { + console.error(stderr); + } try { expect(stdout).to.contain(`${publishedDid}`); expect(stdout).to.contain("https://w3id.org/did/v1"); diff --git a/test/setup.test.ts b/test/setup.test.ts index 8702483..d7bf752 100644 --- a/test/setup.test.ts +++ b/test/setup.test.ts @@ -7,11 +7,11 @@ import { fileURLToPath } from 'url' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) -describe("Ocean CLI Setup", function() { +describe("Ocean CLI Setup", function () { process.env.AVOID_LOOP_RUN = "true"; this.timeout(20000); // Set a longer timeout to allow the command to execute - it("should return a valid response for 'npm run cli h'", function(done) { + it("should return a valid response for 'npm run cli h'", function (done) { // Ensure the command is run from the project root directory const projectRoot = path.resolve(__dirname, ".."); @@ -19,7 +19,10 @@ describe("Ocean CLI Setup", function() { process.env.PRIVATE_KEY = "0x1d751ded5a32226054cd2e71261039b65afb9ee1c746d055dd699b1150a5befc"; process.env.RPC = "http://127.0.0.1:8545"; - exec("npm run cli h", { cwd: projectRoot }, (error, stdout) => { + exec("npm run cli h", { cwd: projectRoot }, (error, stdout, stderr) => { + if (stderr) { + console.error(stderr); + } // Check the stdout for the expected response try { expect(stdout).to.contain("help|h"); @@ -69,7 +72,7 @@ describe("Ocean CLI Setup", function() { }); // Additional comprehensive tests - it("should return an error message when only MNEMONIC is set", function(done) { + it("should return an error message when only MNEMONIC is set", function (done) { const projectRoot = path.resolve(__dirname, ".."); process.env.MNEMONIC = "your-valid-mnemonic-here"; delete process.env.PRIVATE_KEY; @@ -85,7 +88,7 @@ describe("Ocean CLI Setup", function() { }); }); - it("should return an error message when only PRIVATE_KEY is set", function(done) { + it("should return an error message when only PRIVATE_KEY is set", function (done) { const projectRoot = path.resolve(__dirname, ".."); delete process.env.MNEMONIC; process.env.PRIVATE_KEY = "0x1d751ded5a32226054cd2e71261039b65afb9ee1c746d055dd699b1150a5befc"; @@ -101,7 +104,7 @@ describe("Ocean CLI Setup", function() { }); }); - it("should return an error message when only RPC is set", function(done) { + it("should return an error message when only RPC is set", function (done) { const projectRoot = path.resolve(__dirname, ".."); delete process.env.MNEMONIC; delete process.env.PRIVATE_KEY; diff --git a/test/util.ts b/test/util.ts index a00cfcc..ff93989 100644 --- a/test/util.ts +++ b/test/util.ts @@ -16,7 +16,10 @@ export const projectRoot = path.resolve(__dirname, ".."); export const runCommand = async (command: string): Promise => { console.log(`\n[CMD]: ${command}`); try { - const { stdout } = await execPromise(command, { cwd: projectRoot }); + const { stdout, stderr } = await execPromise(command, { cwd: projectRoot }); + if (stderr) { + console.error(`[STDERR]:\n${stderr}`); + } console.log(`[OUTPUT]:\n${stdout}`); return stdout; } catch (error: any) { From 412dceb6e7a90abee5a82883cf388656ff46100b Mon Sep 17 00:00:00 2001 From: ndrpp Date: Mon, 12 Jan 2026 13:46:12 +0200 Subject: [PATCH 2/2] chore: cleanup --- src/commands.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index c25d3e0..df79bef 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -532,8 +532,7 @@ export class Commands { this.indexingParams.maxRetries ); if (!algoDdo) { - console.error( "FAILED to fetch algorithm DDO " + args[2] + ". Does this asset exists?" - ); + console.error("FAILED to fetch algorithm DDO " + args[2] + ". Does this asset exists?"); return; } @@ -810,7 +809,6 @@ export class Commands { console.log("Error calling ProviderInstance.computeStart: ", error); return; } - console.log("DEBUG: Full response: ", JSON.stringify(computeJobs, null, 2)); if (computeJobs && computeJobs[0]) { const { jobId, payment } = computeJobs[0];