Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve(cli): enhance handleLoadOptions to accept existing options #1811

Merged
merged 5 commits into from
Nov 15, 2024
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
201 changes: 201 additions & 0 deletions cli/src/__tests__/utils/options.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/// <reference types="../../types/global" />

import { handleSaveOptions, handleLoadOptions } from '../../utils/options'
import { existsSync, unlinkSync } from 'fs'
import { join } from 'path'
import { expect, afterAll, describe, it, jest, beforeAll } from '@jest/globals'

const testFilePath = join(__dirname, 'test-options.json')
const defaultPath = join(process.cwd(), 'mqttx-cli-options.json')

describe('options', () => {
beforeAll(() => {
global.command = {
getOptionValueSource: jest.fn().mockReturnValue('cli'),
} as any
})

afterAll(() => {
if (existsSync(testFilePath)) {
unlinkSync(testFilePath)
}
if (existsSync(defaultPath)) {
unlinkSync(defaultPath)
}
})

it('should save and load options for command type "conn" with default path', () => {
const options: ConnectOptions = {
mqttVersion: 5,
hostname: 'localhost',
clientId: 'testClient',
clean: true,
keepalive: 60,
reconnectPeriod: 1000,
maximumReconnectTimes: 10,
saveOptions: true,
}

handleSaveOptions('conn', options)
const loadedOptions = handleLoadOptions('conn', true, {} as ConnectOptions)
const { saveOptions, loadOptions, ...expectedOptions } = options
expect(loadedOptions).toMatchObject(expectedOptions as unknown as Record<string, unknown>)
})

it('should save and load options for command type "pub" with custom path', () => {
const options: PublishOptions = {
mqttVersion: 5,
hostname: 'localhost',
clientId: 'testClient',
clean: true,
keepalive: 60,
reconnectPeriod: 1000,
maximumReconnectTimes: 10,
topic: 'test/topic',
message: 'Hello, MQTT!',
qos: 1,
saveOptions: testFilePath,
}

handleSaveOptions('pub', options)
const loadedOptions = handleLoadOptions('pub', testFilePath, {} as PublishOptions)
const { saveOptions, loadOptions, ...expectedOptions } = options
expect(loadedOptions).toMatchObject(expectedOptions as unknown as Record<string, unknown>)

const userOptions: PublishOptions = {
mqttVersion: 5,
hostname: 'localhost',
clientId: 'testClient',
clean: true,
keepalive: 60,
reconnectPeriod: 1000,
maximumReconnectTimes: 10,
topic: 'user/topic',
message: 'User message',
qos: 1,
saveOptions: testFilePath,
}

const overriddenOptions = handleLoadOptions('pub', testFilePath, userOptions)
expect(overriddenOptions.topic).toEqual('user/topic')
expect(overriddenOptions.message).toEqual('User message')
})

it('should save and load options for command type "sub" with default path', () => {
const options: SubscribeOptions = {
mqttVersion: 5,
hostname: 'localhost',
clientId: 'testClient',
clean: true,
keepalive: 60,
reconnectPeriod: 1000,
maximumReconnectTimes: 10,
topic: ['test/topic'],
qos: [1],
saveOptions: true,
verbose: true,
}

handleSaveOptions('sub', options)
const loadedOptions = handleLoadOptions('sub', true, {} as SubscribeOptions)
const { saveOptions, loadOptions, ...expectedOptions } = options
expect(loadedOptions).toMatchObject(expectedOptions as unknown as Record<string, unknown>)
})

it('should save and load options for command type "benchConn" with custom path', () => {
const options: BenchConnectOptions = {
mqttVersion: 5,
hostname: 'localhost',
clientId: 'testClient',
clean: true,
keepalive: 60,
reconnectPeriod: 1000,
maximumReconnectTimes: 10,
count: 100,
interval: 1000,
saveOptions: testFilePath,
}

handleSaveOptions('benchConn', options)
const loadedOptions = handleLoadOptions('benchConn', testFilePath, {} as BenchConnectOptions)
const { saveOptions, loadOptions, ...expectedOptions } = options
expect(loadedOptions).toMatchObject(expectedOptions as unknown as Record<string, unknown>)
})

it('should save and load options for command type "benchPub" with default path', () => {
const options: BenchPublishOptions = {
mqttVersion: 5,
hostname: 'localhost',
clientId: 'testClient',
clean: true,
keepalive: 60,
reconnectPeriod: 1000,
maximumReconnectTimes: 10,
topic: 'test/topic',
message: 'Hello, MQTT!',
qos: 1,
count: 100,
interval: 1000,
messageInterval: 500,
limit: 1000,
verbose: true,
saveOptions: true,
}

handleSaveOptions('benchPub', options)
const loadedOptions = handleLoadOptions('benchPub', true, {} as BenchPublishOptions)
const { saveOptions, loadOptions, ...expectedOptions } = options
expect(loadedOptions).toMatchObject(expectedOptions as unknown as Record<string, unknown>)
})

it('should save and load options for command type "benchSub" with custom path', () => {
const options: BenchSubscribeOptions = {
mqttVersion: 5,
hostname: 'localhost',
clientId: 'testClient',
clean: true,
keepalive: 60,
reconnectPeriod: 1000,
maximumReconnectTimes: 10,
topic: ['test/topic'],
qos: [1],
count: 100,
interval: 1000,
saveOptions: testFilePath,
verbose: true,
}

handleSaveOptions('benchSub', options)
const loadedOptions = handleLoadOptions('benchSub', testFilePath, {} as BenchSubscribeOptions)
const { saveOptions, loadOptions, ...expectedOptions } = options
expect(loadedOptions).toMatchObject(expectedOptions as unknown as Record<string, unknown>)
})

it('should save and load options for command type "simulate" with default path', () => {
const options: SimulatePubOptions = {
mqttVersion: 5,
hostname: 'localhost',
clientId: 'testClient',
clean: true,
keepalive: 60,
reconnectPeriod: 1000,
maximumReconnectTimes: 10,
topic: 'test/topic',
message: 'Hello, MQTT!',
qos: 1,
count: 100,
interval: 1000,
messageInterval: 500,
limit: 1000,
verbose: true,
scenario: 'testScenario',
file: 'testFile',
saveOptions: true,
}

handleSaveOptions('simulate', options)
const loadedOptions = handleLoadOptions('simulate', true, {} as SimulatePubOptions)
const { saveOptions, loadOptions, ...expectedOptions } = options
expect(loadedOptions).toMatchObject(expectedOptions as unknown as Record<string, unknown>)
})
})
30 changes: 30 additions & 0 deletions cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export class Commander {
.command('check')
.description('Check for updates.')
.allowUnknownOption(false)
.hook('preAction', (thisCommand) => {
globalThis.command = thisCommand
})
.action(async () => {
await checkUpdate()
})
Expand All @@ -51,6 +54,9 @@ export class Commander {
.command('init')
.description('Initialize the configuration file.')
.allowUnknownOption(false)
.hook('preAction', (thisCommand) => {
globalThis.command = thisCommand
})
.action(initConfig)

this.program
Expand Down Expand Up @@ -128,6 +134,9 @@ export class Commander {
)
.option('--debug', 'enable debug mode for MQTT.js', false)
.allowUnknownOption(false)
.hook('preAction', (thisCommand) => {
globalThis.command = thisCommand
})
.action(conn)

this.program
Expand Down Expand Up @@ -252,6 +261,9 @@ export class Commander {
)
.option('--debug', 'enable debug mode for MQTT.js', false)
.allowUnknownOption(false)
.hook('preAction', (thisCommand) => {
globalThis.command = thisCommand
})
.action(pub)

this.program
Expand Down Expand Up @@ -383,6 +395,9 @@ export class Commander {
)
.option('--debug', 'enable debug mode for MQTT.js', false)
.allowUnknownOption(false)
.hook('preAction', (thisCommand) => {
globalThis.command = thisCommand
})
.action(sub)

const benchCmd = this.program.command('bench').description('MQTT Benchmark in performance testing.')
Expand Down Expand Up @@ -463,6 +478,9 @@ export class Commander {
'load the parameters from the local configuration file, which supports json and yaml format, default path is ./mqttx-cli-options.json',
)
.allowUnknownOption(false)
.hook('preAction', (thisCommand) => {
globalThis.command = thisCommand
})
.action(benchConn)

benchCmd
Expand Down Expand Up @@ -584,6 +602,9 @@ export class Commander {
'split the input message in a single file by a specified character, default is "\\n"',
)
.allowUnknownOption(false)
.hook('preAction', (thisCommand) => {
globalThis.command = thisCommand
})
.action(benchPub)

benchCmd
Expand Down Expand Up @@ -683,6 +704,9 @@ export class Commander {
'load the parameters from the local configuration file, which supports json and yaml format, default path is ./mqttx-cli-options.json',
)
.allowUnknownOption(false)
.hook('preAction', (thisCommand) => {
globalThis.command = thisCommand
})
.action(benchSub)

this.program
Expand Down Expand Up @@ -796,13 +820,19 @@ export class Commander {
'load the parameters from the local configuration file, which supports json and yaml format, default path is ./mqttx-cli-options.json',
)
.allowUnknownOption(false)
.hook('preAction', (thisCommand) => {
globalThis.command = thisCommand
})
.action(simulatePub)

this.program
.command('ls')
.description('List information based on the provided options.')
.option('-sc, --scenarios', 'List all built-in scenarios')
.allowUnknownOption(false)
.hook('preAction', (thisCommand) => {
globalThis.command = thisCommand
})
.action(ls)
}
}
Expand Down
4 changes: 2 additions & 2 deletions cli/src/lib/conn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as Debug from 'debug'
const conn = (options: ConnectOptions) => {
const { debug, saveOptions, loadOptions } = options

loadOptions && (options = handleLoadOptions('conn', loadOptions))
loadOptions && (options = handleLoadOptions('conn', loadOptions, options))

saveOptions && handleSaveOptions('conn', options)

Expand Down Expand Up @@ -57,7 +57,7 @@ const conn = (options: ConnectOptions) => {
const benchConn = async (options: BenchConnectOptions) => {
const { saveOptions, loadOptions } = options

loadOptions && (options = handleLoadOptions('benchConn', loadOptions))
loadOptions && (options = handleLoadOptions('benchConn', loadOptions, options))

saveOptions && handleSaveOptions('benchConn', options)

Expand Down
6 changes: 3 additions & 3 deletions cli/src/lib/pub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ const handleFileRead = (filePath: string) => {
const pub = (options: PublishOptions) => {
const { debug, saveOptions, loadOptions } = options

loadOptions && (options = handleLoadOptions('pub', loadOptions))
loadOptions && (options = handleLoadOptions('pub', loadOptions, options))

saveOptions && handleSaveOptions('pub', options)

Expand Down Expand Up @@ -252,14 +252,14 @@ const multiPub = async (commandType: CommandType, options: BenchPublishOptions |

let simulator: Simulator = {} as Simulator
if (commandType === 'simulate') {
options = loadOptions ? handleLoadOptions('simulate', loadOptions) : options
options = loadOptions ? handleLoadOptions('simulate', loadOptions, options as SimulatePubOptions) : options
saveOptions && handleSaveOptions('simulate', options)

const simulateOptions = options as SimulatePubOptions
checkScenarioExists(simulateOptions.scenario, simulateOptions.file)
simulator = loadSimulator(simulateOptions.scenario, simulateOptions.file)
} else {
options = loadOptions ? handleLoadOptions('benchPub', loadOptions) : options
options = loadOptions ? handleLoadOptions('benchPub', loadOptions, options as BenchPublishOptions) : options
saveOptions && handleSaveOptions('benchPub', options)
}

Expand Down
4 changes: 2 additions & 2 deletions cli/src/lib/sub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const handleDefaultBinaryFile = (format: FormatType | undefined, filePath?: stri
const sub = (options: SubscribeOptions) => {
const { loadOptions, saveOptions } = options

loadOptions && (options = handleLoadOptions('sub', loadOptions))
loadOptions && (options = handleLoadOptions('sub', loadOptions, options))

saveOptions && handleSaveOptions('sub', options)

Expand Down Expand Up @@ -232,7 +232,7 @@ const sub = (options: SubscribeOptions) => {
const benchSub = async (options: BenchSubscribeOptions) => {
const { saveOptions, loadOptions } = options

loadOptions && (options = handleLoadOptions('benchSub', loadOptions))
loadOptions && (options = handleLoadOptions('benchSub', loadOptions, options))

saveOptions && handleSaveOptions('benchSub', options)

Expand Down
13 changes: 13 additions & 0 deletions cli/src/types/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
import { Command } from 'commander'

declare global {
var command: Command

type CommandType = 'conn' | 'pub' | 'sub' | 'benchConn' | 'benchPub' | 'benchSub' | 'simulate'

type OptionsType =
| ConnectOptions
| PublishOptions
| SubscribeOptions
| BenchConnectOptions
| BenchPublishOptions
| BenchSubscribeOptions
| SimulatePubOptions

type MQTTVersion = 3 | 4 | 5

type Protocol = 'mqtt' | 'mqtts' | 'ws' | 'wss'
Expand Down
Loading
Loading