UNPKG

@hashgraph/solo

Version:

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

129 lines 6.15 kB
// SPDX-License-Identifier: Apache-2.0 import { describe, it } from 'mocha'; import { expect } from 'chai'; import sinon from 'sinon'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { NodeCommandTasks } from '../../../../src/commands/node/tasks.js'; import { NamespaceName } from '../../../../src/types/namespace/namespace-name.js'; import * as constants from '../../../../src/core/constants.js'; function createNodeCommandTasksWithPvcData(persistentVolumeClaimsByContext) { const nodeCommandTasks = Object.create(NodeCommandTasks.prototype); nodeCommandTasks.k8Factory = { getK8: (context) => ({ pvcs: () => ({ list: async () => persistentVolumeClaimsByContext[context] ?? [], }), }), }; return nodeCommandTasks; } function invokeValidateNodePvcsForLocalBuildPath(nodeCommandTasks, contexts) { const validatorFunction = nodeCommandTasks.validateNodePvcsForLocalBuildPath; return validatorFunction.call(nodeCommandTasks, NamespaceName.of('solo'), contexts); } describe('NodeCommandTasks local build path PVC validation', () => { it('throws when local build path is used without node PVCs', async () => { const nodeCommandTasks = createNodeCommandTasksWithPvcData({ 'kind-solo': [], }); await expect(invokeValidateNodePvcsForLocalBuildPath(nodeCommandTasks, ['kind-solo'])).to.be.rejectedWith('Redeploy the consensus network with --pvcs true'); }); it('passes when node PVCs exist for each context', async () => { const nodeCommandTasks = createNodeCommandTasksWithPvcData({ 'kind-alpha': ['data-node1'], 'kind-beta': ['data-node2'], }); await expect(invokeValidateNodePvcsForLocalBuildPath(nodeCommandTasks, ['kind-alpha', 'kind-beta'])).to.eventually .be.fulfilled; }); }); describe('NodeCommandTasks gossipFqdnRestricted resolution', () => { const configMapFalseData = { data: { [constants.APPLICATION_PROPERTIES]: 'nodes.gossipFqdnRestricted=false\n' }, }; const emptyConfigMapData = { data: {} }; function invokeParseGossipFqdnRestricted(nodeCommandTasks, applicationPropertiesText) { const parserFunction = nodeCommandTasks.parseGossipFqdnRestricted; return parserFunction.call(nodeCommandTasks, applicationPropertiesText); } function invokeGetGossipFqdnRestricted(nodeCommandTasks, config, k8) { const getterFunction = nodeCommandTasks.getGossipFqdnRestricted; return getterFunction.call(nodeCommandTasks, config, k8); } it('parses true/false values with surrounding whitespace', () => { const nodeCommandTasks = Object.create(NodeCommandTasks.prototype); expect(invokeParseGossipFqdnRestricted(nodeCommandTasks, 'nodes.gossipFqdnRestricted=true')).to.equal(true); expect(invokeParseGossipFqdnRestricted(nodeCommandTasks, ' nodes.gossipFqdnRestricted = false ')).to.equal(false); }); it('prefers ConfigMap value over staged application.properties', async () => { const nodeCommandTasks = Object.create(NodeCommandTasks.prototype); const stagingDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'gossip-fqdn-configmap-')); const templatesDirectory = path.join(stagingDirectory, 'templates'); fs.mkdirSync(templatesDirectory, { recursive: true }); fs.writeFileSync(path.join(templatesDirectory, constants.APPLICATION_PROPERTIES), 'nodes.gossipFqdnRestricted=true\n'); const k8 = { configMaps: () => ({ read: async () => configMapFalseData, }), }; const config = { namespace: NamespaceName.of('solo'), stagingDir: stagingDirectory, }; try { expect(await invokeGetGossipFqdnRestricted(nodeCommandTasks, config, k8)).to.equal(false); } finally { fs.rmSync(stagingDirectory, { recursive: true, force: true }); } }); it('falls back to staged application.properties when ConfigMap is unavailable', async () => { const nodeCommandTasks = Object.create(NodeCommandTasks.prototype); const stagingDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'gossip-fqdn-staged-')); const templatesDirectory = path.join(stagingDirectory, 'templates'); fs.mkdirSync(templatesDirectory, { recursive: true }); fs.writeFileSync(path.join(templatesDirectory, constants.APPLICATION_PROPERTIES), 'nodes.gossipFqdnRestricted=false\n'); const k8 = { configMaps: () => ({ read: async () => { throw new Error('config map missing'); }, }), }; const config = { namespace: NamespaceName.of('solo'), stagingDir: stagingDirectory, }; try { expect(await invokeGetGossipFqdnRestricted(nodeCommandTasks, config, k8)).to.equal(false); } finally { fs.rmSync(stagingDirectory, { recursive: true, force: true }); } }); it('defaults to true when neither ConfigMap nor staged file provides a value', async () => { const nodeCommandTasks = Object.create(NodeCommandTasks.prototype); const stagingDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'gossip-fqdn-default-')); const k8 = { configMaps: () => ({ read: async () => emptyConfigMapData, }), }; const config = { namespace: NamespaceName.of('solo'), stagingDir: stagingDirectory, }; const existsSyncStub = sinon.stub(fs, 'existsSync').returns(false); try { expect(await invokeGetGossipFqdnRestricted(nodeCommandTasks, config, k8)).to.equal(true); expect(existsSyncStub.calledOnce).to.equal(true); } finally { sinon.restore(); fs.rmSync(stagingDirectory, { recursive: true, force: true }); } }); }); //# sourceMappingURL=local-build-path-pvc-validation.test.js.map