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:
2025-08-18 17:54:04 -04:00
parent 1bc3aaa8aa
commit 4b672f231f
7 changed files with 295 additions and 14 deletions

View File

@@ -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 {
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() {
throw new Error('[CommandLine] is a static class that may not be instantiated');
}

View File

@@ -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;
}
}

View File

@@ -1,4 +0,0 @@
import PCastAPI from '@techniker-me/pcast-api';
import RtmpPush from '@technniker-me/rtmp-push';
class TestRunner {}

View 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);

View File

@@ -9,27 +9,27 @@ export enum LoggingLevel {
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 {
public static convertLoggingLevelToLoggingLevelType(level: LoggingLevel): LoggingLevelType {
switch (level) {
case LoggingLevel.Off:
return 'Off';
return 'off';
case LoggingLevel.Fatal:
return 'Fatal';
return 'fatal';
case LoggingLevel.Error:
return 'Error';
return 'error';
case LoggingLevel.Warning:
return 'Warning';
return 'warning';
case LoggingLevel.Info:
return 'Info';
return 'info';
case LoggingLevel.Debug:
return 'Debug';
return 'debug';
case LoggingLevel.Trace:
return 'Trace';
return 'trace';
case LoggingLevel.All:
return 'All';
return 'all';
default:
throw new Error(`[LoggingLevelMapping] Received unknown logging level [${level}]`);
}

23
test/runner/TestRunner.ts Normal file
View 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();