diff --git a/package-lock.json b/package-lock.json index 5772d89c9..368276831 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ ], "dependencies": { "@hashgraph/sdk": "^2.56.0", + "@inquirer/prompts": "^7.2.3", "@kubernetes/client-node": "^0.22.3", "@listr2/prompt-adapter-enquirer": "^2.0.12", "@peculiar/x509": "^1.12.3", @@ -24,12 +25,10 @@ "class-validator": "^0.14.1", "dot-object": "^2.1.5", "dotenv": "^16.4.7", - "enquirer": "^2.4.1", "esm": "^3.2.25", "figlet": "^1.8.0", "got": "^14.4.5", "http-status-codes": "^2.3.0", - "inquirer": "^12.3.2", "ip": "^2.0.1", "js-base64": "^3.7.7", "listr2": "^8.2.5", @@ -1542,6 +1541,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.2.3.tgz", "integrity": "sha512-hzfnm3uOoDySDXfDNOm9usOuYIaQvTgKp/13l1uJoe6UNY+Zpcn2RYt0jXz3yA+yemGHvDOxVzqWl3S5sQq53Q==", + "license": "MIT", "dependencies": { "@inquirer/checkbox": "^4.0.6", "@inquirer/confirm": "^5.1.3", @@ -4967,6 +4967,8 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "license": "MIT", + "peer": true, "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -6855,26 +6857,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/inquirer": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.3.2.tgz", - "integrity": "sha512-YjQCIcDd3yyDuQrbII0FBtm/ZqNoWtvaC71yeCnd5Vbg4EgzsAGaemzfpzmqfvIZEp2roSwuZZKdM0C65hA43g==", - "dependencies": { - "@inquirer/core": "^10.1.4", - "@inquirer/prompts": "^7.2.3", - "@inquirer/type": "^3.0.2", - "ansi-escapes": "^4.3.2", - "mute-stream": "^2.0.0", - "run-async": "^3.0.0", - "rxjs": "^7.8.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - } - }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -11194,14 +11176,6 @@ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" }, - "node_modules/run-async": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", - "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -11230,6 +11204,7 @@ "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, "dependencies": { "tslib": "^2.1.0" } diff --git a/package.json b/package.json index 06ac2d37b..7453cbdc9 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "license": "Apache2.0", "dependencies": { "@hashgraph/sdk": "^2.56.0", + "@inquirer/prompts": "^7.2.3", "@kubernetes/client-node": "^0.22.3", "@listr2/prompt-adapter-enquirer": "^2.0.12", "@peculiar/x509": "^1.12.3", @@ -57,12 +58,10 @@ "class-validator": "^0.14.1", "dot-object": "^2.1.5", "dotenv": "^16.4.7", - "enquirer": "^2.4.1", "esm": "^3.2.25", "figlet": "^1.8.0", "got": "^14.4.5", "http-status-codes": "^2.3.0", - "inquirer": "^12.3.2", "ip": "^2.0.1", "js-base64": "^3.7.7", "listr2": "^8.2.5", diff --git a/src/commands/deployment.ts b/src/commands/deployment.ts index 87614643f..596e39b47 100644 --- a/src/commands/deployment.ts +++ b/src/commands/deployment.ts @@ -124,7 +124,7 @@ export class DeploymentCommand extends BaseCommand { }); }, }, - ListrRemoteConfig.createRemoteConfigInMultipleClusters(this), + ListrRemoteConfig.createRemoteConfigInMultipleClusters(this, argv), ], { concurrent: false, diff --git a/src/commands/mirror_node.ts b/src/commands/mirror_node.ts index 75c70203f..9ff4eefbb 100644 --- a/src/commands/mirror_node.ts +++ b/src/commands/mirror_node.ts @@ -507,7 +507,7 @@ export class MirrorNodeCommand extends BaseCommand { await tasks.run(); self.logger.debug('mirror node destruction has completed'); } catch (e) { - throw new SoloError(`Error destrong mirror node: ${e.message}`, e); + throw new SoloError(`Error destroying mirror node: ${e.message}`, e); } finally { await lease.release(); await self.accountManager.close(); diff --git a/src/core/config/remote/common_flags_data_wrapper.ts b/src/core/config/remote/common_flags_data_wrapper.ts new file mode 100644 index 000000000..dbd29041e --- /dev/null +++ b/src/core/config/remote/common_flags_data_wrapper.ts @@ -0,0 +1,124 @@ +/** + * 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 {Flags as flags} from '../../../commands/flags.js'; +import type {ToObject} from '../../../types/index.js'; +import type {RemoteConfigCommonFlagsStruct} from './types.js'; +import type {ConfigManager} from '../../config_manager.js'; +import type {CommandFlag} from '../../../types/flag_types.js'; +import type {AnyObject} from '../../../types/aliases.js'; +import {select} from '@inquirer/prompts'; + +export class CommonFlagsDataWrapper implements ToObject { + private static readonly COMMON_FLAGS: CommandFlag[] = [ + flags.releaseTag, + flags.chartDirectory, + flags.relayReleaseTag, + flags.soloChartVersion, + flags.mirrorNodeVersion, + flags.nodeAliasesUnparsed, + flags.hederaExplorerVersion, + ]; + + private constructor( + private readonly configManager: ConfigManager, + private readonly flags: RemoteConfigCommonFlagsStruct, + ) {} + + /** + * Updates the flags or populates them inside the remote config + */ + public async handleFlags(argv: AnyObject): Promise { + for (const flag of CommonFlagsDataWrapper.COMMON_FLAGS) { + await this.handleFlag(flag, argv); + } + } + + private async handleFlag(flag: CommandFlag, argv: AnyObject): Promise { + const detectFlagMismatch = async () => { + const oldValue = this.flags[flag.constName] as string; + const newValue = this.configManager.getFlag(flag); + + // if the old value is not present, override it with the new one + if (!oldValue && newValue) { + this.flags[flag.constName] = newValue; + return; + } + + // if its present but there is a mismatch warn user + else if (oldValue && oldValue !== newValue) { + const isQuiet = this.configManager.getFlag(flags.quiet); + const isForced = this.configManager.getFlag(flags.force); + + // if the quiet or forced flag is passed don't prompt the user + if (isQuiet === true || isForced === true) return; + + const answer = await select({ + message: 'Value in remote config differs with the one you are passing, choose which you want to use', + choices: [ + { + name: `[old value] ${oldValue}`, + value: oldValue, + }, + { + name: `[new value] ${newValue}`, + value: newValue, + }, + ], + }); + + // Override if user chooses new the new value, else override and keep the old one + if (answer === newValue) { + this.flags[flag.constName] = newValue; + } else { + this.configManager.setFlag(flag, oldValue); + argv[flag.constName] = oldValue; + } + } + }; + + // if the flag is set, inspect the value + if (this.configManager.hasFlag(flag)) { + await detectFlagMismatch(); + } + + // use remote config value if no user supplied value + else if (this.flags[flag.constName]) { + argv[flag.constName] = this.flags[flag.constName]; + this.configManager.setFlag(flag, this.flags[flag.constName]); + } + } + + public static async initialize(configManager: ConfigManager, argv: AnyObject): Promise { + const commonFlagsDataWrapper = new CommonFlagsDataWrapper(configManager, {}); + await commonFlagsDataWrapper.handleFlags(argv); + return commonFlagsDataWrapper; + } + + public static fromObject(configManager: ConfigManager, data: RemoteConfigCommonFlagsStruct): CommonFlagsDataWrapper { + return new CommonFlagsDataWrapper(configManager, data); + } + + public toObject(): RemoteConfigCommonFlagsStruct { + return { + nodeAliasesUnparsed: this.flags.nodeAliasesUnparsed, + releaseTag: this.flags.releaseTag, + relayReleaseTag: this.flags.relayReleaseTag, + hederaExplorerVersion: this.flags.hederaExplorerVersion, + mirrorNodeVersion: this.flags.mirrorNodeVersion, + }; + } +} diff --git a/src/core/config/remote/components_data_wrapper.ts b/src/core/config/remote/components_data_wrapper.ts index 117673fdd..31d40b2aa 100644 --- a/src/core/config/remote/components_data_wrapper.ts +++ b/src/core/config/remote/components_data_wrapper.ts @@ -23,25 +23,14 @@ import {MirrorNodeComponent} from './components/mirror_node_component.js'; import {EnvoyProxyComponent} from './components/envoy_proxy_component.js'; import {ConsensusNodeComponent} from './components/consensus_node_component.js'; import {MirrorNodeExplorerComponent} from './components/mirror_node_explorer_component.js'; -import { - type Component, - type ComponentsDataStructure, - type IConsensusNodeComponent, - type IRelayComponent, - type ComponentName, - type Cluster, - type Namespace, +import type { + Component, + ComponentsDataStructure, + IConsensusNodeComponent, + IRelayComponent, + ComponentName, } from './types.js'; import type {ToObject, Validate} from '../../../types/index.js'; -import type {RemoteConfigMetadata} from './metadata.js'; - -export interface RemoteConfigData { - metadata: RemoteConfigMetadata; - clusters: Record; - components: ComponentsDataWrapper; - lastExecutedCommand: string; - commandHistory: string[]; -} /** * Represent the components in the remote config and handles: @@ -166,7 +155,6 @@ export class ComponentsDataWrapper implements Validate, ToObject { return { title: `Create remote config in cluster: ${chalk.cyan(cluster)}`, task: async (): Promise => { - await command.getRemoteConfigManager().createAndValidate(cluster, context, namespace); + await command.getRemoteConfigManager().createAndValidate(cluster, context, namespace, argv); }, }; } @@ -73,8 +70,9 @@ export class ListrRemoteConfig { * Create a remoteConfig object and save it to multiple clusters, read from ctx config * * @param command - the BaseCommand object on which an action will be performed + * @param argv */ - public static createRemoteConfigInMultipleClusters(command: BaseCommand): SoloListrTask { + public static createRemoteConfigInMultipleClusters(command: BaseCommand, argv: AnyObject): SoloListrTask { return { title: 'Create remoteConfig in clusters', task: async (ctx, task) => { @@ -84,7 +82,7 @@ export class ListrRemoteConfig { const context = command.localConfig.clusterContextMapping?.[cluster]; if (!context) continue; - subTasks.push(ListrRemoteConfig.createRemoteConfig(command, cluster, context, ctx.config.namespace)); + subTasks.push(ListrRemoteConfig.createRemoteConfig(command, cluster, context, ctx.config.namespace, argv)); } return task.newListr(subTasks, { diff --git a/src/core/config/remote/metadata.ts b/src/core/config/remote/metadata.ts index 577df08a7..a6680babb 100644 --- a/src/core/config/remote/metadata.ts +++ b/src/core/config/remote/metadata.ts @@ -17,16 +17,9 @@ import {Migration} from './migration.js'; import {SoloError} from '../../errors.js'; import * as k8s from '@kubernetes/client-node'; -import type {EmailAddress, Namespace, Version} from './types.js'; +import type {EmailAddress, Namespace, RemoteConfigMetadataStructure, Version} from './types.js'; import type {Optional, ToObject, Validate} from '../../../types/index.js'; -export interface RemoteConfigMetadataStructure { - name: Namespace; - lastUpdatedAt: Date; - lastUpdateBy: EmailAddress; - migration?: Migration; -} - /** * Represent the remote config metadata object and handles: * - Validation diff --git a/src/core/config/remote/remote_config_data.ts b/src/core/config/remote/remote_config_data.ts new file mode 100644 index 000000000..3e206eb00 --- /dev/null +++ b/src/core/config/remote/remote_config_data.ts @@ -0,0 +1,29 @@ +/** + * 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 type {RemoteConfigMetadata} from './metadata.js'; +import type {ComponentsDataWrapper} from './components_data_wrapper.js'; +import type {CommonFlagsDataWrapper} from './common_flags_data_wrapper.js'; +import {type Cluster, type Namespace} from './types.js'; + +export interface RemoteConfigData { + metadata: RemoteConfigMetadata; + clusters: Record; + components: ComponentsDataWrapper; + lastExecutedCommand: string; + commandHistory: string[]; + flags: CommonFlagsDataWrapper; +} diff --git a/src/core/config/remote/remote_config_data_wrapper.ts b/src/core/config/remote/remote_config_data_wrapper.ts index 8c014c835..dfb0f5d9a 100644 --- a/src/core/config/remote/remote_config_data_wrapper.ts +++ b/src/core/config/remote/remote_config_data_wrapper.ts @@ -16,21 +16,15 @@ */ import {SoloError} from '../../errors.js'; import * as yaml from 'yaml'; -import {RemoteConfigMetadata, type RemoteConfigMetadataStructure} from './metadata.js'; -import {ComponentsDataWrapper, type RemoteConfigData} from './components_data_wrapper.js'; +import {RemoteConfigMetadata} from './metadata.js'; +import {ComponentsDataWrapper} from './components_data_wrapper.js'; import * as constants from '../../constants.js'; -import {type Cluster, type Version, type Namespace, type ComponentsDataStructure} from './types.js'; +import {CommonFlagsDataWrapper} from './common_flags_data_wrapper.js'; +import type {Cluster, Version, Namespace, RemoteConfigDataStructure} from './types.js'; import type * as k8s from '@kubernetes/client-node'; import type {ToObject, Validate} from '../../../types/index.js'; - -export interface RemoteConfigDataStructure { - metadata: RemoteConfigMetadataStructure; - version: Version; - clusters: Record; - components: ComponentsDataStructure; - commandHistory: string[]; - lastExecutedCommand: string; -} +import type {ConfigManager} from '../../config_manager.js'; +import {type RemoteConfigData} from './remote_config_data.js'; export class RemoteConfigDataWrapper implements Validate, ToObject { private readonly _version: Version = '1.0.0'; @@ -39,6 +33,7 @@ export class RemoteConfigDataWrapper implements Validate, ToObject { + private async create(argv: AnyObject): Promise { const clusters: Record = {}; Object.entries(this.localConfig.deployments).forEach( @@ -117,9 +118,10 @@ export class RemoteConfigManager { this.remoteConfig = new RemoteConfigDataWrapper({ metadata: new RemoteConfigMetadata(this.getNamespace(), new Date(), this.localConfig.userEmailAddress), clusters, - components: ComponentsDataWrapper.initializeEmpty(), - lastExecutedCommand: 'deployment create', commandHistory: ['deployment create'], + lastExecutedCommand: 'deployment create', + components: ComponentsDataWrapper.initializeEmpty(), + flags: await CommonFlagsDataWrapper.initialize(this.configManager, argv), }); await this.createConfigMap(); @@ -147,7 +149,7 @@ export class RemoteConfigManager { const configMap = await this.getConfigMap(); if (!configMap) return false; - this.remoteConfig = RemoteConfigDataWrapper.fromConfigmap(configMap); + this.remoteConfig = RemoteConfigDataWrapper.fromConfigmap(this.configManager, configMap); return true; } @@ -160,7 +162,7 @@ export class RemoteConfigManager { await this.load(); try { await RemoteConfigValidator.validateComponents(this.remoteConfig.components, this.k8); - } catch (e) { + } catch { throw new SoloError(ErrorMessages.REMOTE_CONFIG_IS_INVALID(this.k8.getCurrentClusterName())); } return this.remoteConfig; @@ -212,10 +214,12 @@ export class RemoteConfigManager { const currentCommand = argv._.join(' '); self.remoteConfig!.addCommandToHistory(currentCommand); + await self.remoteConfig.flags.handleFlags(argv); + await self.save(); } - public async createAndValidate(cluster: Cluster, context: Context, namespace: Namespace) { + public async createAndValidate(cluster: Cluster, context: Context, namespace: Namespace, argv: AnyObject) { const self = this; self.k8.setCurrentContext(context); @@ -234,7 +238,7 @@ export class RemoteConfigManager { throw new SoloError('Remote config already exists'); } - await self.create(); + await self.create(argv); } /* ---------- Utilities ---------- */ diff --git a/src/core/config/remote/types.ts b/src/core/config/remote/types.ts index f5f7228d6..52c077d04 100644 --- a/src/core/config/remote/types.ts +++ b/src/core/config/remote/types.ts @@ -45,3 +45,30 @@ export interface IConsensusNodeComponent extends Component { } export type ComponentsDataStructure = Record>; + +export type RemoteConfigCommonFlagsStruct = { + releaseTag?: string; + chartDirectory?: string; + relayReleaseTag?: string; + soloChartVersion?: string; + mirrorNodeVersion?: string; + nodeAliasesUnparsed?: string; + hederaExplorerVersion?: string; +}; + +export interface RemoteConfigDataStructure { + metadata: RemoteConfigMetadataStructure; + version: Version; + clusters: Record; + components: ComponentsDataStructure; + commandHistory: string[]; + lastExecutedCommand: string; + flags: RemoteConfigCommonFlagsStruct; +} + +export interface RemoteConfigMetadataStructure { + name: Namespace; + lastUpdatedAt: Date; + lastUpdateBy: EmailAddress; + migration?: IMigration; +} diff --git a/src/index.ts b/src/index.ts index 11e831515..c1bbf515a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -141,6 +141,7 @@ export function main(argv: any) { (command === 'cluster' && subCommand === 'info') || (command === 'cluster' && subCommand === 'list') || (command === 'deployment' && subCommand === 'create'); + if (!skip) { await remoteConfigManager.loadAndValidate(argv); } diff --git a/test/unit/core/remote_config/remote_config_data_wrapper.test.ts b/test/unit/core/remote_config/remote_config_data_wrapper.test.ts index e1f783295..45b86313e 100644 --- a/test/unit/core/remote_config/remote_config_data_wrapper.test.ts +++ b/test/unit/core/remote_config/remote_config_data_wrapper.test.ts @@ -23,8 +23,16 @@ import {createMetadata} from './metadata.test.js'; import {createComponentsDataWrapper} from './components_data_wrapper.test.js'; import {SoloError} from '../../../../src/core/errors.js'; import * as constants from '../../../../src/core/constants.js'; +import {CommonFlagsDataWrapper} from '../../../../src/core/config/remote/common_flags_data_wrapper.js'; -function createRemoteConfigDataWrapper() { +const configManagerMock = { + update: (...args: any) => true, + getFlag: (...args: any) => true, + hasFlag: (...args: any) => true, + setFlag: (...args: any) => true, +}; + +async function createRemoteConfigDataWrapper() { const {metadata} = createMetadata(); const { wrapper: {componentsDataWrapper}, @@ -34,6 +42,7 @@ function createRemoteConfigDataWrapper() { const components = componentsDataWrapper; const lastExecutedCommand = 'lastExecutedCommand'; const commandHistory = []; + const flags = await CommonFlagsDataWrapper.initialize(configManagerMock as any, {}); const dataWrapper = new RemoteConfigDataWrapper({ metadata, @@ -41,6 +50,7 @@ function createRemoteConfigDataWrapper() { components, lastExecutedCommand, commandHistory, + flags, }); return { @@ -49,11 +59,11 @@ function createRemoteConfigDataWrapper() { }; } -describe('RemoteConfigDataWrapper', () => { +describe('RemoteConfigDataWrapper', async () => { it('should be able to create a instance', () => createRemoteConfigDataWrapper()); - it('should be able to add new command to history with addCommandToHistory()', () => { - const {dataWrapper} = createRemoteConfigDataWrapper(); + it('should be able to add new command to history with addCommandToHistory()', async () => { + const {dataWrapper} = await createRemoteConfigDataWrapper(); const command = 'command'; @@ -69,8 +79,8 @@ describe('RemoteConfigDataWrapper', () => { }); }); - it('should successfully be able to parse yaml and create instance with fromConfigmap()', () => { - const {dataWrapper} = createRemoteConfigDataWrapper(); + it('should successfully be able to parse yaml and create instance with fromConfigmap()', async () => { + const {dataWrapper} = await createRemoteConfigDataWrapper(); const dataWrapperObject = dataWrapper.toObject(); const yamlData = yaml.stringify({ @@ -81,23 +91,37 @@ describe('RemoteConfigDataWrapper', () => { lastExecutedCommand: dataWrapperObject.lastExecutedCommand, }); - // @ts-ignore - RemoteConfigDataWrapper.fromConfigmap({data: {'remote-config-data': yamlData}}); + RemoteConfigDataWrapper.fromConfigmap(configManagerMock as any, {data: {'remote-config-data': yamlData}} as any); }); - it('should fail if invalid data is passed to setters', () => { - const {dataWrapper} = createRemoteConfigDataWrapper(); - - // @ts-ignore - expect(() => (dataWrapper.commandHistory = '')).to.throw(SoloError); // @ts-ignore - expect(() => (dataWrapper.lastExecutedCommand = '')).to.throw(SoloError); // @ts-ignore - expect(() => (dataWrapper.lastExecutedCommand = 1)).to.throw(SoloError); // @ts-ignore - expect(() => (dataWrapper.clusters = 1)).to.throw(SoloError); // @ts-ignore - expect(() => (dataWrapper.clusters = '')).to.throw(SoloError); // @ts-ignore - expect(() => (dataWrapper.components = 1)).to.throw(SoloError); // @ts-ignore - expect(() => (dataWrapper.components = '')).to.throw(SoloError); // @ts-ignore - expect(() => (dataWrapper.metadata = null)).to.throw(SoloError); // @ts-ignore - expect(() => (dataWrapper.metadata = {})).to.throw(SoloError); // @ts-ignore + it('should fail if invalid data is passed to setters', async () => { + const {dataWrapper} = await createRemoteConfigDataWrapper(); + + // @ts-expect-error TS2322: Type string is not assignable to type string[] + expect(() => (dataWrapper.commandHistory = '')).to.throw(SoloError); + + // @ts-expect-error TS2341 Property lastExecutedCommand is private and only accessible within class RemoteConfigDataWrapper + expect(() => (dataWrapper.lastExecutedCommand = '')).to.throw(SoloError); + + // @ts-expect-error TS2341 Property lastExecutedCommand is private and only accessible within class RemoteConfigDataWrapper + expect(() => (dataWrapper.lastExecutedCommand = 1)).to.throw(SoloError); + + // @ts-expect-error TS2322 Type number is not assignable to type Record + expect(() => (dataWrapper.clusters = 1)).to.throw(SoloError); + + // @ts-expect-error TS2322 Type string is not assignable to type Record + expect(() => (dataWrapper.clusters = '')).to.throw(SoloError); + + // @ts-expect-error TS2322 Type number is not assignable to type ComponentsDataWrapper + expect(() => (dataWrapper.components = 1)).to.throw(SoloError); + + // @ts-expect-error TS2322 Type string is not assignable to type ComponentsDataWrapper + expect(() => (dataWrapper.components = '')).to.throw(SoloError); + + expect(() => (dataWrapper.metadata = null)).to.throw(SoloError); + + // @ts-expect-error 2740: Type {} is missing the following properties from type RemoteConfigMetadata + expect(() => (dataWrapper.metadata = {})).to.throw(SoloError); expect(() => (dataWrapper.clusters = {null: null})).to.throw(SoloError); expect(() => (dataWrapper.clusters = {namespace: null})).to.throw(SoloError);