From f323ca709c376a9b8aa1f36a0a52961eacb19a7a Mon Sep 17 00:00:00 2001 From: Jeromy Cannon Date: Mon, 23 Dec 2024 19:59:26 +0000 Subject: [PATCH] Squashed commit of the following: commit 24269fea9e4ead36cd2881e0bf176308e5e9d6ef Author: Ivo Yankov Date: Fri Dec 20 11:03:26 2024 +0200 wip: attempting to fix tests Signed-off-by: Ivo Yankov commit 7698f168dbdcebb3a5e940938f78cebcc16a357d Author: Ivo Yankov Date: Thu Dec 19 15:41:38 2024 +0200 chore: format Signed-off-by: Ivo Yankov commit 507a0817fe6686fe5405d0ba3b5f9ed9072d1032 Author: Ivo Yankov Date: Thu Dec 19 14:53:36 2024 +0200 feat: implement IOC in core classes Signed-off-by: Ivo Yankov commit c582f12730050e2cf7e82857edce680fd849501c Author: Ivo Yankov Date: Wed Dec 18 17:32:22 2024 +0200 wip: refactoring dependencies Signed-off-by: Ivo Yankov Signed-off-by: Jeromy Cannon --- eslint.config.mjs | 7 -- package-lock.json | 13 ++++ package.json | 1 + src/commands/base.ts | 5 +- src/core/account_manager.ts | 13 ++-- src/core/certificate_manager.ts | 20 +++--- src/core/chart_manager.ts | 15 ++--- src/core/config/local_config.ts | 11 ++-- .../config/remote/remote_config_manager.ts | 18 ++--- src/core/config_manager.ts | 10 +-- src/core/container_init.ts | 60 +++++++++++++++++ .../dependency_managers/dependency_manager.ts | 20 +++--- .../helm_dependency_manager.ts | 23 +++---- src/core/helm.ts | 12 ++-- src/core/k8.ts | 15 ++--- src/core/key_manager.ts | 8 +-- src/core/lease/interval_lease_renewal.ts | 2 + src/core/lease/lease_manager.ts | 35 ++++------ src/core/logging.ts | 2 + src/core/package_downloader.ts | 8 +-- src/core/platform_installer.ts | 26 +++----- src/core/profile_manager.ts | 15 ++--- src/core/shell_runner.ts | 8 +-- src/core/zippy.ts | 8 +-- src/index.ts | 43 ++++++------ test/e2e/e2e_node_util.ts | 3 +- test/e2e/integration/commands/init.test.ts | 29 +++++---- .../integration/core/chart_manager.test.ts | 4 +- .../helm_dependency_manager.test.ts | 26 ++++---- test/e2e/integration/core/k8_e2e.test.ts | 5 +- test/e2e/integration/core/lease.test.ts | 5 +- .../integration/core/lease_renewal.test.ts | 7 +- .../core/remote_config_manager.test.ts | 7 +- .../core/remote_config_validator.test.ts | 5 +- test/setup.ts | 4 ++ test/test_container.ts | 65 +++++++++++++++++++ test/test_util.ts | 43 ++++++------ test/unit/commands/base.test.ts | 49 +++++++------- test/unit/commands/cluster.test.ts | 8 ++- test/unit/commands/context.test.ts | 12 ++-- test/unit/commands/network.test.ts | 24 ++++--- test/unit/core/certificate_manager.test.ts | 7 +- test/unit/core/config_manager.test.ts | 11 ++-- .../dependency_manager.test.ts | 13 ++-- test/unit/core/helm.test.ts | 2 +- test/unit/core/k8.test.ts | 5 +- test/unit/core/key_manager.test.ts | 3 +- test/unit/core/local_config.test.ts | 12 ++-- test/unit/core/platform_installer.test.ts | 16 +++-- test/unit/core/profile_manager.test.ts | 34 ++++++---- test/unit/core/shell_runner.test.ts | 2 +- 51 files changed, 467 insertions(+), 332 deletions(-) create mode 100644 src/core/container_init.ts create mode 100644 test/test_container.ts diff --git a/eslint.config.mjs b/eslint.config.mjs index 33b92c046..34e6011a2 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -147,13 +147,6 @@ export default [ '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/ban-types': 'off', '@typescript-eslint/camelcase': 'off', - '@typescript-eslint/consistent-type-imports': [ - // optional: assists in reducing circular dependencies - 'error', - { - fixStyle: 'inline-type-imports', - }, - ], '@typescript-eslint/no-explicit-any': 'warn', // TODO remove (771 errors) '@typescript-eslint/no-this-alias': [ 'error', diff --git a/package-lock.json b/package-lock.json index 36b5f440d..c33ea069e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "stream-buffers": "^3.0.3", "tar": "^7.4.3", "tsx": "^4.19.2", + "tsyringe-neo": "^5.1.0", "uuid": "^11.0.3", "validator": "^13.12.0", "winston": "^3.17.0", @@ -12110,6 +12111,18 @@ "node": ">= 6.0.0" } }, + "node_modules/tsyringe-neo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/tsyringe-neo/-/tsyringe-neo-5.1.0.tgz", + "integrity": "sha512-x6QAckY85YLGE980TIR5Xle3s76nhBNYu0kr6UlLAWiPqt4S6PgbbvNV4cjZlItv3ka8adcGYG2Wy/I2yxcqdg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.3" + }, + "engines": { + "node": ">= 18.0.0" + } + }, "node_modules/tsyringe/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", diff --git a/package.json b/package.json index 36fe8ec07..0f12c9437 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "stream-buffers": "^3.0.3", "tar": "^7.4.3", "tsx": "^4.19.2", + "tsyringe-neo": "^5.1.0", "uuid": "^11.0.3", "validator": "^13.12.0", "winston": "^3.17.0", diff --git a/src/commands/base.ts b/src/commands/base.ts index c83d24864..d2e7db8cf 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -48,7 +48,7 @@ export abstract class BaseCommand extends ShellRunner { protected readonly remoteConfigManager: RemoteConfigManager; constructor(opts: Opts) { - if (!opts || !opts.logger) throw new Error('An instance of core/SoloLogger is required'); + // if (!opts || !opts.logger) throw new Error('An instance of core/SoloLogger is required'); if (!opts || !opts.helm) throw new Error('An instance of core/Helm is required'); if (!opts || !opts.k8) throw new Error('An instance of core/K8 is required'); if (!opts || !opts.chartManager) throw new Error('An instance of core/ChartManager is required'); @@ -57,8 +57,7 @@ export abstract class BaseCommand extends ShellRunner { if (!opts || !opts.localConfig) throw new Error('An instance of core/LocalConfig is required'); if (!opts || !opts.remoteConfigManager) throw new Error('An instance of core/config/RemoteConfigManager is required'); - - super(opts.logger); + super(); this.helm = opts.helm; this.k8 = opts.k8; diff --git a/src/core/account_manager.ts b/src/core/account_manager.ts index 4af1b9987..29f6201a3 100644 --- a/src/core/account_manager.ts +++ b/src/core/account_manager.ts @@ -40,13 +40,14 @@ import type {NetworkNodeServices} from './network_node_services.js'; import {NetworkNodeServicesBuilder} from './network_node_services.js'; import path from 'path'; -import {type SoloLogger} from './logging.js'; -import {type K8} from './k8.js'; +import {SoloLogger} from './logging.js'; +import {K8} from './k8.js'; import {type AccountIdWithKeyPairObject, type ExtendedNetServer} from '../types/index.js'; import {type NodeAlias, type PodName, type SdkNetworkEndpoint} from '../types/aliases.js'; import {IGNORED_NODE_ACCOUNT_ID} from './constants.js'; import {sleep} from './helpers.js'; import {Duration} from './time/duration.js'; +import {autoInjectable} from 'tsyringe-neo'; const REASON_FAILED_TO_GET_KEYS = 'failed to get keys for accountId'; const REASON_SKIPPED = 'skipped since it does not have a genesis key'; @@ -55,17 +56,15 @@ const REASON_FAILED_TO_CREATE_K8S_S_KEY = 'failed to create k8s scrt key'; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; +@autoInjectable() export class AccountManager { private _portForwards: ExtendedNetServer[]; public _nodeClient: Client | null; constructor( - private readonly logger: SoloLogger, - private readonly k8: K8, + private readonly logger?: SoloLogger, + private readonly k8?: K8, ) { - if (!logger) throw new Error('An instance of core/SoloLogger is required'); - if (!k8) throw new Error('An instance of core/K8 is required'); - this._portForwards = []; this._nodeClient = null; } diff --git a/src/core/certificate_manager.ts b/src/core/certificate_manager.ts index d1e3876a5..e3e0e457d 100644 --- a/src/core/certificate_manager.ts +++ b/src/core/certificate_manager.ts @@ -20,25 +20,23 @@ import fs from 'fs'; import {Templates} from './templates.js'; import {GrpcProxyTlsEnums} from './enumerations.js'; -import type {ConfigManager} from './config_manager.js'; -import type {K8} from './k8.js'; -import type {SoloLogger} from './logging.js'; +import {ConfigManager} from './config_manager.js'; +import {K8} from './k8.js'; +import {SoloLogger} from './logging.js'; import type {ListrTaskWrapper} from 'listr2'; import type {NodeAlias} from '../types/aliases.js'; +import {autoInjectable} from 'tsyringe-neo'; /** * Used to handle interactions with certificates data and inject it into the K8s cluster secrets */ +@autoInjectable() export class CertificateManager { constructor( - private readonly k8: K8, - private readonly logger: SoloLogger, - private readonly configManager: ConfigManager, - ) { - if (!k8) throw new MissingArgumentError('an instance of core/K8 is required'); - if (!logger) throw new MissingArgumentError('an instance of core/SoloLogger is required'); - if (!configManager) throw new MissingArgumentError('an instance of core/ConfigManager is required'); - } + private readonly k8?: K8, + private readonly logger?: SoloLogger, + private readonly configManager?: ConfigManager, + ) {} /** * Reads the certificate and key and build the secret with the appropriate structure diff --git a/src/core/chart_manager.ts b/src/core/chart_manager.ts index cab158fa9..191435eb1 100644 --- a/src/core/chart_manager.ts +++ b/src/core/chart_manager.ts @@ -15,19 +15,18 @@ * */ import * as constants from './constants.js'; -import {type Helm} from './helm.js'; +import {Helm} from './helm.js'; import chalk from 'chalk'; import {SoloError} from './errors.js'; -import {type SoloLogger} from './logging.js'; +import {SoloLogger} from './logging.js'; +import {autoInjectable} from 'tsyringe-neo'; +@autoInjectable() export class ChartManager { constructor( - private readonly helm: Helm, - private readonly logger: SoloLogger, - ) { - if (!logger) throw new Error('An instance of core/SoloLogger is required'); - if (!helm) throw new Error('An instance of core/Helm is required'); - } + private readonly helm?: Helm, + private readonly logger?: SoloLogger, + ) {} /** * Setup chart repositories diff --git a/src/core/config/local_config.ts b/src/core/config/local_config.ts index a5b5532c5..1f968a4ef 100644 --- a/src/core/config/local_config.ts +++ b/src/core/config/local_config.ts @@ -26,14 +26,16 @@ import { type LocalConfigData, } from './local_config_data.js'; import {MissingArgumentError, SoloError} from '../errors.js'; -import {type SoloLogger} from '../logging.js'; +import {SoloLogger} from '../logging.js'; import {IsClusterContextMapping, IsDeployments} from '../validator_decorators.js'; -import type {ConfigManager} from '../config_manager.js'; +import {ConfigManager} from '../config_manager.js'; import type {EmailAddress, Namespace} from './remote/types.js'; import {ErrorMessages} from '../error_messages.js'; import {type K8} from '../k8.js'; import {splitFlagInput} from '../helpers.js'; +import {autoInjectable} from 'tsyringe-neo'; +@autoInjectable() export class LocalConfig implements LocalConfigData { @IsEmail( {}, @@ -70,11 +72,10 @@ export class LocalConfig implements LocalConfigData { public constructor( private readonly filePath: string, - private readonly logger: SoloLogger, - private readonly configManager: ConfigManager, + private readonly logger?: SoloLogger, + private readonly configManager?: ConfigManager, ) { if (!filePath || filePath === '') throw new MissingArgumentError('a valid filePath is required'); - if (!logger) throw new Error('An instance of core/SoloLogger is required'); const allowedKeys = ['userEmailAddress', 'deployments', 'currentDeploymentName', 'clusterContextMapping']; if (this.configFileExists()) { diff --git a/src/core/config/remote/remote_config_manager.ts b/src/core/config/remote/remote_config_manager.ts index 6da2cb402..a1f9f673c 100644 --- a/src/core/config/remote/remote_config_manager.ts +++ b/src/core/config/remote/remote_config_manager.ts @@ -23,16 +23,17 @@ import {Flags as flags} from '../../../commands/flags.js'; import * as yaml from 'yaml'; import {ComponentsDataWrapper} from './components_data_wrapper.js'; import {RemoteConfigValidator} from './remote_config_validator.js'; -import type {K8} from '../../k8.js'; +import {K8} from '../../k8.js'; import type {Cluster, Namespace} from './types.js'; -import type {SoloLogger} from '../../logging.js'; -import type {ConfigManager} from '../../config_manager.js'; -import type {LocalConfig} from '../local_config.js'; +import {SoloLogger} from '../../logging.js'; +import {ConfigManager} from '../../config_manager.js'; +import {LocalConfig} from '../local_config.js'; import type {DeploymentStructure} from '../local_config_data.js'; import {type ContextClusterStructure} from '../../../types/config_types.js'; import {type EmptyContextConfig, type Optional, type SoloListrTask} from '../../../types/index.js'; import type * as k8s from '@kubernetes/client-node'; import {StatusCodes} from 'http-status-codes'; +import {autoInjectable} from 'tsyringe-neo'; interface ListrContext { config: {contextCluster: ContextClusterStructure}; @@ -42,6 +43,7 @@ interface ListrContext { * Uses Kubernetes ConfigMaps to manage the remote configuration data by creating, loading, modifying, * and saving the configuration data to and from a Kubernetes cluster. */ +@autoInjectable() export class RemoteConfigManager { /** Stores the loaded remote configuration data. */ private remoteConfig: Optional; @@ -53,10 +55,10 @@ export class RemoteConfigManager { * @param configManager - Manager to retrieve application flags and settings. */ public constructor( - private readonly k8: K8, - private readonly logger: SoloLogger, - private readonly localConfig: LocalConfig, - private readonly configManager: ConfigManager, + private readonly k8?: K8, + private readonly logger?: SoloLogger, + private readonly localConfig?: LocalConfig, + private readonly configManager?: ConfigManager, ) {} /* ---------- Getters ---------- */ diff --git a/src/core/config_manager.ts b/src/core/config_manager.ts index 1f6789d93..7cbed15cc 100644 --- a/src/core/config_manager.ts +++ b/src/core/config_manager.ts @@ -14,7 +14,7 @@ * limitations under the License. * */ -import {SoloError, MissingArgumentError, IllegalArgumentError} from './errors.js'; +import {SoloError, MissingArgumentError} from './errors.js'; import {SoloLogger} from './logging.js'; import {Flags, Flags as flags} from '../commands/flags.js'; import * as paths from 'path'; @@ -22,6 +22,7 @@ import * as helpers from './helpers.js'; import type * as yargs from 'yargs'; import {type CommandFlag} from '../types/flag_types.js'; import {type ListrTaskWrapper} from 'listr2'; +import {autoInjectable, container} from 'tsyringe-neo'; /** * ConfigManager cache command flag values so that user doesn't need to enter the same values repeatedly. @@ -29,13 +30,12 @@ import {type ListrTaskWrapper} from 'listr2'; * For example, 'namespace' is usually remains the same across commands once it is entered, and therefore user * doesn't need to enter it repeatedly. However, user should still be able to specify the flag explicitly for any command. */ +@autoInjectable() export class ConfigManager { config!: Record; - constructor(private readonly logger: SoloLogger) { - if (!logger || !(logger instanceof SoloLogger)) - throw new MissingArgumentError('An instance of core/SoloLogger is required'); - + constructor(private readonly logger?: SoloLogger) { + const logger2 = container.resolve(SoloLogger) this.reset(); } diff --git a/src/core/container_init.ts b/src/core/container_init.ts new file mode 100644 index 000000000..9aaaa880a --- /dev/null +++ b/src/core/container_init.ts @@ -0,0 +1,60 @@ +/** + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {container} from 'tsyringe-neo'; +import {SoloLogger} from './logging.js'; +import {PackageDownloader} from './package_downloader.js'; +import {Zippy} from './zippy.js'; +import {DependencyManager, HelmDependencyManager} from './dependency_managers/index.js'; +import * as constants from './constants.js'; +import {Helm} from './helm.js'; +import {ChartManager} from './chart_manager.js'; +import {ConfigManager} from './config_manager.js'; +import {K8} from './k8.js'; +import {AccountManager} from './account_manager.js'; +import {PlatformInstaller} from './platform_installer.js'; +import {KeyManager} from './key_manager.js'; +import {ProfileManager} from './profile_manager.js'; +import {IntervalLeaseRenewalService} from './lease/interval_lease_renewal.js'; +import {LeaseManager} from './lease/lease_manager.js'; +import {CertificateManager} from './certificate_manager.js'; +import path from 'path'; +import {LocalConfig} from './config/local_config.js'; +import {RemoteConfigManager} from './config/remote/remote_config_manager.js'; + +container.register(SoloLogger, {useValue: new SoloLogger('debug', false)}); +container.register(PackageDownloader, {useValue: new PackageDownloader()}); +container.register(Zippy, {useValue: new Zippy()}); +container.register(HelmDependencyManager, {useValue: new HelmDependencyManager()}); +container.register(DependencyManager, {useValue: new DependencyManager()}); +container.register(Helm, {useValue: new Helm()}); +container.register(ChartManager, {useValue: new ChartManager()}); +container.register(ConfigManager, {useValue: new ConfigManager()}); +container.register(K8, {useValue: new K8()}); +container.register(AccountManager, {useValue: new AccountManager()}); +container.register(PlatformInstaller, {useValue: new PlatformInstaller()}); +container.register(KeyManager, {useValue: new KeyManager()}); +container.register(ProfileManager, {useValue: new ProfileManager()}); +container.register(IntervalLeaseRenewalService, { + useValue: new IntervalLeaseRenewalService(), +}); +container.register(LeaseManager, { + useValue: new LeaseManager(container.resolve(IntervalLeaseRenewalService)), +}); +container.register(CertificateManager, {useValue: new CertificateManager()}); +const localConfigPath = path.join(constants.SOLO_CACHE_DIR, constants.DEFAULT_LOCAL_CONFIG_FILE); +container.register(LocalConfig, {useValue: new LocalConfig(localConfigPath)}); +container.register(RemoteConfigManager, {useValue: new RemoteConfigManager()}); diff --git a/src/core/dependency_managers/dependency_manager.ts b/src/core/dependency_managers/dependency_manager.ts index 4e3981956..fc69e3208 100644 --- a/src/core/dependency_managers/dependency_manager.ts +++ b/src/core/dependency_managers/dependency_manager.ts @@ -15,20 +15,20 @@ * */ import os from 'os'; -import {SoloError, MissingArgumentError} from '../errors.js'; +import {SoloError} from '../errors.js'; import {ShellRunner} from '../shell_runner.js'; -import {type SoloLogger} from '../logging.js'; -import {type HelmDependencyManager} from './helm_dependency_manager.js'; +import {HelmDependencyManager} from './helm_dependency_manager.js'; import {type ListrTask} from 'listr2'; +import {autoInjectable} from 'tsyringe-neo'; +import * as constants from '../constants.js'; +@autoInjectable() export class DependencyManager extends ShellRunner { - constructor( - logger: SoloLogger, - private readonly depManagerMap: Map, - ) { - if (!logger) throw new MissingArgumentError('an instance of core/SoloLogger is required', logger); - super(logger); - if (!depManagerMap) throw new MissingArgumentError('A map of dependency managers are required'); + private readonly depManagerMap: Map; + + constructor(helmDepManager?: HelmDependencyManager) { + super(); + this.depManagerMap = new Map().set(constants.HELM, helmDepManager); } /** diff --git a/src/core/dependency_managers/helm_dependency_manager.ts b/src/core/dependency_managers/helm_dependency_manager.ts index 120dd6904..1f5c56fc9 100644 --- a/src/core/dependency_managers/helm_dependency_manager.ts +++ b/src/core/dependency_managers/helm_dependency_manager.ts @@ -18,17 +18,17 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; import * as util from 'util'; -import {IllegalArgumentError, MissingArgumentError} from '../errors.js'; +import {MissingArgumentError} from '../errors.js'; import * as helpers from '../helpers.js'; import * as constants from '../constants.js'; -import {type PackageDownloader} from '../package_downloader.js'; -import {type Zippy} from '../zippy.js'; +import {PackageDownloader} from '../package_downloader.js'; +import {Zippy} from '../zippy.js'; import {Templates} from '../templates.js'; import * as version from '../../../version.js'; import {ShellRunner} from '../shell_runner.js'; import * as semver from 'semver'; import {OS_WIN32, OS_WINDOWS} from '../constants.js'; -import {type SoloLogger} from '../logging.js'; +import {container, singleton} from 'tsyringe-neo'; // constants required by HelmDependencyManager const HELM_RELEASE_BASE_URL = 'https://get.helm.sh'; @@ -42,6 +42,7 @@ const HELM_ARTIFACT_EXT: Map = new Map() /** * Helm dependency manager installs or uninstalls helm client at SOLO_HOME_DIR/bin directory */ +@singleton() export class HelmDependencyManager extends ShellRunner { private readonly osPlatform: string; private readonly osArch: string; @@ -49,25 +50,21 @@ export class HelmDependencyManager extends ShellRunner { private readonly artifactName: string; private readonly helmURL: string; private readonly checksumURL: string; + private readonly downloader; + private readonly zippy; constructor( - private readonly downloader: PackageDownloader, - private readonly zippy: Zippy, - logger: SoloLogger, private readonly installationDir = path.join(constants.SOLO_HOME_DIR, 'bin'), osPlatform = os.platform(), osArch = os.arch(), private readonly helmVersion = version.HELM_VERSION, ) { - super(logger); + super(); - if (!downloader) throw new MissingArgumentError('An instance of core/PackageDownloader is required'); - if (!zippy) throw new MissingArgumentError('An instance of core/Zippy is required'); - if (!logger) throw new IllegalArgumentError('an instance of core/SoloLogger is required', logger); if (!installationDir) throw new MissingArgumentError('installation directory is required'); - this.downloader = downloader; - this.zippy = zippy; + this.downloader = container.resolve(PackageDownloader); + this.zippy = container.resolve(Zippy); this.installationDir = installationDir; // Node.js uses 'win32' for windows in package.json os field, but helm uses 'windows' if (osPlatform === OS_WIN32) { diff --git a/src/core/helm.ts b/src/core/helm.ts index b2cec27f8..b986e2bfc 100644 --- a/src/core/helm.ts +++ b/src/core/helm.ts @@ -18,18 +18,14 @@ import os from 'os'; import * as constants from './constants.js'; import {ShellRunner} from './shell_runner.js'; import {Templates} from './templates.js'; -import {IllegalArgumentError} from './errors.js'; -import type {SoloLogger} from './logging.js'; +import {singleton} from 'tsyringe-neo'; +@singleton() export class Helm extends ShellRunner { private readonly helmPath: string; - constructor( - logger: SoloLogger, - private readonly osPlatform: NodeJS.Platform = os.platform(), - ) { - if (!logger) throw new IllegalArgumentError('an instance of core/SoloLogger is required', logger); - super(logger); + constructor(private readonly osPlatform: NodeJS.Platform = os.platform()) { + super(); this.helmPath = Templates.installationPath(constants.HELM, this.osPlatform); } diff --git a/src/core/k8.ts b/src/core/k8.ts index c6281ed0f..460b79be9 100644 --- a/src/core/k8.ts +++ b/src/core/k8.ts @@ -31,12 +31,13 @@ import {getReasonPhrase, StatusCodes} from 'http-status-codes'; import {sleep} from './helpers.js'; import * as constants from './constants.js'; -import {type ConfigManager} from './config_manager.js'; -import {type SoloLogger} from './logging.js'; +import {ConfigManager} from './config_manager.js'; +import {SoloLogger} from './logging.js'; import {type PodName, type TarCreateFilter} from '../types/aliases.js'; import type {ExtendedNetServer, LocalContextObject} from '../types/index.js'; import {HEDERA_HAPI_PATH, ROOT_CONTAINER, SOLO_LOGS_DIR} from './constants.js'; import {Duration} from './time/duration.js'; +import {autoInjectable, container} from 'tsyringe-neo'; interface TDirectoryData { directory: boolean; @@ -53,6 +54,7 @@ interface TDirectoryData { * Note: Take care if the same instance is used for parallel execution, as the behaviour may be unpredictable. * For parallel execution, create separate instances by invoking clone() */ +@autoInjectable() export class K8 { private _cachedContexts: Context[]; @@ -65,12 +67,9 @@ export class K8 { private coordinationApiClient: k8s.CoordinationV1Api; constructor( - private readonly configManager: ConfigManager, - public readonly logger: SoloLogger, + private readonly configManager?: ConfigManager, + public readonly logger?: SoloLogger, ) { - if (!configManager) throw new MissingArgumentError('An instance of core/ConfigManager is required'); - if (!logger) throw new MissingArgumentError('An instance of core/SoloLogger is required'); - this.init(); } @@ -79,7 +78,7 @@ export class K8 { * Internally it instantiates a new kube API client */ clone() { - const c = new K8(this.configManager, this.logger); + const c = container.resolve(K8); return c.init(); } diff --git a/src/core/key_manager.ts b/src/core/key_manager.ts index b55500bf6..2be8a0921 100644 --- a/src/core/key_manager.ts +++ b/src/core/key_manager.ts @@ -27,10 +27,12 @@ import chalk from 'chalk'; import {type NodeAlias, type NodeAliases} from '../types/aliases.js'; import {type NodeKeyObject, type PrivateKeyAndCertificateObject} from '../types/index.js'; import type {ListrTask} from 'listr2'; +import {autoInjectable} from 'tsyringe-neo'; // @ts-ignore x509.cryptoProvider.set(crypto); +@autoInjectable() export class KeyManager { static SigningKeyAlgo = { name: 'RSASSA-PKCS1-v1_5', @@ -60,11 +62,7 @@ export class KeyManager { hash: 'SHA-384', }; - constructor(private readonly logger: SoloLogger) { - if (!logger || !(logger instanceof SoloLogger)) - throw new MissingArgumentError('An instance of core/SoloLogger is required'); - this.logger = logger; - } + constructor(private readonly logger?: SoloLogger) {} /** Convert CryptoKey into PEM string */ async convertPrivateKeyToPem(privateKey: CryptoKey) { diff --git a/src/core/lease/interval_lease_renewal.ts b/src/core/lease/interval_lease_renewal.ts index caf6c039c..23c63c147 100644 --- a/src/core/lease/interval_lease_renewal.ts +++ b/src/core/lease/interval_lease_renewal.ts @@ -16,11 +16,13 @@ */ import {type Lease, type LeaseRenewalService} from './lease.js'; import {Duration} from '../time/duration.js'; +import {autoInjectable} from 'tsyringe-neo'; /** * Implements a lease renewal service which utilizes a setInterval() based approach to renew leases at regular intervals. * The renewal delay is calculated as half the duration of the lease in seconds. */ +@autoInjectable() export class IntervalLeaseRenewalService implements LeaseRenewalService { /** The internal registry used to track all non-cancelled lease renewals. */ private readonly _scheduledLeases: Map; diff --git a/src/core/lease/lease_manager.ts b/src/core/lease/lease_manager.ts index 7d80f867c..7d941035c 100644 --- a/src/core/lease/lease_manager.ts +++ b/src/core/lease/lease_manager.ts @@ -14,26 +14,21 @@ * limitations under the License. * */ -import {MissingArgumentError} from '../errors.js'; import {Flags as flags} from '../../commands/flags.js'; -import type {ConfigManager} from '../config_manager.js'; -import type {K8} from '../k8.js'; -import type {SoloLogger} from '../logging.js'; -import {type Lease, type LeaseRenewalService} from './lease.js'; +import {ConfigManager} from '../config_manager.js'; +import {K8} from '../k8.js'; +import {SoloLogger} from '../logging.js'; +import {type Lease, LeaseRenewalService} from './lease.js'; import {IntervalLease} from './interval_lease.js'; import {LeaseHolder} from './lease_holder.js'; import {LeaseAcquisitionError} from './lease_errors.js'; +import {autoInjectable} from 'tsyringe-neo'; /** * Manages the acquisition and renewal of leases. */ +@autoInjectable() export class LeaseManager { - /** The injected logger instance. */ - private readonly _logger: SoloLogger; - - /** The injected lease renewal service instance. */ - private readonly _renewalService: LeaseRenewalService; - /** * Creates a new lease manager. * @@ -43,19 +38,11 @@ export class LeaseManager { * @param renewalService - the lease renewal service. */ constructor( - private readonly k8: K8, - private readonly configManager: ConfigManager, - logger: SoloLogger, - renewalService: LeaseRenewalService, - ) { - if (!k8) throw new MissingArgumentError('an instance of core/K8 is required'); - if (!logger) throw new MissingArgumentError('an instance of core/SoloLogger is required'); - if (!configManager) throw new MissingArgumentError('an instance of core/ConfigManager is required'); - if (!renewalService) throw new MissingArgumentError('an instance of core/LeaseRenewalService is required'); - - this._logger = logger; - this._renewalService = renewalService; - } + private readonly _renewalService?: LeaseRenewalService, + private readonly _logger?: SoloLogger, + private readonly k8?: K8, + private readonly configManager?: ConfigManager, + ) {} /** * Creates a new lease. This lease is not acquired until the `acquire` method is called. diff --git a/src/core/logging.ts b/src/core/logging.ts index 46c71f4d3..65de71cff 100644 --- a/src/core/logging.ts +++ b/src/core/logging.ts @@ -20,6 +20,7 @@ import * as util from 'util'; import chalk from 'chalk'; import path from 'path'; import * as constants from './constants.js'; +import {singleton} from 'tsyringe-neo'; const customFormat = winston.format.combine( winston.format.label({label: 'SOLO', message: false}), @@ -47,6 +48,7 @@ const customFormat = winston.format.combine( winston.format(data => (data.private ? false : data))(), ); +@singleton() export class SoloLogger { private winstonLogger: winston.Logger; private traceId?: string; diff --git a/src/core/package_downloader.ts b/src/core/package_downloader.ts index 5abd01b13..ea910c743 100644 --- a/src/core/package_downloader.ts +++ b/src/core/package_downloader.ts @@ -30,13 +30,13 @@ import * as https from 'https'; import * as http from 'http'; import {Templates} from './templates.js'; import * as constants from './constants.js'; -import {type SoloLogger} from './logging.js'; +import {SoloLogger} from './logging.js'; import {StatusCodes} from 'http-status-codes'; +import {autoInjectable} from 'tsyringe-neo'; +@autoInjectable() export class PackageDownloader { - constructor(public readonly logger: SoloLogger) { - if (!logger) throw new IllegalArgumentError('an instance of core/SoloLogger is required', logger); - } + constructor(public readonly logger?: SoloLogger) {} isValidURL(url: string) { try { diff --git a/src/core/platform_installer.ts b/src/core/platform_installer.ts index d8be49e00..224f92606 100644 --- a/src/core/platform_installer.ts +++ b/src/core/platform_installer.ts @@ -19,33 +19,27 @@ import {Listr} from 'listr2'; import * as path from 'path'; import {SoloError, IllegalArgumentError, MissingArgumentError} from './errors.js'; import * as constants from './constants.js'; -import {type ConfigManager} from './config_manager.js'; -import {type K8} from './k8.js'; +import {ConfigManager} from './config_manager.js'; +import {K8} from './k8.js'; import {Templates} from './templates.js'; import {Flags as flags} from '../commands/flags.js'; import * as Base64 from 'js-base64'; import chalk from 'chalk'; -import {type SoloLogger} from './logging.js'; +import {SoloLogger} from './logging.js'; import type {NodeAlias, NodeAliases, PodName} from '../types/aliases.js'; import {Duration} from './time/duration.js'; import {sleep} from './helpers.js'; +import {autoInjectable} from 'tsyringe-neo'; /** PlatformInstaller install platform code in the root-container of a network pod */ +@autoInjectable() export class PlatformInstaller { - private logger: SoloLogger; - private k8: K8; - private configManager: ConfigManager; - - constructor(logger: SoloLogger, k8: K8, configManager: ConfigManager) { - if (!logger) throw new MissingArgumentError('an instance of core/SoloLogger is required'); - if (!k8) throw new MissingArgumentError('an instance of core/K8 is required'); - if (!configManager) throw new MissingArgumentError('an instance of core/ConfigManager is required'); - - this.logger = logger; - this.k8 = k8; - this.configManager = configManager; - } + constructor( + private logger?: SoloLogger, + private k8?: K8, + private configManager?: ConfigManager, + ) {} private _getNamespace(): string { const ns = this.configManager.getFlag(flags.namespace) as string; diff --git a/src/core/profile_manager.ts b/src/core/profile_manager.ts index 61a07d790..c844c97be 100644 --- a/src/core/profile_manager.ts +++ b/src/core/profile_manager.ts @@ -25,15 +25,16 @@ import {readFile, writeFile} from 'fs/promises'; import {Flags as flags} from '../commands/flags.js'; import {Templates} from './templates.js'; import * as constants from './constants.js'; -import {type ConfigManager} from './config_manager.js'; +import {ConfigManager} from './config_manager.js'; import * as helpers from './helpers.js'; import {getNodeAccountMap} from './helpers.js'; import {AccountId} from '@hashgraph/sdk'; import type {SemVer} from 'semver'; -import type {SoloLogger} from './logging.js'; +import {SoloLogger} from './logging.js'; import type {AnyObject, DirPath, NodeAlias, NodeAliases, Path} from '../types/aliases.js'; import type {GenesisNetworkDataConstructor} from './genesis_network_models/genesis_network_data_constructor.js'; import type {Optional} from '../types/index.js'; +import {container, singleton} from 'tsyringe-neo'; const consensusSidecars = [ 'recordStreamUploader', @@ -43,6 +44,7 @@ const consensusSidecars = [ 'otelCollector', ]; +@singleton() export class ProfileManager { private readonly logger: SoloLogger; private readonly configManager: ConfigManager; @@ -51,12 +53,9 @@ export class ProfileManager { private profiles: Map; private profileFile: Optional; - constructor(logger: SoloLogger, configManager: ConfigManager, cacheDir: DirPath = constants.SOLO_VALUES_DIR) { - if (!logger) throw new MissingArgumentError('An instance of core/SoloLogger is required'); - if (!configManager) throw new MissingArgumentError('An instance of core/ConfigManager is required'); - - this.logger = logger; - this.configManager = configManager; + constructor(cacheDir: DirPath = constants.SOLO_VALUES_DIR) { + this.logger = container.resolve(SoloLogger); + this.configManager = container.resolve(ConfigManager); this.profiles = new Map(); diff --git a/src/core/shell_runner.ts b/src/core/shell_runner.ts index dc19f18c0..336b16c8c 100644 --- a/src/core/shell_runner.ts +++ b/src/core/shell_runner.ts @@ -16,12 +16,12 @@ */ import {spawn} from 'child_process'; import chalk from 'chalk'; -import {type SoloLogger} from './logging.js'; +import {SoloLogger} from './logging.js'; +import {autoInjectable} from 'tsyringe-neo'; +@autoInjectable() export class ShellRunner { - constructor(public logger: SoloLogger) { - if (!logger) throw new Error('An instance of core/SoloLogger is required'); - } + constructor(public logger?: SoloLogger) {} /** Returns a promise that invokes the shell command */ run(cmd: string, verbose = false) { diff --git a/src/core/zippy.ts b/src/core/zippy.ts index 152258df0..a35605469 100644 --- a/src/core/zippy.ts +++ b/src/core/zippy.ts @@ -20,12 +20,12 @@ import AdmZip from 'adm-zip'; import * as tar from 'tar'; import chalk from 'chalk'; import path from 'path'; -import type {SoloLogger} from './logging.js'; +import {SoloLogger} from './logging.js'; +import {autoInjectable} from 'tsyringe-neo'; +@autoInjectable() export class Zippy { - constructor(private readonly logger: SoloLogger) { - if (!logger) throw new Error('An instance of core/SoloLogger is required'); - } + constructor(private readonly logger?: SoloLogger) {} /** * Zip a file or directory diff --git a/src/index.ts b/src/index.ts index 386fa8639..4fcdd1dc2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,6 +19,8 @@ import yargs from 'yargs'; import {hideBin} from 'yargs/helpers'; import 'dotenv/config'; import path from 'path'; +import 'reflect-metadata'; +import './core/container_init.js'; import {ListrLogger} from 'listr2'; import {Flags as flags} from './commands/flags.js'; @@ -26,7 +28,6 @@ import * as commands from './commands/index.js'; import {HelmDependencyManager, DependencyManager} from './core/dependency_managers/index.js'; import * as constants from './core/constants.js'; import {PackageDownloader} from './core/package_downloader.js'; -import {Zippy} from './core/zippy.js'; import {Helm} from './core/helm.js'; import {ChartManager} from './core/chart_manager.js'; import {ConfigManager} from './core/config_manager.js'; @@ -38,16 +39,15 @@ import {LeaseManager} from './core/lease/lease_manager.js'; import {CertificateManager} from './core/certificate_manager.js'; import {LocalConfig} from './core/config/local_config.js'; import {RemoteConfigManager} from './core/config/remote/remote_config_manager.js'; -import * as logging from './core/logging.js'; import * as helpers from './core/helpers.js'; import {K8} from './core/k8.js'; import {CustomProcessOutput} from './core/process_output.js'; import {type Opts} from './types/command_types.js'; -import {IntervalLeaseRenewalService} from './core/lease/interval_lease_renewal.js'; -import {type LeaseRenewalService} from './core/lease/lease.js'; +import {container} from 'tsyringe-neo'; +import {SoloLogger} from './core/logging.js'; export function main(argv: any) { - const logger = logging.NewLogger('debug'); + const logger = container.resolve(SoloLogger); constants.LISTR_DEFAULT_RENDERER_OPTION.logger = new ListrLogger({processOutput: new CustomProcessOutput(logger)}); if (argv.length >= 3 && ['-version', '--version', '-v', '--v'].includes(argv[2])) { logger.showUser(chalk.cyan('\n******************************* Solo *********************************************')); @@ -58,26 +58,21 @@ export function main(argv: any) { try { // prepare dependency manger registry - const downloader = new PackageDownloader(logger); - const zippy = new Zippy(logger); - const helmDepManager = new HelmDependencyManager(downloader, zippy, logger); - const depManagerMap = new Map().set(constants.HELM, helmDepManager); - const depManager = new DependencyManager(logger, depManagerMap); - - const helm = new Helm(logger); - const chartManager = new ChartManager(helm, logger); - const configManager = new ConfigManager(logger); - const k8 = new K8(configManager, logger); - const accountManager = new AccountManager(logger, k8); - const platformInstaller = new PlatformInstaller(logger, k8, configManager); - const keyManager = new KeyManager(logger); - const profileManager = new ProfileManager(logger, configManager); - const leaseRenewalService: LeaseRenewalService = new IntervalLeaseRenewalService(); - const leaseManager = new LeaseManager(k8, configManager, logger, leaseRenewalService); - const certificateManager = new CertificateManager(k8, logger, configManager); + const downloader = container.resolve(PackageDownloader); + const depManager = container.resolve(DependencyManager); + const helm = container.resolve(Helm); + const chartManager = container.resolve(ChartManager); + const configManager = container.resolve(ConfigManager); + const k8 = container.resolve(K8); + const accountManager = container.resolve(AccountManager); + const platformInstaller = container.resolve(PlatformInstaller); + const keyManager = container.resolve(KeyManager); + const profileManager = container.resolve(ProfileManager); + const leaseManager = container.resolve(LeaseManager); + const certificateManager = container.resolve(CertificateManager); const localConfigPath = path.join(constants.SOLO_CACHE_DIR, constants.DEFAULT_LOCAL_CONFIG_FILE); - const localConfig = new LocalConfig(localConfigPath, logger, configManager); - const remoteConfigManager = new RemoteConfigManager(k8, logger, localConfig, configManager); + const localConfig = new LocalConfig(localConfigPath); + const remoteConfigManager = container.resolve(RemoteConfigManager); // set cluster and namespace in the global configManager from kubernetes context // so that we don't need to prompt the user diff --git a/test/e2e/e2e_node_util.ts b/test/e2e/e2e_node_util.ts index 19d135891..fd6585eae 100644 --- a/test/e2e/e2e_node_util.ts +++ b/test/e2e/e2e_node_util.ts @@ -36,6 +36,7 @@ import {type K8} from '../../src/core/k8.js'; import {type NodeCommand} from '../../src/commands/node/index.js'; import {Duration} from '../../src/core/time/duration.js'; import {StatusCodes} from 'http-status-codes'; +import {container} from 'tsyringe-neo'; export function e2eNodeKeyRefreshTest(testName: string, mode: string, releaseTag = HEDERA_PLATFORM_VERSION_TAG) { const namespace = testName; @@ -191,7 +192,7 @@ export function e2eNodeKeyRefreshTest(testName: string, mode: string, releaseTag async function nodeRefreshTestSetup(argv: Record, testName: string, k8: K8, nodeAliases: string) { argv[flags.nodeAliasesUnparsed.name] = nodeAliases; - const configManager = new ConfigManager(testLogger); + const configManager = container.resolve(ConfigManager); configManager.update(argv); const podArray = await k8.getPodsByLabel([`app=network-${nodeAliases}`, 'solo.hedera.com/type=network-node']); diff --git a/test/e2e/integration/commands/init.test.ts b/test/e2e/integration/commands/init.test.ts index 64272c0f3..53c23c911 100644 --- a/test/e2e/integration/commands/init.test.ts +++ b/test/e2e/integration/commands/init.test.ts @@ -36,23 +36,25 @@ import {IntervalLeaseRenewalService} from '../../../../src/core/lease/interval_l import path from 'path'; import {BASE_TEST_DIR} from '../../../test_util.js'; import {Duration} from '../../../../src/core/time/duration.js'; +import {container} from 'tsyringe-neo'; const testLogger = logging.NewLogger('debug', true); describe('InitCommand', () => { // prepare dependency manger registry - const downloader = new PackageDownloader(testLogger); - const zippy = new Zippy(testLogger); - const helmDepManager = new HelmDependencyManager(downloader, zippy, testLogger); - const depManagerMap = new Map().set(constants.HELM, helmDepManager); - const depManager = new DependencyManager(testLogger, depManagerMap); + // const downloader = new PackageDownloader(testLogger); + // const zippy = new Zippy(testLogger); + // const helmDepManager = new HelmDependencyManager(downloader, zippy, testLogger); - const helm = new Helm(testLogger); - const chartManager = new ChartManager(helm, testLogger); - const configManager = new ConfigManager(testLogger); + // const depManager = new DependencyManager(helmDepManager); + const depManager = container.resolve(DependencyManager); + const helm = container.resolve(Helm); + const chartManager = container.resolve(ChartManager); + + const configManager = container.resolve(ConfigManager); let k8: K8; let localConfig: LocalConfig; - const keyManager = new KeyManager(testLogger); + const keyManager = container.resolve(KeyManager); let leaseManager: LeaseManager; let remoteConfigManager: RemoteConfigManager; @@ -63,10 +65,11 @@ describe('InitCommand', () => { before(() => { sandbox = sinon.createSandbox(); sandbox.stub(K8.prototype, 'init').callsFake(() => this); - k8 = new K8(configManager, testLogger); - localConfig = new LocalConfig(path.join(BASE_TEST_DIR, 'local-config.yaml'), testLogger, configManager); - remoteConfigManager = new RemoteConfigManager(k8, testLogger, localConfig, configManager); - leaseManager = new LeaseManager(k8, configManager, testLogger, new IntervalLeaseRenewalService()); + k8 = container.resolve(K8); + localConfig = new LocalConfig(path.join(BASE_TEST_DIR, 'local-config.yaml')); + remoteConfigManager = container.resolve(RemoteConfigManager); + leaseManager = container.resolve(LeaseManager); + // @ts-ignore initCmd = new InitCommand({ logger: testLogger, diff --git a/test/e2e/integration/core/chart_manager.test.ts b/test/e2e/integration/core/chart_manager.test.ts index 79d9d5e83..72399eed9 100644 --- a/test/e2e/integration/core/chart_manager.test.ts +++ b/test/e2e/integration/core/chart_manager.test.ts @@ -21,10 +21,10 @@ import * as constants from '../../../../src/core/constants.js'; import {Helm} from '../../../../src/core/helm.js'; import {ChartManager} from '../../../../src/core/chart_manager.js'; import {testLogger} from '../../../test_util.js'; +import {container} from 'tsyringe-neo'; describe('ChartManager', () => { - const helm = new Helm(testLogger); - const chartManager = new ChartManager(helm, testLogger); + const chartManager = container.resolve(ChartManager); it('should be able to list installed charts', async () => { const ns = constants.SOLO_SETUP_NAMESPACE; diff --git a/test/e2e/integration/core/dependency_managers/helm_dependency_manager.test.ts b/test/e2e/integration/core/dependency_managers/helm_dependency_manager.test.ts index 0a360e275..bba2fea42 100644 --- a/test/e2e/integration/core/dependency_managers/helm_dependency_manager.test.ts +++ b/test/e2e/integration/core/dependency_managers/helm_dependency_manager.test.ts @@ -40,17 +40,20 @@ describe('HelmDependencyManager', () => { }); it('should return helm version', () => { - const helmDependencyManager = new HelmDependencyManager(downloader, zippy, testLogger, tmpDir); + // const helmDependencyManager = new HelmDependencyManager(downloader, zippy, testLogger, tmpDir); + const helmDependencyManager = new HelmDependencyManager(tmpDir); expect(helmDependencyManager.getHelmVersion()).to.equal(version.HELM_VERSION); }); it('should be able to check when helm not installed', () => { - const helmDependencyManager = new HelmDependencyManager(downloader, zippy, testLogger, tmpDir); + // const helmDependencyManager = new HelmDependencyManager(downloader, zippy, testLogger, tmpDir); + const helmDependencyManager = new HelmDependencyManager(tmpDir); expect(helmDependencyManager.isInstalled()).not.to.be.ok; }); it('should be able to check when helm is installed', () => { - const helmDependencyManager = new HelmDependencyManager(downloader, zippy, testLogger, tmpDir); + // const helmDependencyManager = new HelmDependencyManager(downloader, zippy, testLogger, tmpDir); + const helmDependencyManager = new HelmDependencyManager(tmpDir); fs.writeFileSync(helmDependencyManager.getHelmPath(), ''); expect(helmDependencyManager.isInstalled()).to.be.ok; }); @@ -62,14 +65,15 @@ describe('HelmDependencyManager', () => { // { osRelease: 'linux', osArch: 'amd64' }, // { osRelease: 'windows', osArch: 'amd64' } ]).it('should be able to install helm base on os and architecture', async input => { - const helmDependencyManager = new HelmDependencyManager( - downloader, - zippy, - testLogger, - tmpDir, - input.osPlatform, - input.osArch, - ); + // const helmDependencyManager = new HelmDependencyManager( + // downloader, + // zippy, + // testLogger, + // tmpDir, + // input.osPlatform, + // input.osArch, + // ); + const helmDependencyManager = new HelmDependencyManager(tmpDir, input.osPlatform, input.osArch); if (fs.existsSync(tmpDir)) { fs.rmSync(tmpDir, {recursive: true}); diff --git a/test/e2e/integration/core/k8_e2e.test.ts b/test/e2e/integration/core/k8_e2e.test.ts index f4642039a..95f513f2d 100644 --- a/test/e2e/integration/core/k8_e2e.test.ts +++ b/test/e2e/integration/core/k8_e2e.test.ts @@ -47,6 +47,7 @@ import { import crypto from 'crypto'; import type {PodName} from '../../../../src/types/aliases.js'; import {Duration} from '../../../../src/core/time/duration.js'; +import {container} from 'tsyringe-neo'; const defaultTimeout = Duration.ofMinutes(2).toMillis(); @@ -80,8 +81,8 @@ async function createPod( describe('K8', () => { const testLogger = logging.NewLogger('debug', true); - const configManager = new ConfigManager(testLogger); - const k8 = new K8(configManager, testLogger); + const configManager = container.resolve(ConfigManager); + const k8 = container.resolve(K8); const testNamespace = 'k8-e2e'; const argv = []; const podName = `test-pod-${uuid4()}` as PodName; diff --git a/test/e2e/integration/core/lease.test.ts b/test/e2e/integration/core/lease.test.ts index 27ef8cbde..773733f5a 100644 --- a/test/e2e/integration/core/lease.test.ts +++ b/test/e2e/integration/core/lease.test.ts @@ -25,14 +25,15 @@ import {sleep} from '../../../../src/core/helpers.js'; import {LeaseRelinquishmentError} from '../../../../src/core/lease/lease_errors.js'; import {NoopLeaseRenewalService} from './noop_lease_renewal_service.test.js'; import {Duration} from '../../../../src/core/time/duration.js'; +import {container} from 'tsyringe-neo'; const defaultTimeout = Duration.ofMinutes(2).toMillis(); const leaseDuration = 4; describe('Lease', async () => { const testLogger = logging.NewLogger('debug', true); - const configManager = new ConfigManager(testLogger); - const k8 = new K8(configManager, testLogger); + const configManager = container.resolve(ConfigManager); + const k8 = container.resolve(K8); const testNamespace = 'lease-e2e'; const renewalService = new NoopLeaseRenewalService(); diff --git a/test/e2e/integration/core/lease_renewal.test.ts b/test/e2e/integration/core/lease_renewal.test.ts index 27cebceff..e1e508e20 100644 --- a/test/e2e/integration/core/lease_renewal.test.ts +++ b/test/e2e/integration/core/lease_renewal.test.ts @@ -25,16 +25,17 @@ import {sleep} from '../../../../src/core/helpers.js'; import {IntervalLeaseRenewalService} from '../../../../src/core/lease/interval_lease_renewal.js'; import {type V1Lease} from '@kubernetes/client-node'; import {Duration} from '../../../../src/core/time/duration.js'; +import {container} from 'tsyringe-neo'; const defaultTimeout = Duration.ofMinutes(2).toMillis(); const leaseDuration = 4; describe('LeaseRenewalService', async () => { const testLogger = logging.NewLogger('debug', true); - const configManager = new ConfigManager(testLogger); - const k8 = new K8(configManager, testLogger); + const configManager = container.resolve(ConfigManager); + const k8 = container.resolve(K8); + const renewalService = container.resolve(IntervalLeaseRenewalService); const testNamespace = 'lease-renewal-e2e'; - const renewalService = new IntervalLeaseRenewalService(); before(async function () { this.timeout(defaultTimeout); diff --git a/test/e2e/integration/core/remote_config_manager.test.ts b/test/e2e/integration/core/remote_config_manager.test.ts index 8098bb2c1..e42160265 100644 --- a/test/e2e/integration/core/remote_config_manager.test.ts +++ b/test/e2e/integration/core/remote_config_manager.test.ts @@ -29,6 +29,7 @@ import path from 'path'; import {SoloError} from '../../../../src/core/errors.js'; import {RemoteConfigDataWrapper} from '../../../../src/core/config/remote/remote_config_data_wrapper.js'; import {Duration} from '../../../../src/core/time/duration.js'; +import {container} from 'tsyringe-neo'; const defaultTimeout = Duration.ofSeconds(20).toMillis(); @@ -58,12 +59,10 @@ e2eTestSuite( bootstrapResp => { describe('RemoteConfigManager', async () => { const k8 = bootstrapResp.opts.k8; - const logger = bootstrapResp.opts.logger; - const configManager = bootstrapResp.opts.configManager; const filePath = path.join(constants.SOLO_CACHE_DIR, constants.DEFAULT_LOCAL_CONFIG_FILE); - const localConfig = new LocalConfig(filePath, logger, configManager); - const remoteConfigManager = new RemoteConfigManager(k8, logger, localConfig, configManager); + const localConfig = new LocalConfig(filePath); + const remoteConfigManager = container.resolve(RemoteConfigManager); const email = 'john@gmail.com'; diff --git a/test/e2e/integration/core/remote_config_validator.test.ts b/test/e2e/integration/core/remote_config_validator.test.ts index fc3cf49b4..6e9987a00 100644 --- a/test/e2e/integration/core/remote_config_validator.test.ts +++ b/test/e2e/integration/core/remote_config_validator.test.ts @@ -36,13 +36,14 @@ import {MirrorNodeExplorerComponent} from '../../../../src/core/config/remote/co import {EnvoyProxyComponent} from '../../../../src/core/config/remote/components/envoy_proxy_component.js'; import type {NodeAlias, NodeAliases} from '../../../../src/types/aliases.js'; +import {container} from 'tsyringe-neo'; describe('RemoteConfigValidator', () => { const namespace = 'remote-config-validator'; - const configManager = new ConfigManager(testLogger); + const configManager = container.resolve(ConfigManager); configManager.update({[flags.namespace.name]: namespace}); - const k8 = new K8(configManager, testLogger); + const k8 = container.resolve(K8); before(async () => { await k8.createNamespace(namespace); diff --git a/test/setup.ts b/test/setup.ts index c4c4ddb84..32e6dbded 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -17,6 +17,10 @@ import * as chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; import sinonChai from 'sinon-chai'; +import 'reflect-metadata'; +import {resetTestContainer} from './test_container.js'; + +resetTestContainer(); chai.use(chaiAsPromised); chai.use(sinonChai); diff --git a/test/test_container.ts b/test/test_container.ts new file mode 100644 index 000000000..d6ccb21fa --- /dev/null +++ b/test/test_container.ts @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {container} from 'tsyringe-neo'; +import {SoloLogger} from '../src/core/logging.js'; +import {PackageDownloader} from '../src/core/package_downloader.js'; +import {Zippy} from '../src/core/zippy.js'; +import {DependencyManager, HelmDependencyManager} from '../src/core/dependency_managers/index.js'; +import {Helm} from '../src/core/helm.js'; +import {ChartManager} from '../src/core/chart_manager.js'; +import {ConfigManager} from '../src/core/config_manager.js'; +import {K8} from '../src/core/k8.js'; +import {AccountManager} from '../src/core/account_manager.js'; +import {PlatformInstaller} from '../src/core/platform_installer.js'; +import {KeyManager} from '../src/core/key_manager.js'; +import {ProfileManager} from '../src/core/profile_manager.js'; +import {IntervalLeaseRenewalService} from '../src/core/lease/interval_lease_renewal.js'; +import {LeaseManager} from '../src/core/lease/lease_manager.js'; +import {CertificateManager} from '../src/core/certificate_manager.js'; +import path from 'path'; +import * as constants from '../src/core/constants.js'; +import {LocalConfig} from '../src/core/config/local_config.js'; +import {RemoteConfigManager} from '../src/core/config/remote/remote_config_manager.js'; + +const cacheDir = path.join('test', 'data', 'tmp'); +// if (!cacheDir) cacheDir = path.join('test', 'data', 'tmp'); +// container.reset(); +container.register(SoloLogger, {useValue: new SoloLogger('debug', true)}); +container.register(PackageDownloader, {useValue: new PackageDownloader()}); +container.register(Zippy, {useValue: new Zippy()}); +container.register(HelmDependencyManager, {useValue: new HelmDependencyManager()}); +container.register(DependencyManager, {useValue: new DependencyManager()}); +container.register(Helm, {useValue: new Helm()}); +container.register(ChartManager, {useValue: new ChartManager()}); +container.register(ConfigManager, {useValue: new ConfigManager()}); +container.register(K8, {useValue: new K8()}); +container.register(AccountManager, {useValue: new AccountManager()}); +container.register(PlatformInstaller, {useValue: new PlatformInstaller()}); +container.register(KeyManager, {useValue: new KeyManager()}); +container.register(ProfileManager, {useValue: new ProfileManager()}); +container.register(IntervalLeaseRenewalService, { + useValue: new IntervalLeaseRenewalService(), +}); +container.register(LeaseManager, { + useValue: new LeaseManager(container.resolve(IntervalLeaseRenewalService)), +}); +container.register(CertificateManager, {useValue: new CertificateManager()}); +const localConfigPath = path.join(cacheDir, constants.DEFAULT_LOCAL_CONFIG_FILE); +container.register(LocalConfig, {useValue: new LocalConfig(localConfigPath)}); +container.register(RemoteConfigManager, {useValue: new RemoteConfigManager()}); + +export function resetTestContainer(cacheDir?: string) {} diff --git a/test/test_util.ts b/test/test_util.ts index b6935fc95..6cdc86b22 100644 --- a/test/test_util.ts +++ b/test/test_util.ts @@ -36,7 +36,7 @@ import {AccountCommand} from '../src/commands/account.js'; import {SoloError} from '../src/core/errors.js'; import {execSync} from 'child_process'; import * as NodeCommandConfigs from '../src/commands/node/configs.js'; -import type {SoloLogger} from '../src/core/logging.js'; +import {SoloLogger} from '../src/core/logging.js'; import type {BaseCommand} from '../src/commands/base.js'; import type {NodeAlias} from '../src/types/aliases.js'; import type {NetworkNodeServices} from '../src/core/network_node_services.js'; @@ -60,6 +60,8 @@ import {Zippy} from '../src/core/zippy.js'; import {HEDERA_PLATFORM_VERSION} from '../version.js'; import {IntervalLeaseRenewalService} from '../src/core/lease/interval_lease_renewal.js'; import {Duration} from '../src/core/time/duration.js'; +import {container} from 'tsyringe-neo'; +import {resetTestContainer} from "./test_container.js"; export const testLogger = logging.NewLogger('debug', true); export const TEST_CLUSTER = 'solo-e2e'; @@ -137,24 +139,25 @@ export function bootstrapTestVariables( ): BootstrapResponse { const namespace: string = argv[flags.namespace.name] || 'bootstrap-ns'; const cacheDir: string = argv[flags.cacheDir.name] || getTestCacheDir(testName); - const configManager = new ConfigManager(testLogger); + + // resetTestContainer(cacheDir) + + const configManager = container.resolve(ConfigManager); configManager.update(argv); - const downloader = new PackageDownloader(testLogger); - const zippy = new Zippy(testLogger); - const helmDepManager = new HelmDependencyManager(downloader, zippy, testLogger); - const depManagerMap = new Map().set(constants.HELM, helmDepManager); - const depManager = new DependencyManager(testLogger, depManagerMap); - const keyManager = new KeyManager(testLogger); - const helm = new Helm(testLogger); - const chartManager = new ChartManager(helm, testLogger); - const k8 = k8Arg || new K8(configManager, testLogger); - const accountManager = new AccountManager(testLogger, k8); - const platformInstaller = new PlatformInstaller(testLogger, k8, configManager); - const profileManager = new ProfileManager(testLogger, configManager); - const leaseManager = new LeaseManager(k8, configManager, testLogger, new IntervalLeaseRenewalService()); - const certificateManager = new CertificateManager(k8, testLogger, configManager); - const localConfig = new LocalConfig(path.join(BASE_TEST_DIR, 'local-config.yaml'), testLogger, configManager); - const remoteConfigManager = new RemoteConfigManager(k8, testLogger, localConfig, configManager); + + const downloader = container.resolve(PackageDownloader); + const depManager = container.resolve(DependencyManager); + const helm = container.resolve(Helm); + const chartManager = container.resolve(ChartManager); + const keyManager = container.resolve(KeyManager); + const k8 = k8Arg || container.resolve(K8); + const accountManager = container.resolve(AccountManager); + const platformInstaller = container.resolve(PlatformInstaller); + const profileManager = container.resolve(ProfileManager); + const leaseManager = container.resolve(LeaseManager); + const certificateManager = container.resolve(CertificateManager); + const localConfig = new LocalConfig(path.join(BASE_TEST_DIR, 'local-config.yaml')); + const remoteConfigManager = container.resolve(RemoteConfigManager); const opts: TestOpts = { logger: testLogger, @@ -434,7 +437,7 @@ async function addKeyHashToMap( export function getK8Instance(configManager: ConfigManager) { try { - return new K8(configManager, testLogger); + return container.resolve(K8); // TODO: return a mock without running the init within constructor after we convert to Mocha, Jest ESModule mocks are broke. } catch (e) { if (!(e instanceof SoloError)) { @@ -448,7 +451,7 @@ export function getK8Instance(configManager: ConfigManager) { // Create cluster execSync(`kind create cluster --name "${process.env.SOLO_CLUSTER_NAME}"`, {stdio: 'inherit'}); - return new K8(configManager, testLogger); + return container.resolve(K8); } } diff --git a/test/unit/commands/base.test.ts b/test/unit/commands/base.test.ts index 2df6be98e..589154483 100644 --- a/test/unit/commands/base.test.ts +++ b/test/unit/commands/base.test.ts @@ -16,13 +16,10 @@ */ import {expect} from 'chai'; -import {HelmDependencyManager, DependencyManager} from '../../../src/core/dependency_managers/index.js'; +import {DependencyManager} from '../../../src/core/dependency_managers/index.js'; import {Helm} from '../../../src/core/helm.js'; import {ChartManager} from '../../../src/core/chart_manager.js'; import {ConfigManager} from '../../../src/core/config_manager.js'; -import {PackageDownloader} from '../../../src/core/package_downloader.js'; -import {Zippy} from '../../../src/core/zippy.js'; -import * as constants from '../../../src/core/constants.js'; import {LocalConfig} from '../../../src/core/config/local_config.js'; import {RemoteConfigManager} from '../../../src/core/config/remote/remote_config_manager.js'; import {K8} from '../../../src/core/k8.js'; @@ -30,34 +27,36 @@ import * as logging from '../../../src/core/logging.js'; import {BaseCommand} from '../../../src/commands/base.js'; import {Flags as flags} from '../../../src/commands/flags.js'; import sinon from 'sinon'; -import path from 'path'; -import {BASE_TEST_DIR} from '../../test_util.js'; - -const testLogger = logging.NewLogger('debug', true); - -describe('BaseCommand', () => { - const helm = new Helm(testLogger); - const chartManager = new ChartManager(helm, testLogger); - const configManager = new ConfigManager(testLogger); - - // prepare dependency manger registry - const downloader = new PackageDownloader(testLogger); - const zippy = new Zippy(testLogger); - const helmDepManager = new HelmDependencyManager(downloader, zippy, testLogger); - const depManagerMap = new Map().set(constants.HELM, helmDepManager); - const depManager = new DependencyManager(testLogger, depManagerMap); - const localConfig = new LocalConfig(path.join(BASE_TEST_DIR, 'local-config.yaml'), testLogger, configManager); - const remoteConfigManager = new RemoteConfigManager({} as any, testLogger, localConfig, configManager); - +import {container} from 'tsyringe-neo'; +import {SoloLogger} from "../../../src/core/logging.js"; +import {resetTestContainer} from "../../test_container.js"; + +describe.only('BaseCommand', () => { + let helm: Helm; + let chartManager: ChartManager; + let configManager: ConfigManager; + let depManager: DependencyManager; + let localConfig: LocalConfig; + let remoteConfigManager: RemoteConfigManager; let sandbox = sinon.createSandbox(); + let testLogger: SoloLogger; let baseCmd: BaseCommand; describe('runShell', () => { before(() => { - sandbox = sinon.createSandbox(); + // resetTestContainer(); + testLogger = container.resolve(SoloLogger); + helm = container.resolve(Helm); + chartManager = container.resolve(ChartManager); + configManager = container.resolve(ConfigManager); + depManager = container.resolve(DependencyManager); + localConfig = container.resolve(LocalConfig); + remoteConfigManager = container.resolve(RemoteConfigManager); + + sandbox = sinon.createSandbox(); sandbox.stub(K8.prototype, 'init').callsFake(() => this); - const k8 = new K8(configManager, testLogger); + const k8 = container.resolve(K8); // @ts-ignore baseCmd = new BaseCommand({ diff --git a/test/unit/commands/cluster.test.ts b/test/unit/commands/cluster.test.ts index 5eb726bbc..bb2af11ff 100644 --- a/test/unit/commands/cluster.test.ts +++ b/test/unit/commands/cluster.test.ts @@ -29,6 +29,7 @@ import {ChartManager} from '../../../src/core/chart_manager.js'; import {Helm} from '../../../src/core/helm.js'; import {ROOT_DIR} from '../../../src/core/constants.js'; import path from 'path'; +import {container} from 'tsyringe-neo'; const getBaseCommandOpts = () => ({ logger: sinon.stub(), @@ -61,13 +62,14 @@ describe('ClusterCommand unit tests', () => { beforeEach(() => { opts = getBaseCommandOpts(); opts.logger = new SoloLogger(); - opts.helm = new Helm(opts.logger); + opts.helm = container.resolve(Helm); + opts.chartManager = container.resolve(ChartManager); opts.helm.dependency = sinon.stub(); - opts.chartManager = new ChartManager(opts.helm, opts.logger); + opts.chartManager.isChartInstalled = sinon.stub().returns(false); opts.chartManager.install = sinon.stub().returns(true); - opts.configManager = new ConfigManager(opts.logger); + opts.configManager = container.resolve(ConfigManager); opts.remoteConfigManager = sinon.stub(); }); diff --git a/test/unit/commands/context.test.ts b/test/unit/commands/context.test.ts index b8381c2eb..ceea764dc 100644 --- a/test/unit/commands/context.test.ts +++ b/test/unit/commands/context.test.ts @@ -100,7 +100,7 @@ describe('ContextCommandTasks unit tests', () => { chartManager: sandbox.createStubInstance(ChartManager), configManager, depManager: sandbox.createStubInstance(DependencyManager), - localConfig: new LocalConfig(filePath, loggerStub, configManager), + localConfig: new LocalConfig(filePath), downloader: sandbox.createStubInstance(PackageDownloader), keyManager: sandbox.createStubInstance(KeyManager), accountManager: sandbox.createStubInstance(AccountManager), @@ -156,7 +156,7 @@ describe('ContextCommandTasks unit tests', () => { }; const opts = getBaseCommandOpts(sandbox, remoteConfig, []); command = await runUpdateLocalConfigTask(opts); // @ts-ignore - localConfig = new LocalConfig(filePath, loggerStub, command.configManager); + localConfig = new LocalConfig(filePath); expect(localConfig.currentDeploymentName).to.equal('deployment'); expect(localConfig.getCurrentDeployment().clusters).to.deep.equal(['cluster-2']); @@ -174,7 +174,7 @@ describe('ContextCommandTasks unit tests', () => { }; const opts = getBaseCommandOpts(sandbox, remoteConfig, [[flags.context, 'provided-context']]); command = await runUpdateLocalConfigTask(opts); // @ts-ignore - localConfig = new LocalConfig(filePath, loggerStub, command.configManager); + localConfig = new LocalConfig(filePath); expect(localConfig.currentDeploymentName).to.equal('deployment'); expect(localConfig.getCurrentDeployment().clusters).to.deep.equal(['cluster-2']); @@ -196,7 +196,7 @@ describe('ContextCommandTasks unit tests', () => { [flags.context, 'provided-context-2,provided-context-3,provided-context-4'], ]); command = await runUpdateLocalConfigTask(opts); // @ts-ignore - localConfig = new LocalConfig(filePath, loggerStub, command.configManager); + localConfig = new LocalConfig(filePath); expect(localConfig.currentDeploymentName).to.equal('deployment'); expect(localConfig.getCurrentDeployment().clusters).to.deep.equal(['cluster-2', 'cluster-3', 'cluster-4']); @@ -217,7 +217,7 @@ describe('ContextCommandTasks unit tests', () => { }; const opts = getBaseCommandOpts(sandbox, remoteConfig, [[flags.quiet, true]]); command = await runUpdateLocalConfigTask(opts); // @ts-ignore - localConfig = new LocalConfig(filePath, loggerStub, command.configManager); + localConfig = new LocalConfig(filePath); expect(localConfig.currentDeploymentName).to.equal('deployment'); expect(localConfig.getCurrentDeployment().clusters).to.deep.equal(['cluster-2', 'cluster-3']); @@ -238,7 +238,7 @@ describe('ContextCommandTasks unit tests', () => { const opts = getBaseCommandOpts(sandbox, remoteConfig, []); command = await runUpdateLocalConfigTask(opts); // @ts-ignore - localConfig = new LocalConfig(filePath, loggerStub, command.configManager); + localConfig = new LocalConfig(filePath); expect(localConfig.currentDeploymentName).to.equal('deployment'); expect(localConfig.getCurrentDeployment().clusters).to.deep.equal(['cluster-2', 'new-cluster']); diff --git a/test/unit/commands/network.test.ts b/test/unit/commands/network.test.ts index 57a0988c7..20463f53c 100644 --- a/test/unit/commands/network.test.ts +++ b/test/unit/commands/network.test.ts @@ -41,6 +41,7 @@ import {KeyManager} from '../../../src/core/key_manager.js'; import {ROOT_DIR} from '../../../src/core/constants.js'; import {ListrLease} from '../../../src/core/lease/listr_lease.js'; import {GenesisNetworkDataConstructor} from '../../../src/core/genesis_network_models/genesis_network_data_constructor.js'; +import {container} from 'tsyringe-neo'; const getBaseCommandOpts = () => ({ logger: sinon.stub(), @@ -70,16 +71,19 @@ argv[flags.chartDirectory.name] = undefined; describe('NetworkCommand unit tests', () => { describe('Chart Install Function is called correctly', () => { let opts: any; + let bootstrapResp: any; - const bootstrapResp = bootstrapTestVariables(testName, argv); + before(() => { + bootstrapResp = bootstrapTestVariables(testName, argv); + }) beforeEach(() => { opts = getBaseCommandOpts(); opts.logger = testLogger; - opts.helm = new Helm(opts.logger); + opts.helm = container.resolve(Helm); opts.helm.dependency = sinon.stub(); - opts.configManager = new ConfigManager(testLogger); + opts.configManager = container.resolve(ConfigManager); opts.configManager.update(argv); opts.k8 = sinon.stub(); opts.k8.hasNamespace = sinon.stub().returns(true); @@ -93,25 +97,27 @@ describe('NetworkCommand unit tests', () => { run: sinon.stub().returns({}), }); - opts.keyManager = new KeyManager(testLogger); + opts.keyManager = container.resolve(KeyManager); opts.keyManager.copyGossipKeysToStaging = sinon.stub(); opts.keyManager.copyNodeKeysToStaging = sinon.stub(); opts.platformInstaller = sinon.stub(); opts.platformInstaller.copyNodeKeys = sinon.stub(); - opts.profileManager = new ProfileManager(testLogger, opts.configManager); + opts.profileManager = container.resolve(ProfileManager); opts.profileManager.prepareValuesForSoloChart = sinon.stub(); opts.certificateManager = sinon.stub(); - opts.chartManager = new ChartManager(opts.helm, opts.logger); + opts.chartManager = container.resolve(ChartManager); opts.chartManager.isChartInstalled = sinon.stub().returns(true); opts.chartManager.isChartInstalled.onSecondCall().returns(false); opts.chartManager.install = sinon.stub().returns(true); - opts.remoteConfigManager = new RemoteConfigManager(opts.k8, opts.logger, opts.localConfig, opts.configManager); - opts.configManager = new ConfigManager(opts.logger); - opts.leaseManager = new LeaseManager(opts.k8, opts.configManager, opts.logger, new IntervalLeaseRenewalService()); + opts.remoteConfigManager = container.resolve(RemoteConfigManager); + + opts.configManager = container.resolve(ConfigManager); + + opts.leaseManager = container.resolve(LeaseManager); opts.leaseManager.currentNamespace = sinon.stub().returns(testName); GenesisNetworkDataConstructor.initialize = sinon.stub().returns(null); diff --git a/test/unit/core/certificate_manager.test.ts b/test/unit/core/certificate_manager.test.ts index 60814eed4..5c5159853 100644 --- a/test/unit/core/certificate_manager.test.ts +++ b/test/unit/core/certificate_manager.test.ts @@ -24,6 +24,7 @@ import {CertificateManager} from '../../../src/core/certificate_manager.js'; import {Flags as flags} from '../../../src/commands/flags.js'; import {testLogger} from '../../test_util.js'; import {SoloError} from '../../../src/core/errors.js'; +import {container} from 'tsyringe-neo'; describe('Certificate Manager', () => { const argv = {}; @@ -35,10 +36,10 @@ describe('Certificate Manager', () => { before(() => { argv[flags.namespace.name] = 'namespace'; - const configManager = new ConfigManager(testLogger); + const configManager = container.resolve(ConfigManager); configManager.update(argv); - k8 = new K8(configManager, testLogger); - certificateManager = new CertificateManager(k8, testLogger, configManager); + k8 = container.resolve(K8); + certificateManager = container.resolve(CertificateManager); }); after(() => { diff --git a/test/unit/core/config_manager.test.ts b/test/unit/core/config_manager.test.ts index 96aa9512f..c25cba851 100644 --- a/test/unit/core/config_manager.test.ts +++ b/test/unit/core/config_manager.test.ts @@ -20,11 +20,12 @@ import {describe, it} from 'mocha'; import {ConfigManager} from '../../../src/core/config_manager.js'; import {Flags as flags} from '../../../src/commands/flags.js'; import {testLogger} from '../../test_util.js'; +import {container} from 'tsyringe-neo'; describe('ConfigManager', () => { describe('update values using argv', () => { it('should update string flag value', () => { - const cm = new ConfigManager(testLogger); + const cm = container.resolve(ConfigManager); const argv = {}; argv[flags.releaseTag.name] = 'v0.42.5'; @@ -40,7 +41,7 @@ describe('ConfigManager', () => { }); it('should update number flag value', () => { - const cm = new ConfigManager(testLogger); + const cm = container.resolve(ConfigManager); const argv = {}; argv[flags.replicaCount.name] = 1; @@ -56,7 +57,7 @@ describe('ConfigManager', () => { }); it('should update boolean flag value', () => { - const cm = new ConfigManager(testLogger); + const cm = container.resolve(ConfigManager); // boolean values should work const argv = {}; @@ -87,7 +88,7 @@ describe('ConfigManager', () => { it('should take user input as the first preference', () => { // Given: config has value, argv has a different value // Expected: argv should retain the value - const cm = new ConfigManager(testLogger); + const cm = container.resolve(ConfigManager); cm.setFlag(flags.devMode, false); expect(cm.getFlag(flags.devMode)).not.to.be.ok; @@ -102,7 +103,7 @@ describe('ConfigManager', () => { it('should take default as the last preference', () => { // Given: neither config nor argv has the flag value set // Expected: argv should inherit the default flag value - const cm = new ConfigManager(testLogger); + const cm = container.resolve(ConfigManager); expect(cm.hasFlag(flags.devMode)).not.to.be.ok; // shouldn't have set const argv = {}; // devMode flag is not set in argv and cached config doesn't have it either diff --git a/test/unit/core/dependency_managers/dependency_manager.test.ts b/test/unit/core/dependency_managers/dependency_manager.test.ts index 5e4274f79..38d8d4518 100644 --- a/test/unit/core/dependency_managers/dependency_manager.test.ts +++ b/test/unit/core/dependency_managers/dependency_manager.test.ts @@ -17,20 +17,15 @@ import {expect} from 'chai'; import {describe, it} from 'mocha'; -import {DependencyManager, HelmDependencyManager} from '../../../../src/core/dependency_managers/index.js'; -import {PackageDownloader} from '../../../../src/core/package_downloader.js'; -import {Zippy} from '../../../../src/core/zippy.js'; -import * as constants from '../../../../src/core/constants.js'; +import {DependencyManager} from '../../../../src/core/dependency_managers/index.js'; import * as logging from '../../../../src/core/logging.js'; +import {container} from 'tsyringe-neo'; const testLogger = logging.NewLogger('debug', true); describe('DependencyManager', () => { // prepare dependency manger registry - const downloader = new PackageDownloader(testLogger); - const zippy = new Zippy(testLogger); - const helmDepManager = new HelmDependencyManager(downloader, zippy, testLogger); - const depManagerMap: Map = new Map().set(constants.HELM, helmDepManager); - const depManager = new DependencyManager(testLogger, depManagerMap); + + const depManager = container.resolve(DependencyManager); describe('checkDependency', () => { it('should fail during invalid dependency check', async () => { diff --git a/test/unit/core/helm.test.ts b/test/unit/core/helm.test.ts index 2abfb2db1..0c944d1e6 100644 --- a/test/unit/core/helm.test.ts +++ b/test/unit/core/helm.test.ts @@ -28,7 +28,7 @@ import {ShellRunner} from '../../../src/core/shell_runner.js'; describe('Helm platform specific tests', () => { each(['linux', 'windows', 'darwin']).describe('Helm on %s platform', osPlatform => { const logger = logging.NewLogger('debug', true); - const helm = new Helm(logger, osPlatform); + const helm = new Helm(osPlatform); let shellStub: sinon.SinonStub<[cmd: string, verbose?: boolean], Promise>; diff --git a/test/unit/core/k8.test.ts b/test/unit/core/k8.test.ts index bef75fb7f..28a46e0f6 100644 --- a/test/unit/core/k8.test.ts +++ b/test/unit/core/k8.test.ts @@ -24,6 +24,7 @@ import {ConfigManager} from '../../../src/core/config_manager.js'; import {testLogger} from '../../test_util.js'; import {Flags as flags} from '../../../src/commands/flags.js'; import {Duration} from '../../../src/core/time/duration.js'; +import {container} from 'tsyringe-neo'; function listNamespacedPodMockSetup(k8: K8, numOfFailures: number, result: any) { for (let i = 0; i < numOfFailures - 1; i++) { @@ -72,9 +73,9 @@ describe('K8 Unit Tests', function () { before(() => { argv[flags.namespace.name] = 'namespace'; - const configManager = new ConfigManager(testLogger); + const configManager = container.resolve(ConfigManager); configManager.update(argv); - k8 = new K8(configManager, testLogger); + k8 = container.resolve(K8); k8.kubeClient = { // @ts-ignore listNamespacedPod: jest.fn(), diff --git a/test/unit/core/key_manager.test.ts b/test/unit/core/key_manager.test.ts index 9662f43f3..df32a6d99 100644 --- a/test/unit/core/key_manager.test.ts +++ b/test/unit/core/key_manager.test.ts @@ -25,10 +25,11 @@ import * as constants from '../../../src/core/constants.js'; import * as logging from '../../../src/core/logging.js'; import type {NodeAlias} from '../../../src/types/aliases.js'; import {Duration} from '../../../src/core/time/duration.js'; +import {container} from 'tsyringe-neo'; describe('KeyManager', () => { const logger = logging.NewLogger('debug', true); - const keyManager = new KeyManager(logger); + const keyManager = container.resolve(KeyManager); it('should generate signing key', async () => { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'keys-')); diff --git a/test/unit/core/local_config.test.ts b/test/unit/core/local_config.test.ts index 4dc78a699..99de98df3 100644 --- a/test/unit/core/local_config.test.ts +++ b/test/unit/core/local_config.test.ts @@ -33,7 +33,7 @@ describe('LocalConfig', () => { const expectFailedValidation = expectedMessage => { try { - new LocalConfig(filePath, testLogger, configManager); + new LocalConfig(filePath); expect.fail('Expected an error to be thrown'); } catch (error) { expect(error).to.be.instanceOf(SoloError); @@ -43,7 +43,7 @@ describe('LocalConfig', () => { beforeEach(async () => { await fs.promises.writeFile(filePath, stringify(config)); - localConfig = new LocalConfig(filePath, testLogger, configManager); + localConfig = new LocalConfig(filePath); }); afterEach(async () => { @@ -65,7 +65,7 @@ describe('LocalConfig', () => { await localConfig.write(); // reinitialize with updated config file - const newConfig = new LocalConfig(filePath, testLogger, configManager); + const newConfig = new LocalConfig(filePath); expect(newConfig.userEmailAddress).to.eq(newEmailAddress); }); @@ -92,7 +92,7 @@ describe('LocalConfig', () => { expect(localConfig.deployments).to.deep.eq(newDeployments); await localConfig.write(); - const newConfig = new LocalConfig(filePath, testLogger, configManager); + const newConfig = new LocalConfig(filePath); expect(newConfig.deployments).to.deep.eq(newDeployments); }); @@ -160,7 +160,7 @@ describe('LocalConfig', () => { expect(localConfig.currentDeploymentName).to.eq(newCurrentDeployment); await localConfig.write(); - const newConfig = new LocalConfig(filePath, testLogger, configManager); + const newConfig = new LocalConfig(filePath); expect(newConfig.currentDeploymentName).to.eq(newCurrentDeployment); }); @@ -184,7 +184,7 @@ describe('LocalConfig', () => { it('should throw an error if file path is not set', async () => { try { - new LocalConfig('', testLogger, configManager); + new LocalConfig(''); expect.fail('Expected an error to be thrown'); } catch (error) { expect(error).to.be.instanceOf(MissingArgumentError); diff --git a/test/unit/core/platform_installer.test.ts b/test/unit/core/platform_installer.test.ts index 0506ea20b..720116b48 100644 --- a/test/unit/core/platform_installer.test.ts +++ b/test/unit/core/platform_installer.test.ts @@ -27,14 +27,18 @@ import * as logging from '../../../src/core/logging.js'; import {IllegalArgumentError, MissingArgumentError} from '../../../src/core/errors.js'; import {getK8Instance} from '../../test_util.js'; import type {PodName} from '../../../src/types/aliases.js'; +import {container} from 'tsyringe-neo'; +import {K8} from "../../../src/core/k8.js"; +import {SoloLogger} from "../../../src/core/logging.js"; describe('PackageInstaller', () => { - const testLogger = logging.NewLogger('debug', true); - const configManager = new ConfigManager(testLogger); - - const k8 = getK8Instance(configManager); - - const installer = new PlatformInstaller(testLogger, k8, configManager); + let testLogger: SoloLogger, configManager: ConfigManager, k8: K8, installer: PlatformInstaller; + before(() => { + testLogger = logging.NewLogger('debug', true); + configManager = container.resolve(ConfigManager); + k8 = getK8Instance(configManager); + installer = container.resolve(PlatformInstaller); + }) describe('validatePlatformReleaseDir', () => { it('should fail for missing path', () => { diff --git a/test/unit/core/profile_manager.test.ts b/test/unit/core/profile_manager.test.ts index a4b01a417..961836487 100644 --- a/test/unit/core/profile_manager.test.ts +++ b/test/unit/core/profile_manager.test.ts @@ -27,22 +27,30 @@ import {ProfileManager} from '../../../src/core/profile_manager.js'; import {getTestCacheDir, getTmpDir, testLogger} from '../../test_util.js'; import * as version from '../../../version.js'; import type {NodeAlias} from '../../../src/types/aliases.js'; +import {container} from 'tsyringe-neo'; + -const tmpDir = getTmpDir(); -const configManager = new ConfigManager(testLogger); -const profileManager = new ProfileManager(testLogger, configManager, tmpDir); -configManager.setFlag(flags.nodeAliasesUnparsed, 'node1,node2,node4'); -const testProfileFile = path.join('test', 'data', 'test-profiles.yaml'); -configManager.setFlag(flags.cacheDir, getTestCacheDir('ProfileManager')); -configManager.setFlag(flags.releaseTag, version.HEDERA_PLATFORM_VERSION); -const cacheDir = configManager.getFlag(flags.cacheDir) as string; -configManager.setFlag(flags.apiPermissionProperties, path.join(cacheDir, 'templates', 'api-permission.properties')); -configManager.setFlag(flags.applicationProperties, path.join(cacheDir, 'templates', 'application.properties')); -configManager.setFlag(flags.bootstrapProperties, path.join(cacheDir, 'templates', 'bootstrap.properties')); -configManager.setFlag(flags.log4j2Xml, path.join(cacheDir, 'templates', 'log4j2.xml')); -configManager.setFlag(flags.settingTxt, path.join(cacheDir, 'templates', 'settings.txt')); describe('ProfileManager', () => { + let tmpDir: string, configManager: ConfigManager, profileManager: ProfileManager, testProfileFile: string, + cacheDir: string; + + before(() => { + tmpDir = getTmpDir(); + configManager = container.resolve(ConfigManager); + profileManager = new ProfileManager(tmpDir); + configManager.setFlag(flags.nodeAliasesUnparsed, 'node1,node2,node4'); + testProfileFile = path.join('test', 'data', 'test-profiles.yaml'); + configManager.setFlag(flags.cacheDir, getTestCacheDir('ProfileManager')); + configManager.setFlag(flags.releaseTag, version.HEDERA_PLATFORM_VERSION); + cacheDir = configManager.getFlag(flags.cacheDir) as string; + configManager.setFlag(flags.apiPermissionProperties, path.join(cacheDir, 'templates', 'api-permission.properties')); + configManager.setFlag(flags.applicationProperties, path.join(cacheDir, 'templates', 'application.properties')); + configManager.setFlag(flags.bootstrapProperties, path.join(cacheDir, 'templates', 'bootstrap.properties')); + configManager.setFlag(flags.log4j2Xml, path.join(cacheDir, 'templates', 'log4j2.xml')); + configManager.setFlag(flags.settingTxt, path.join(cacheDir, 'templates', 'settings.txt')); + }); + after(() => { fs.rmSync(tmpDir, {recursive: true}); }); diff --git a/test/unit/core/shell_runner.test.ts b/test/unit/core/shell_runner.test.ts index 886fef943..4abd8d4f1 100644 --- a/test/unit/core/shell_runner.test.ts +++ b/test/unit/core/shell_runner.test.ts @@ -35,7 +35,7 @@ describe('ShellRunner', () => { beforeEach(() => { logger = NewLogger('debug'); - shellRunner = new ShellRunner(logger); + shellRunner = new ShellRunner(); // Spy on methods loggerStub = sinon.stub(SoloLogger.prototype, 'debug');