Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions tests/functional/ctst/common/parseGoDuration.test.ts

This file was deleted.

60 changes: 60 additions & 0 deletions tests/functional/ctst/common/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import assert from 'assert';
import { paramToCli, parseGoDuration } from './utils';

const durations: [string, number][] = [
['1m', 60],
['2h', 7200],
['30s', 30],
['2h45m', 9900],
['500ms', 0.5],
['1.5s', 1.5],
['1h30m10s', 5410],
['100ns', 1e-7],
['10us', 1e-5],
['10µs', 1e-5],
['0s', 0],
];

for (const [input, expected] of durations) {
const result = parseGoDuration(input);
assert.strictEqual(
Math.abs(result - expected) < 1e-12, true,
`parseGoDuration("${input}") = ${result}, expected ${expected}`,
);
}

const invalid = ['', 'abc', '1x', '5h 3m', '1', 'm', ' 1m'];
for (const input of invalid) {
assert.throws(
() => parseGoDuration(input),
{ message: /Invalid duration/ },
`parseGoDuration("${input}") should throw`,
);
}

const cliParams: [Record<string, unknown>, string][] = [
// pflag boolean flags must use the "=" form: "--flag false" would set the
// flag to true and drop "false" as a positional argument.
[{ forceRotateServiceCredentials: false }, '--force-rotate-service-credentials=false'],
[{ forceRotateServiceCredentials: true }, '--force-rotate-service-credentials=true'],
[{ wait: true }, '--wait=true'],
[{ sinkZenkoInstance: 'end2end-pra' }, '--sink-zenko-instance end2end-pra'],
[{ kafkaExternalPort: 9092 }, '--kafka-external-port 9092'],
[{ kafkaPersistenceSelector: 'app=kafka-dr-sink' }, '--kafka-persistence-selector app=kafka-dr-sink'],
[{ mongodbHosts: ['host-a', 'host-b'] }, '--mongodb-hosts host-a,host-b'],
[{ timeout: undefined }, ''],
[{ timeout: null }, ''],
[{}, ''],
[
{ sinkZenkoInstance: 'end2end-pra', wait: false, timeout: '30m' },
'--sink-zenko-instance end2end-pra --wait=false --timeout 30m',
],
];

for (const [params, expected] of cliParams) {
const result = paramToCli(params);
assert.strictEqual(
result, expected,
`paramToCli(${JSON.stringify(params)}) = "${result}", expected "${expected}"`,
);
}
24 changes: 24 additions & 0 deletions tests/functional/ctst/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,30 @@ export function parseGoDuration(duration: string): number {
return totalSeconds;
}

/**
* Serialises an options object into arguments for a Go CLI built with cobra/pflag.
* @param {Record<string, unknown>} params - the options to serialise
* @return {string} - the arguments, space-separated
*/
export function paramToCli(params: Record<string, unknown>): string {
const command: string[] = [];
Object.keys(params).forEach(key => {
const value = params[key];
if (value == null) {
return;
}
const flag = `--${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`;
if (typeof value === 'boolean') {
// pflag boolean flags do not consume the next argument: "--flag false"
// sets the flag to true and drops "false" as a positional argument.
command.push(`${flag}=${String(value)}`);
} else {
command.push(flag, String(value));
}
});
return command.join(' ');
}

export function safeJsonParse<T>(jsonString: string): { ok: boolean, result: T | null, error?: Error | null } {
let result: T;
try {
Expand Down
33 changes: 11 additions & 22 deletions tests/functional/ctst/steps/dr/drctl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import util from 'util';
import { exec } from 'child_process';

import Zenko from 'world/Zenko';
import { paramToCli } from 'common/utils';

type InstallConfig = {
sourceZenkoDrInstance?: string;
Expand Down Expand Up @@ -241,54 +242,42 @@ export default class ZenkoDrctl {
}

async install(config: InstallConfig) {
return this.runCommand('install', this.paramToCli(this.withSourceSinkKubeconfig(config)), true);
return this.runCommand('install', paramToCli(this.withSourceSinkKubeconfig(config)), true);
}

async uninstall(config: UninstallConfig) {
return this.runCommand('uninstall', this.paramToCli(this.withSourceSinkKubeconfig(config)), true);
return this.runCommand('uninstall', paramToCli(this.withSourceSinkKubeconfig(config)), true);
}

async bootstrapDump(config: BootstrapDumpConfig) {
return this.runCommand('bootstrap dump', this.paramToCli(config));
return this.runCommand('bootstrap dump', paramToCli(config));
}

async bootstrapLoad(config: BootstrapLoadConfig) {
return this.runCommand('bootstrap load', this.paramToCli(config));
return this.runCommand('bootstrap load', paramToCli(config));
}

async failover(config: FailoverConfig) {
return this.runCommand('failover', this.paramToCli(this.withSinkKubeconfig(config)));
return this.runCommand('failover', paramToCli(this.withSinkKubeconfig(config)));
}

async failback(config: FailbackConfig) {
return this.runCommand('failback', this.paramToCli(this.withSinkKubeconfig(config)));
return this.runCommand('failback', paramToCli(this.withSinkKubeconfig(config)));
}

async status(config: StatusConfig) {
return this.runCommand('status', this.paramToCli(this.withSourceSinkKubeconfig(config)));
return this.runCommand('status', paramToCli(this.withSourceSinkKubeconfig(config)));
}

async volumeGet(config: VolumeGetConfig) {
return this.runCommand('volume get', this.paramToCli(this.withTargetKubeconfig(config)));
return this.runCommand('volume get', paramToCli(this.withTargetKubeconfig(config)));
}

async replicationPause(config: ReplicationPauseConfig) {
return this.runCommand('replication pause', this.paramToCli(this.withSourceSinkKubeconfig(config)));
return this.runCommand('replication pause', paramToCli(this.withSourceSinkKubeconfig(config)));
}

async replicationResume(config: ReplicationResumeConfig) {
return this.runCommand('replication resume', this.paramToCli(this.withSourceSinkKubeconfig(config)));
}

paramToCli(params: Record<string, unknown>): string {
const command: string[] = [];
Object.keys(params).forEach(key => {
const value = params[key];
if (value !== undefined && value !== null) {
command.push(`--${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`);
command.push(String(value));
}
});
return command.join(' ');
return this.runCommand('replication resume', paramToCli(this.withSourceSinkKubeconfig(config)));
}
}
Loading