@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
129 lines • 6.15 kB
JavaScript
// 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