@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
140 lines • 7.39 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
import { Flags } from '../../../../src/commands/flags.js';
import { getTestCacheDirectory } from '../../../test-utility.js';
import { container } from 'tsyringe-neo';
import { InjectTokens } from '../../../../src/core/dependency-injection/inject-tokens.js';
import { DeploymentCommandDefinition } from '../../../../src/commands/command-definitions/deployment-command-definition.js';
import { Argv } from '../../../helpers/argv-wrapper.js';
import { NamespaceName } from '../../../../src/types/namespace/namespace-name.js';
import { getEnvironmentVariable } from '../../../../src/core/constants.js';
import { ConsensusCommandDefinition } from '../../../../src/commands/command-definitions/consensus-command-definition.js';
import { Templates } from '../../../../src/core/templates.js';
import { PathEx } from '../../../../src/business/utils/path-ex.js';
import { main } from '../../../../src/index.js';
import fs from 'node:fs';
export class BaseCommandTest {
static newArgv() {
return ['${PATH}/node', '${SOLO_ROOT}/solo.ts'];
}
static optionFromFlag(flag) {
return `--${flag.name}`;
}
static argvPushGlobalFlags(argv, testName, shouldSetTestCacheDirectory = false, shouldSetChartDirectory = false) {
argv.push(BaseCommandTest.optionFromFlag(Flags.devMode), BaseCommandTest.optionFromFlag(Flags.quiet));
const soloChartsDirectory = getEnvironmentVariable('SOLO_CHARTS_DIR');
if (shouldSetChartDirectory && soloChartsDirectory && soloChartsDirectory !== '') {
argv.push(BaseCommandTest.optionFromFlag(Flags.chartDirectory), process.env.SOLO_CHARTS_DIR);
}
if (shouldSetTestCacheDirectory) {
argv.push(BaseCommandTest.optionFromFlag(Flags.cacheDir), getTestCacheDirectory(testName));
}
return argv;
}
/**
* Collects diagnostic logs using the deployment diagnostics command.
* This is a shared helper used by both test patterns.
*/
static async collectDiagnosticLogs(testName, testLogger, deployment) {
try {
testLogger.info(`${testName}: Collecting diagnostic logs...`);
// Create proper Argv object
const argv = Argv.getDefaultArgv(NamespaceName.of(testName), testName);
argv.setArg(Flags.deployment, deployment);
argv.setCommand(DeploymentCommandDefinition.COMMAND_NAME, DeploymentCommandDefinition.DIAGNOSTICS_SUBCOMMAND_NAME, DeploymentCommandDefinition.DIAGNOSTICS_LOGS);
const nodeCmd = container.resolve(InjectTokens.NodeCommand);
await nodeCmd.handlers.logs(argv.build());
testLogger.info(`${testName}: Diagnostic logs collected successfully`);
}
catch (error) {
testLogger.error(`${testName}: Error collecting diagnostic logs: ${error}`);
if (error instanceof Error && error.stack) {
testLogger.error(`${testName}: Stack trace:\n${error.stack}`);
}
}
}
static async collectJavaFlightRecorderLogs(testName, testLogger, deployment, nodeAlias) {
try {
testLogger.info(`${testName}: Collecting jfr logs...`);
// Create proper Argv object
const argv = Argv.getDefaultArgv(NamespaceName.of(testName), testName);
argv.setArg(Flags.deployment, deployment);
argv.setArg(Flags.nodeAlias, nodeAlias);
argv.setCommand(ConsensusCommandDefinition.COMMAND_NAME, ConsensusCommandDefinition.NODE_SUBCOMMAND_NAME, ConsensusCommandDefinition.COLLECT_JFR);
const nodeCmd = container.resolve(InjectTokens.NodeCommand);
await nodeCmd.handlers.collectJavaFlightRecorderLogs(argv.build());
testLogger.info(`${testName}: Java Flight Recorder logs for node ${nodeAlias} collected successfully`);
}
catch (error) {
testLogger.error(`${testName}: Error collecting Java Flight Recorder logs for node ${nodeAlias}: ${error}`);
if (error instanceof Error && error.stack) {
testLogger.error(`${testName}: Stack trace:\n${error.stack}`);
}
}
}
/**
* Sets up an after() hook for diagnostic log collection in E2E tests.
* Call this within your test suite describe block.
*/
static async setupDiagnosticLogCollection(options) {
const { testName, testLogger, deployment } = options;
await BaseCommandTest.collectDiagnosticLogs(testName, testLogger, deployment);
}
/**
* Sets up an after() hook for diagnostic log collection in E2E tests.
* Call this within your test suite describe block.
*/
static setupJavaFlightRecorderLogCollection(options) {
const { testName, testLogger, deployment } = options;
const promises = [];
for (let index = 0; index < options.consensusNodesCount; index++) {
const nodeAlias = Templates.renderNodeAliasFromNumber(index + 1);
promises.push(BaseCommandTest.collectJavaFlightRecorderLogs(testName, testLogger, deployment, nodeAlias));
}
return Promise.all(promises);
}
static async runMainAndCaptureOutputToJson(argv, options) {
const stdoutChunks = [];
const stderrChunks = [];
const outputSubdirectory = options.outputSubdirectory ?? 'command-output';
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
const originalStderrWrite = process.stderr.write.bind(process.stderr);
process.stdout.write = ((chunk, encoding, callback) => {
stdoutChunks.push(typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString(encoding));
if (encoding === undefined) {
return callback ? originalStdoutWrite(chunk, callback) : originalStdoutWrite(chunk);
}
return callback ? originalStdoutWrite(chunk, encoding, callback) : originalStdoutWrite(chunk, encoding);
});
process.stderr.write = ((chunk, encoding, callback) => {
stderrChunks.push(typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString(encoding));
if (encoding === undefined) {
return callback ? originalStderrWrite(chunk, callback) : originalStderrWrite(chunk);
}
return callback ? originalStderrWrite(chunk, encoding, callback) : originalStderrWrite(chunk, encoding);
});
try {
await main(argv);
}
finally {
process.stdout.write = originalStdoutWrite;
process.stderr.write = originalStderrWrite;
}
const outputDirectory = PathEx.join(getTestCacheDirectory(options.testName), outputSubdirectory);
fs.mkdirSync(outputDirectory, { recursive: true });
const outputFilePath = PathEx.join(outputDirectory, options.outputFileName);
const payload = {
timestamp: new Date().toISOString(),
argv,
stdout: stdoutChunks.join(''),
stderr: stderrChunks.join(''),
...options.metadata,
};
fs.writeFileSync(outputFilePath, JSON.stringify(payload, undefined, 2), 'utf8');
return {
stdout: payload.stdout,
stderr: payload.stderr,
outputFilePath,
};
}
}
//# sourceMappingURL=base-command-test.js.map