UNPKG

@hashgraph/solo

Version:

An opinionated CLI tool to deploy and manage private Hedera Networks.

142 lines 7.34 kB
// SPDX-License-Identifier: Apache-2.0 import sinon from 'sinon'; import { describe, it, beforeEach, afterEach } from 'mocha'; import { expect } from 'chai'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { Flags as flags } from '../../../src/commands/flags.js'; import * as constants from '../../../src/core/constants.js'; import { TssSchema } from '../../../src/data/schema/model/solo/tss-schema.js'; import { WrapsSchema } from '../../../src/data/schema/model/solo/wraps-schema.js'; import { container } from 'tsyringe-neo'; import { resetForTest } from '../../test-container.js'; import { InjectTokens } from '../../../src/core/dependency-injection/inject-tokens.js'; import { Argv } from '../../helpers/argv-wrapper.js'; import { ValueContainer } from '../../../src/core/dependency-injection/value-container.js'; import { SoloError } from '../../../src/core/errors/solo-error.js'; import { PathEx } from '../../../src/business/utils/path-ex.js'; describe('NodeCommandTasks.addWrapsLib', () => { let configManager; let nodeCommandTasks; let sourceDirectory; let extractedDirectory; let downloaderStub; let zippyStub; const allowedFiles = ['decider_pp.bin', 'decider_vp.bin', 'nova_pp.bin', 'nova_vp.bin']; beforeEach(async () => { sourceDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'wraps-test-')); extractedDirectory = PathEx.join(constants.SOLO_CACHE_DIR, 'wraps-v0.2.0'); // Ensure parent cache directory exists if (!fs.existsSync(constants.SOLO_CACHE_DIR)) { fs.mkdirSync(constants.SOLO_CACHE_DIR, { recursive: true }); } // Clean up extractedDirectory if it exists from a previous test if (fs.existsSync(extractedDirectory)) { fs.rmSync(extractedDirectory, { recursive: true, force: true }); } downloaderStub = { fetchPackage: sinon.stub().resolves() }; zippyStub = { untar: sinon.stub() }; const remoteConfigStub = { configuration: { state: { wrapsEnabled: true } }, isLoaded: sinon.stub().returns(true), }; const containerOverrides = new Map([ [InjectTokens.PackageDownloader, new ValueContainer(InjectTokens.PackageDownloader, downloaderStub)], [InjectTokens.Zippy, new ValueContainer(InjectTokens.Zippy, zippyStub)], [ InjectTokens.RemoteConfigRuntimeState, new ValueContainer(InjectTokens.RemoteConfigRuntimeState, remoteConfigStub), ], ]); resetForTest(undefined, undefined, true, containerOverrides); configManager = container.resolve(InjectTokens.ConfigManager); nodeCommandTasks = container.resolve(InjectTokens.NodeCommandTasks); // Load the config sources so TSS/WRAPS values are available via ConfigProvider const configProvider = container.resolve(InjectTokens.ConfigProvider); await configProvider.config().refresh(); }); afterEach(() => { sinon.restore(); if (fs.existsSync(sourceDirectory)) { fs.rmSync(sourceDirectory, { recursive: true, force: true }); } if (fs.existsSync(extractedDirectory)) { fs.rmSync(extractedDirectory, { recursive: true, force: true }); } }); it('should copy allowed .bin files from wrapsKeyPath to cache directory', async () => { for (const file of allowedFiles) { fs.writeFileSync(path.join(sourceDirectory, file), `content-${file}`); } const argv = Argv.initializeEmpty(); argv.setArg(flags.wrapsKeyPath, sourceDirectory); configManager.update(argv.build()); const listrTask = nodeCommandTasks.addWrapsLib(); await listrTask.task({ config: { consensusNodes: [] } }, {}); const copiedFiles = fs.readdirSync(extractedDirectory); expect(copiedFiles).to.have.members(allowedFiles); for (const file of allowedFiles) { const content = fs.readFileSync(path.join(extractedDirectory, file), 'utf8'); expect(content).to.equal(`content-${file}`); } }); it('should ignore non-allowed files in wrapsKeyPath', async () => { const extraFiles = ['README.md', 'extra.bin', 'config.json']; for (const file of [...allowedFiles, ...extraFiles]) { fs.writeFileSync(path.join(sourceDirectory, file), `content-${file}`); } const argv = Argv.initializeEmpty(); argv.setArg(flags.wrapsKeyPath, sourceDirectory); configManager.update(argv.build()); const listrTask = nodeCommandTasks.addWrapsLib(); await listrTask.task({ config: { consensusNodes: [] } }, {}); const copiedFiles = fs.readdirSync(extractedDirectory); expect(copiedFiles).to.have.members(allowedFiles); for (const extra of extraFiles) { expect(copiedFiles).to.not.include(extra); } }); it('should throw SoloError for non-existent wrapsKeyPath', async () => { const argv = Argv.initializeEmpty(); argv.setArg(flags.wrapsKeyPath, '/this/path/does/not/exist'); configManager.update(argv.build()); const listrTask = nodeCommandTasks.addWrapsLib(); try { await listrTask.task({ config: { consensusNodes: [] } }, {}); expect.fail('Expected SoloError to be thrown'); } catch (error) { expect(error).to.be.instanceOf(SoloError); expect(error.message).to.include('WRAPs key path does not exist'); } }); it('should create destination directory if missing', async () => { fs.writeFileSync(path.join(sourceDirectory, 'decider_pp.bin'), 'data'); expect(fs.existsSync(extractedDirectory)).to.be.false; const argv = Argv.initializeEmpty(); argv.setArg(flags.wrapsKeyPath, sourceDirectory); configManager.update(argv.build()); const listrTask = nodeCommandTasks.addWrapsLib(); await listrTask.task({ config: { consensusNodes: [] } }, {}); expect(fs.existsSync(extractedDirectory)).to.be.true; expect(fs.readdirSync(extractedDirectory)).to.include('decider_pp.bin'); }); it('should fall back to download when wrapsKeyPath is not set', async () => { const argv = Argv.initializeEmpty(); configManager.update(argv.build()); const listrTask = nodeCommandTasks.addWrapsLib(); await listrTask.task({ config: { consensusNodes: [] } }, {}); expect(downloaderStub.fetchPackage.calledOnce).to.be.true; expect(zippyStub.untar.calledOnce).to.be.true; }); }); describe('TssSchema WRAPS defaults', () => { it('allowedKeyFiles default should contain the expected file names', () => { const wraps = new WrapsSchema('wraps-v0.2.0', 'wraps-v0.2.0', 'decider_pp.bin,decider_vp.bin,nova_pp.bin,nova_vp.bin', 'https://builds.hedera.com/tss/hiero/wraps/v0.2/wraps-v0.2.0.tar.gz'); const tss = new TssSchema(undefined, undefined, undefined, undefined, undefined, wraps); const files = (tss.wraps?.allowedKeyFiles ?? '').split(','); expect(files).to.have.members(['decider_pp.bin', 'decider_vp.bin', 'nova_pp.bin', 'nova_vp.bin']); }); }); //# sourceMappingURL=wraps-key-path.test.js.map