Skip to content

Commit

Permalink
feat: Add support for properties and environment variables
Browse files Browse the repository at this point in the history
  • Loading branch information
guilgaly committed Jul 8, 2024
1 parent 8a627f8 commit 8acfa81
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 5 deletions.
43 changes: 38 additions & 5 deletions js/cli/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env node

import { Command, Option } from "commander";
import { Command, Option, Argument } from "commander";
import os from "os";

import { bundle } from "./bundle";
Expand Down Expand Up @@ -133,6 +133,25 @@ const nonInteractiveOption = new Option(
"Switch to non-interactive mode and fail if no simulation is explicitly specified"
).default(false);

const runOptionsArgument = new Argument(
"[optionKey=optionValue...]",
"Specify one or more option which can be read in the simulation script with the getOption() function; format must be key=value"
);

const parseRunOptions = (args: string[]): Record<string, string> => {
const parsedOptions: Record<string, string> = {};
for (const arg of args) {
const i = arg.indexOf("=");
if (i < 0) {
throw Error(`Option '${arg}' is not valid: format should be key=value`);
} else {
const key = arg.slice(0, i).trim();
parsedOptions[key] = arg.slice(i + 1);
}
}
return parsedOptions;
};

program
.command("install")
.description("Install all required components and dependencies for Gatling")
Expand Down Expand Up @@ -171,14 +190,16 @@ program
.addOption(resourcesFolderOption)
.addOption(resultsFolderOption)
.addOption(memoryOption)
.action(async (options) => {
.addArgument(runOptionsArgument)
.action(async (args: string[], options) => {
const graalvmHome: string = options.graalvmHome;
const jvmClasspath: string = options.jvmClasspath;
const simulation: string = options.simulation;
const bundleFile = validateBundleFile(options);
const resourcesFolder: string = options.resourcesFolder;
const resultsFolder: string = options.resultsFolder;
const memory: number | undefined = options.memory;
const runOptions = parseRunOptions(args);

await runSimulation({
graalvmHome,
Expand All @@ -187,7 +208,8 @@ program
bundleFile,
resourcesFolder,
resultsFolder,
memory
memory,
runOptions
});
});

Expand All @@ -205,14 +227,16 @@ program
.addOption(gatlingHomeOption)
.addOption(memoryOption)
.addOption(nonInteractiveOption)
.action(async (options) => {
.addArgument(runOptionsArgument)
.action(async (args: string[], options) => {
const gatlingHome = gatlingHomeDirWithDefaults(options);
const sourcesFolder: string = options.sourcesFolder;
const bundleFile = validateBundleFile(options);
const resourcesFolder: string = options.resourcesFolder;
const resultsFolder: string = options.resultsFolder;
const memory: number | undefined = options.memory;
const nonInteractive: boolean = options.nonInteractive;
const runOptions = parseRunOptions(args);

const simulations = await findSimulations(sourcesFolder);
const typescript = typescriptWithDefaults(options, simulations);
Expand All @@ -225,7 +249,16 @@ program

await bundle({ sourcesFolder, bundleFile, typescript, simulations });

await runSimulation({ graalvmHome, jvmClasspath, simulation, bundleFile, resourcesFolder, resultsFolder, memory });
await runSimulation({
graalvmHome,
jvmClasspath,
simulation,
bundleFile,
resourcesFolder,
resultsFolder,
memory,
runOptions
});
});

program
Expand Down
2 changes: 2 additions & 0 deletions js/cli/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface RunSimulationOptions extends RunJavaProcessOptions {
resourcesFolder: string;
resultsFolder: string;
memory?: number;
runOptions: Record<string, string>;
}

export interface RunRecorderOptions extends RunJavaProcessOptions {
Expand All @@ -26,6 +27,7 @@ export const runSimulation = async (options: RunSimulationOptions): Promise<void
const additionalClasspathElements = [options.resourcesFolder];
const memoryArgs = options.memory !== undefined ? [`-Xms${options.memory}M`, `-Xmx${options.memory}M`] : [];
const javaArgs = [
...Object.entries(options.runOptions).map(([key, value]) => `-D${key}=${value}`),
`-Dgatling.js.bundle.filePath=${options.bundleFile}`,
`-Dgatling.js.simulation=${options.simulation}`,
...memoryArgs
Expand Down
1 change: 1 addition & 0 deletions js/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export * from "./filters";
export { GlobalStore } from "./globalStore";
export * from "./openInjection";
export * from "./population";
export { getOption, getEnvironmentVariable, GetWithDefault } from "./parameters";
export * from "./protocol";
export * from "./scenario";
export * from "./session";
Expand Down
32 changes: 32 additions & 0 deletions js/core/src/parameters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { System as JvmSystem } from "@gatling.io/jvm-types";

export interface GetWithDefault {
(name: string): string | undefined;
(name: string, defaultValue: string): string;
}

/**
* Gets the option indicated by the specified name.
*
* Options can be specified in the `gatling run` command by passing arguments with the format `key=value`, e.g.
* `gatling run option1=foo option2=bar`.
*
* @param key - the key of the option.
* @param defaultValue - a default value
* @returns the string value of the option if it is defined, or else `defaultValue` if provided, or else `undefined`.
*/
export const getOption: GetWithDefault = (key: string, defaultValue?: string) =>
getOrElse(JvmSystem.getProperty(key), defaultValue) as any;

/**
* Gets the environment variable indicated by the specified name.
*
* @param name - the name of the environment variable.
* @param defaultValue - a default value
* @returns the string value of the environment variable if it is defined, or else `defaultValue` if provided, or else `undefined`.
*/
export const getEnvironmentVariable: GetWithDefault = (name: string, defaultValue?: string) =>
getOrElse(JvmSystem.getenv(name), defaultValue) as any;

const getOrElse = (value: string | null, defaultValue?: string): string | undefined =>
typeof value === "string" ? value : defaultValue;
7 changes: 7 additions & 0 deletions js/jvm-types/gatling.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3657,6 +3657,12 @@ declare namespace java.lang {
trim(): string;
} // end String
} // end namespace java.lang
declare namespace java.lang {
class System /* extends Object*/ {
equals(arg0: any /*java.lang.Object*/): boolean;
toString(): string;
} // end System
} // end namespace java.lang
declare namespace java.lang {
interface Comparable<T> {
compareTo(arg0: T): int;
Expand Down Expand Up @@ -3887,6 +3893,7 @@ declare namespace java.util.stream {
flatMapToLong(arg0: Func<T, any /*java.util.stream.LongStream*/>): any /*java.util.stream.LongStream*/;
forEach(arg0: Consumer<T>): void;
forEachOrdered(arg0: Consumer<T>): void;
gather<R>(arg0: any /*java.util.stream.Gatherer*/): Stream<R>;
isParallel(): boolean;
iterator(): java.util.Iterator<T>;
limit(arg0: long): Stream<T>;
Expand Down
34 changes: 34 additions & 0 deletions js/jvm-types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2137,6 +2137,40 @@ interface StructureBuilderStatic {

export const StructureBuilder: StructureBuilderStatic = Java.type("io.gatling.javaapi.core.StructureBuilder");

interface SystemStatic {
readonly class: any;
console(): any /*java.io.Console*/;
getSecurityManager(): any /*java.lang.SecurityManager*/;
clearProperty(arg0: string): string;
getProperty(arg0: string): string;
getProperty(arg0: string, arg1: string): string;
getenv(arg0: string): string;
lineSeparator(): string;
setProperty(arg0: string, arg1: string): string;
getLogger(arg0: string): any /*java.lang.System$Logger*/;
getLogger(arg0: string, arg1: any /*java.util.ResourceBundle*/): any /*java.lang.System$Logger*/;
inheritedChannel(): any /*java.nio.channels.Channel*/;
getenv(): java.util.Map<string, string>;
getProperties(): any /*java.util.Properties*/;
identityHashCode(arg0: any /*java.lang.Object*/): int;
mapLibraryName(arg0: string): string;
currentTimeMillis(): long;
nanoTime(): long;
arraycopy(arg0: any /*java.lang.Object*/, arg1: int, arg2: any /*java.lang.Object*/, arg3: int, arg4: int): void;
exit(arg0: int): void;
gc(): void;
load(arg0: string): void;
loadLibrary(arg0: string): void;
runFinalization(): void;
setErr(arg0: any /*java.io.PrintStream*/): void;
setIn(arg0: any /*java.io.InputStream*/): void;
setOut(arg0: any /*java.io.PrintStream*/): void;
setProperties(arg0: any /*java.util.Properties*/): void;
setSecurityManager(arg0: any /*java.lang.SecurityManager*/): void;
}

export const System: SystemStatic = Java.type("java.lang.System");

interface TemporalUnitStatic {
readonly class: any;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
@Java2TS(
declare = {
// ********** java **********
@Type(value = java.lang.System.class, export = true),
// java.time
@Type(value = java.time.Duration.class, export = true),
@Type(value = java.time.temporal.ChronoUnit.class, export = true),
Expand Down

0 comments on commit 8acfa81

Please sign in to comment.