@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
90 lines • 6.51 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
import { it, describe } from 'mocha';
import { expect } from 'chai';
import { Flags as flags } from '../../../src/commands/flags.js';
import { accountCreationShouldSucceed, balanceQueryShouldSucceed, getNodeAliasesPrivateKeysHash, getTemporaryDirectory, } from '../../test-utility.js';
import { Duration } from '../../../src/core/time/duration.js';
import { AccountBalanceQuery, AccountCreateTransaction, Hbar, HbarUnit, PrivateKey, } from '@hiero-ledger/sdk';
import { sleep } from '../../../src/core/helpers.js';
import { PathEx } from '../../../src/business/utils/path-ex.js';
import { SOLO_LOGS_DIR } from '../../../src/core/constants.js';
import { ConsensusNodeTest } from './tests/consensus-node-test.js';
import { LedgerTest } from './tests/ledger-test.js';
import { ConsensusNodeAddTest } from './tests/consensus-node-add-test.js';
import { main } from '../../../src/index.js';
export function testSeparateNodeAdd(argv, bootstrapResp, namespace, timeout) {
const temporaryDirectory = 'contextDir';
const argvPrepare = argv.clone();
argvPrepare.setArg(flags.outputDir, temporaryDirectory);
const argvExecute = argv.clone();
argvExecute.setArg(flags.inputDir, temporaryDirectory);
const { opts: { k8Factory, accountManager, remoteConfig, logger }, } = bootstrapResp;
describe('Node add via separated commands should success', async () => {
let existingServiceMap;
let existingNodeIdsPrivateKeysHash;
it('cache current version of private keys', async () => {
existingServiceMap = await accountManager.getNodeServiceMap(namespace, remoteConfig.getClusterRefs(), argv.getArg(flags.deployment));
existingNodeIdsPrivateKeysHash = await getNodeAliasesPrivateKeysHash(existingServiceMap, k8Factory, getTemporaryDirectory());
}).timeout(timeout);
it('should succeed with init command', async () => {
await main(LedgerTest.soloLedgerSystemInitArgv(argv.getArg(flags.deployment), argv.getArg(flags.nodeAliasesUnparsed), argv.getArg(flags.clusterRef)));
}).timeout(Duration.ofMinutes(8).toMillis());
it('should add a new node to the network successfully', async () => {
await main(ConsensusNodeAddTest.soloConsensusNodeAddPrepareArgv(argv.getArg(flags.deployment), temporaryDirectory, argv.getArg(flags.cacheDir), {
persistentVolumeClaims: true,
generateGossipKeys: true,
generateTlsKeys: true,
}));
await main(ConsensusNodeAddTest.soloConsensusNodeAddSubmitArgv(argv.getArg(flags.deployment), temporaryDirectory));
await main(ConsensusNodeAddTest.soloConsensusNodeAddExecuteArgv(argv.getArg(flags.deployment), temporaryDirectory, argv.getArg(flags.cacheDir)));
await accountManager.close();
argv.setArg(flags.nodeAliasesUnparsed, 'node1,node2,node3');
}).timeout(Duration.ofMinutes(12).toMillis());
it('should be able to create account after a separated consensus node add commands', async () => {
await main(LedgerTest.soloLedgerAccountCreateArgv(argv.getArg(flags.deployment)));
});
balanceQueryShouldSucceed(accountManager, namespace, remoteConfig, logger);
accountCreationShouldSucceed(accountManager, namespace, remoteConfig, logger);
it('existing nodes private keys should not have changed', async () => {
const currentNodeIdsPrivateKeysHash = await getNodeAliasesPrivateKeysHash(existingServiceMap, k8Factory, getTemporaryDirectory());
for (const [nodeAlias, existingKeyHashMap] of existingNodeIdsPrivateKeysHash.entries()) {
const currentNodeKeyHashMap = currentNodeIdsPrivateKeysHash.get(nodeAlias);
for (const [keyFileName, existingKeyHash] of existingKeyHashMap.entries()) {
expect(`${nodeAlias}:${keyFileName}:${currentNodeKeyHashMap.get(keyFileName)}`).to.equal(`${nodeAlias}:${keyFileName}:${existingKeyHash}`);
}
}
}).timeout(timeout);
it('should save the state, restart node, and preserve account balances', async () => {
// create account before stopping
await accountManager.loadNodeClient(namespace, remoteConfig.getClusterRefs(), argv.getArg(flags.deployment), argv.getArg(flags.forcePortForward));
const privateKey = PrivateKey.generate();
// get random integer between 100 and 1000
const amount = Math.floor(Math.random() * (1000 - 100) + 100);
const newAccount = await new AccountCreateTransaction()
.setKeyWithoutAlias(privateKey.publicKey)
.setInitialBalance(Hbar.from(amount, HbarUnit.Hbar))
.execute(accountManager._nodeClient);
// Get the new account ID
const getReceipt = await newAccount.getReceipt(accountManager._nodeClient);
const accountInfo = {
accountId: getReceipt.accountId.toString(),
balance: amount,
};
// create more transactions to save more round of states
await main(LedgerTest.soloLedgerAccountCreateArgv(argv.getArg(flags.deployment)));
await sleep(Duration.ofSeconds(1));
await main(LedgerTest.soloLedgerAccountCreateArgv(argv.getArg(flags.deployment)));
await main(ConsensusNodeTest.soloConsensusNetworkFreezeArgv(argv.getArg(flags.deployment)));
await main(ConsensusNodeTest.soloConsensusStateDownloadArgv(argv.getArg(flags.deployment), argv.getArg(flags.nodeAliasesUnparsed)));
await main(ConsensusNodeTest.soloConsensusNodeRestartArgv(argv.getArg(flags.deployment)));
argv.setArg(flags.stateFile, PathEx.joinWithRealPath(SOLO_LOGS_DIR, namespace.name, 'network-node1-0-state.zip'));
// check balance of accountInfo.accountId
await accountManager.loadNodeClient(namespace, remoteConfig.getClusterRefs(), argv.getArg(flags.deployment), argv.getArg(flags.forcePortForward));
const balance = await new AccountBalanceQuery()
.setAccountId(accountInfo.accountId)
.execute(accountManager._nodeClient);
expect(balance.hbars).to.be.eql(Hbar.from(accountInfo.balance, HbarUnit.Hbar));
}).timeout(Duration.ofMinutes(10).toMillis());
}).timeout(Duration.ofMinutes(3).toMillis());
}
//# sourceMappingURL=separate-node-add.test.js.map