Add command line parsing and configuration management
* Introduced `CommandLine` class for handling command line options and arguments * Added `TestConfiguration` class to manage application credentials and URIs * Implemented example usage for generating command line arguments from a configuration object * Updated `package.json` to include `commander` dependency * Removed unused `TestRunner` class and created a new `TestRunner` for executing tests with command line options * Adjusted logging level type to use lowercase values for consistency
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@techniker-me/pcast-api": "2025.0.2",
|
"@techniker-me/pcast-api": "2025.0.2",
|
||||||
"@techniker-me/rtmp-push": "2025.0.2"
|
"@techniker-me/rtmp-push": "2025.0.2",
|
||||||
|
"commander": "14.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,144 @@
|
|||||||
|
import {Command} from 'commander';
|
||||||
|
import PackageJson from '../../package.json' assert {type: 'json'};
|
||||||
|
import {LoggingLevel, LoggingLevelMapping} from '../logger/LoggingLevel';
|
||||||
|
|
||||||
|
export interface CommandLineOptions {
|
||||||
|
applicationId: string;
|
||||||
|
secret: string;
|
||||||
|
logLevel: string;
|
||||||
|
pcastUri: string;
|
||||||
|
ingestUri: string;
|
||||||
|
channelUri: string;
|
||||||
|
publisherUri: string;
|
||||||
|
viewers: string[];
|
||||||
|
publishers: string[];
|
||||||
|
tests: string[];
|
||||||
|
useBrowserstack: boolean;
|
||||||
|
useBrowserstackLocal: boolean;
|
||||||
|
browserstackUser: string;
|
||||||
|
browserstackKey: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConfigurationObject {
|
||||||
|
viewers: string[];
|
||||||
|
publishers: string[];
|
||||||
|
tests: string[];
|
||||||
|
useBrowserstack: boolean;
|
||||||
|
useBrowserstackLocal: boolean;
|
||||||
|
browserstackUser: string;
|
||||||
|
browserstackKey: string;
|
||||||
|
logLevel: string;
|
||||||
|
applicationId: string;
|
||||||
|
secret: string;
|
||||||
|
pcastUri: string;
|
||||||
|
ingestUri: string;
|
||||||
|
channelUri: string;
|
||||||
|
publisherUri?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultLogLevel = LoggingLevel.Info;
|
||||||
|
const defaultViewers: string[] = [];
|
||||||
|
const defaultPublishers: string[] = [];
|
||||||
|
const defaultTests: string[] = [];
|
||||||
|
const defaultUseBrowserstack = false;
|
||||||
|
const defaultUseBrowserstackLocal = false;
|
||||||
|
|
||||||
export default class CommandLine {
|
export default class CommandLine {
|
||||||
|
private static readonly _program: Command = new Command();
|
||||||
|
|
||||||
|
public static parse(args: string[]): CommandLineOptions {
|
||||||
|
CommandLine._program.parse(args);
|
||||||
|
|
||||||
|
return CommandLine._program.opts<CommandLineOptions>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a configuration object to command line arguments array
|
||||||
|
*/
|
||||||
|
public static configToArgs(config: ConfigurationObject): string[] {
|
||||||
|
const args: string[] = [];
|
||||||
|
|
||||||
|
// Required options
|
||||||
|
args.push('--application-id', config.applicationId);
|
||||||
|
args.push('--secret', config.secret);
|
||||||
|
args.push('--pcast-uri', config.pcastUri);
|
||||||
|
args.push('--channel-uri', config.channelUri);
|
||||||
|
|
||||||
|
// Optional URI options
|
||||||
|
if (config.publisherUri) {
|
||||||
|
args.push('--publisher-uri', config.publisherUri);
|
||||||
|
}
|
||||||
|
if (config.ingestUri) {
|
||||||
|
args.push('--ingest-uri', config.ingestUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Browser and OS options (singular option names, multiple values)
|
||||||
|
config.viewers.forEach(viewer => {
|
||||||
|
args.push('--viewer', viewer);
|
||||||
|
});
|
||||||
|
config.publishers.forEach(publisher => {
|
||||||
|
args.push('--publisher', publisher);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test options (singular option name, multiple values)
|
||||||
|
config.tests.forEach(test => {
|
||||||
|
args.push('--test', test);
|
||||||
|
});
|
||||||
|
|
||||||
|
// BrowserStack options
|
||||||
|
if (config.useBrowserstack) {
|
||||||
|
args.push('--use-browserstack');
|
||||||
|
}
|
||||||
|
if (config.useBrowserstackLocal) {
|
||||||
|
args.push('--use-browserstack-local');
|
||||||
|
}
|
||||||
|
if (config.browserstackUser) {
|
||||||
|
args.push('--browserstack-user', config.browserstackUser);
|
||||||
|
}
|
||||||
|
if (config.browserstackKey) {
|
||||||
|
args.push('--browserstack-key', config.browserstackKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logging options
|
||||||
|
if (config.logLevel) {
|
||||||
|
args.push('--log-level', config.logLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
CommandLine._program.version(PackageJson.version);
|
||||||
|
CommandLine._setupProgramOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _setupProgramOptions(): void {
|
||||||
|
const handleArrayOption = (value: string, previousValue: string[]) => {
|
||||||
|
if (previousValue) {
|
||||||
|
return previousValue.concat(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [value];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Required options
|
||||||
|
CommandLine._program.requiredOption('--application-id <applicationId>', 'The application ID to use');
|
||||||
|
CommandLine._program.requiredOption('--secret <secret>', 'The secret to use');
|
||||||
|
CommandLine._program.requiredOption('--pcast-uri <pcastUri>', 'The pcast URI to use');
|
||||||
|
CommandLine._program.requiredOption('--channel-uri <channelUri>', 'The channel URI to use');
|
||||||
|
|
||||||
|
CommandLine._program.option('--ingest-uri <ingestUri>', 'The ingest URI to use');
|
||||||
|
CommandLine._program.option('--publisher-uri <publisherUri>', 'The publisher URI to use');
|
||||||
|
CommandLine._program.option('--viewer <browser@version:OS@OSVersion...>', 'The browser and OS for simulating a viewer to use', handleArrayOption, defaultViewers);
|
||||||
|
CommandLine._program.option('--publisher <browser@version:OS@OSVersion...>', 'The browser and OS for simulating a publisher to use', handleArrayOption, defaultPublishers);
|
||||||
|
CommandLine._program.option('-t, --test <test...>', 'The test to run', handleArrayOption, defaultTests);
|
||||||
|
CommandLine._program.option('--use-browserstack', 'Run tests using BrowserStack', defaultUseBrowserstack);
|
||||||
|
CommandLine._program.option('--use-browserstack-local', 'Run tests using BrowserStack Local', defaultUseBrowserstackLocal);
|
||||||
|
CommandLine._program.option('--browserstack-user <username>', 'The BrowserStack username to use', process.env.BROWSERSTACK_USER || '');
|
||||||
|
CommandLine._program.option('--browserstack-key <key>', 'The BrowserStack key to use', process.env.BROWSERSTACK_KEY || '');
|
||||||
|
CommandLine._program.option('--log-level <logLevel>', 'The log level to use', LoggingLevelMapping.convertLoggingLevelToLoggingLevelType(defaultLogLevel));
|
||||||
|
}
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
throw new Error('[CommandLine] is a static class that may not be instantiated');
|
throw new Error('[CommandLine] is a static class that may not be instantiated');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import CommandLine, { CommandLineOptions } from './CommandLine';
|
||||||
|
|
||||||
|
|
||||||
|
type ApplicationCredentials = {
|
||||||
|
applicationId: string;
|
||||||
|
secret: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Uri = {
|
||||||
|
pcast: string;
|
||||||
|
ingest: string | undefined;
|
||||||
|
channel: string | undefined;
|
||||||
|
publisher: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
type BrowserstackConfiguration = {
|
||||||
|
enabled: boolean;
|
||||||
|
local: boolean;
|
||||||
|
user: string;
|
||||||
|
key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class TestConfiguration {
|
||||||
|
private readonly _applicationCredentials: ApplicationCredentials;
|
||||||
|
private readonly _uri: Uri;
|
||||||
|
private readonly _viewers: string[];
|
||||||
|
private readonly _publishers: string[];
|
||||||
|
private readonly _tests: string[];
|
||||||
|
private readonly _browserstack: BrowserstackConfiguration;
|
||||||
|
|
||||||
|
constructor(commandLineOptions: CommandLineOptions) {
|
||||||
|
this._applicationCredentials = {
|
||||||
|
applicationId: commandLineOptions.applicationId,
|
||||||
|
secret: commandLineOptions.secret,
|
||||||
|
};
|
||||||
|
|
||||||
|
this._uri = {
|
||||||
|
pcast: commandLineOptions.pcastUri,
|
||||||
|
ingest: commandLineOptions.ingestUri,
|
||||||
|
channel: commandLineOptions.channelUri,
|
||||||
|
publisher: commandLineOptions.publisherUri,
|
||||||
|
};
|
||||||
|
|
||||||
|
this._viewers = commandLineOptions.viewers;
|
||||||
|
this._publishers = commandLineOptions.publishers;
|
||||||
|
this._tests = commandLineOptions.tests;
|
||||||
|
this._browserstack = {
|
||||||
|
enabled: commandLineOptions.useBrowserstack,
|
||||||
|
local: commandLineOptions.useBrowserstackLocal,
|
||||||
|
user: commandLineOptions.browserstackUser,
|
||||||
|
key: commandLineOptions.browserstackKey,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get applicationCredentials(): ApplicationCredentials {
|
||||||
|
return this._applicationCredentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
get uri(): Uri {
|
||||||
|
return this._uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
get viewers(): string[] {
|
||||||
|
return this._viewers;
|
||||||
|
}
|
||||||
|
|
||||||
|
get publishers(): string[] {
|
||||||
|
return this._publishers;
|
||||||
|
}
|
||||||
|
|
||||||
|
get tests(): string[] {
|
||||||
|
return this._tests;
|
||||||
|
}
|
||||||
|
|
||||||
|
get browserstack(): BrowserstackConfiguration {
|
||||||
|
return this._browserstack;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import PCastAPI from '@techniker-me/pcast-api';
|
|
||||||
import RtmpPush from '@technniker-me/rtmp-push';
|
|
||||||
|
|
||||||
class TestRunner {}
|
|
||||||
43
test/config/example-usage.ts
Normal file
43
test/config/example-usage.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import CommandLine from './CommandLine';
|
||||||
|
|
||||||
|
// Example configuration object matching your structure
|
||||||
|
const config = {
|
||||||
|
viewers: ["chrome", "firefox"],
|
||||||
|
publishers: [],
|
||||||
|
tests: ["test/tests/real-time", "test/tests/dash", "test/tests/hls"],
|
||||||
|
useBrowserstack: false,
|
||||||
|
useBrowserstackLocal: false,
|
||||||
|
browserstackUser: "",
|
||||||
|
browserstackKey: "",
|
||||||
|
logLevel: "Info",
|
||||||
|
applicationId: "phenixrts.com-alex.zinn",
|
||||||
|
secret: "AMAsDzr.dIuGMZ.Zu52Dt~MQvP!DZwYg",
|
||||||
|
pcastUri: "https://pcast-stg.phenixrts.com",
|
||||||
|
ingestUri: "rtmp://ingest-stg.phenixrts.com:80/ingest",
|
||||||
|
channelUri: "https://pcast-stg.phenixrts.com/channel",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert configuration to command line arguments
|
||||||
|
const args = CommandLine.configToArgs(config);
|
||||||
|
|
||||||
|
console.log('Generated command line arguments:');
|
||||||
|
console.log(args.join(' '));
|
||||||
|
|
||||||
|
console.log('\nThis generates the equivalent of:');
|
||||||
|
console.log('--application-id phenixrts.com-alex.zinn \\');
|
||||||
|
console.log('--secret AMAsDzr.dIuGMZ.Zu52Dt~MQvP!DZwYg \\');
|
||||||
|
console.log('--pcast-uri https://pcast-stg.phenixrts.com \\');
|
||||||
|
console.log('--channel-uri https://pcast-stg.phenixrts.com/channel \\');
|
||||||
|
console.log('--ingest-uri rtmp://ingest-stg.phenixrts.com:80/ingest \\');
|
||||||
|
console.log('--viewer chrome \\');
|
||||||
|
console.log('--viewer firefox \\');
|
||||||
|
console.log('--test test/tests/real-time \\');
|
||||||
|
console.log('--test test/tests/dash \\');
|
||||||
|
console.log('--test test/tests/hls \\');
|
||||||
|
console.log('--log-level Info');
|
||||||
|
|
||||||
|
console.log('\nNote: Users can pass --viewer, --publisher, and -t multiple times to build arrays');
|
||||||
|
|
||||||
|
// You can now use these arguments with the CommandLine.parse method
|
||||||
|
// const options = CommandLine.parse(args);
|
||||||
|
// console.log('Parsed options:', options);
|
||||||
@@ -9,27 +9,27 @@ export enum LoggingLevel {
|
|||||||
All = 7
|
All = 7
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LoggingLevelType = 'Off' | 'Fatal' | 'Error' | 'Warning' | 'Info' | 'Debug' | 'Trace' | 'All';
|
export type LoggingLevelType = 'off' | 'fatal' | 'error' | 'warning' | 'info' | 'debug' | 'trace' | 'all';
|
||||||
|
|
||||||
export class LoggingLevelMapping {
|
export class LoggingLevelMapping {
|
||||||
public static convertLoggingLevelToLoggingLevelType(level: LoggingLevel): LoggingLevelType {
|
public static convertLoggingLevelToLoggingLevelType(level: LoggingLevel): LoggingLevelType {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case LoggingLevel.Off:
|
case LoggingLevel.Off:
|
||||||
return 'Off';
|
return 'off';
|
||||||
case LoggingLevel.Fatal:
|
case LoggingLevel.Fatal:
|
||||||
return 'Fatal';
|
return 'fatal';
|
||||||
case LoggingLevel.Error:
|
case LoggingLevel.Error:
|
||||||
return 'Error';
|
return 'error';
|
||||||
case LoggingLevel.Warning:
|
case LoggingLevel.Warning:
|
||||||
return 'Warning';
|
return 'warning';
|
||||||
case LoggingLevel.Info:
|
case LoggingLevel.Info:
|
||||||
return 'Info';
|
return 'info';
|
||||||
case LoggingLevel.Debug:
|
case LoggingLevel.Debug:
|
||||||
return 'Debug';
|
return 'debug';
|
||||||
case LoggingLevel.Trace:
|
case LoggingLevel.Trace:
|
||||||
return 'Trace';
|
return 'trace';
|
||||||
case LoggingLevel.All:
|
case LoggingLevel.All:
|
||||||
return 'All';
|
return 'all';
|
||||||
default:
|
default:
|
||||||
throw new Error(`[LoggingLevelMapping] Received unknown logging level [${level}]`);
|
throw new Error(`[LoggingLevelMapping] Received unknown logging level [${level}]`);
|
||||||
}
|
}
|
||||||
|
|||||||
23
test/runner/TestRunner.ts
Normal file
23
test/runner/TestRunner.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import PCastAPI from '@techniker-me/pcast-api';
|
||||||
|
import RtmpPush from '@technniker-me/rtmp-push';
|
||||||
|
import CommandLine from '../config/CommandLine';
|
||||||
|
|
||||||
|
interface CommandLineOptions {
|
||||||
|
applicationId: string;
|
||||||
|
secret: string;
|
||||||
|
logLevel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestRunner {
|
||||||
|
private static readonly _commandLineOptions: CommandLineOptions = CommandLine.parse(process.argv);
|
||||||
|
|
||||||
|
public static main(): void {
|
||||||
|
// const testRunner = new TestRunner();
|
||||||
|
// testRunner.run();
|
||||||
|
|
||||||
|
console.log(TestRunner._commandLineOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestRunner.main();
|
||||||
|
|
||||||
Reference in New Issue
Block a user