diff --git a/packages/artillery/lib/cmds/run-lambda.js b/packages/artillery/lib/cmds/run-lambda.js index c74eb7f954..5282519bc3 100644 --- a/packages/artillery/lib/cmds/run-lambda.js +++ b/packages/artillery/lib/cmds/run-lambda.js @@ -115,6 +115,9 @@ RunLambdaCommand.flags = { key: Flags.string({ description: 'API key for Artillery Cloud' }), + 'scenario-name': Flags.string({ + description: 'Name of the specific scenario to run' + }), architecture: Flags.string({ description: 'Architecture of the Lambda function', default: 'arm64' diff --git a/packages/artillery/lib/cmds/run.js b/packages/artillery/lib/cmds/run.js index 87457af3a1..a39fa47d86 100644 --- a/packages/artillery/lib/cmds/run.js +++ b/packages/artillery/lib/cmds/run.js @@ -155,6 +155,9 @@ RunCommand.flags = { }), key: Flags.string({ description: 'API key for Artillery Cloud' + }), + 'scenario-name': Flags.string({ + description: 'Name of the specific scenario to run' }) }; @@ -207,7 +210,8 @@ RunCommand.runCommandImplementation = async function (flags, argv, args) { scriptPath: args.script, // TODO: This should be an array of files, like inputFiles above absoluteScriptPath: path.resolve(process.cwd(), args.script), - plugins: [] + plugins: [], + scenarioName: flags['scenario-name'] }; // Set "name" tag if not set explicitly diff --git a/packages/artillery/lib/platform/aws-lambda/index.js b/packages/artillery/lib/platform/aws-lambda/index.js index b3db63ddc0..a8b62f2a3f 100644 --- a/packages/artillery/lib/platform/aws-lambda/index.js +++ b/packages/artillery/lib/platform/aws-lambda/index.js @@ -189,6 +189,11 @@ class PlatformLambda { this.artilleryArgs.push(path.basename(this.platformOpts.cliArgs.dotenv)); } + if (this.platformOpts.cliArgs['scenario-name']) { + this.artilleryArgs.push('--scenario-name'); + this.artilleryArgs.push(this.platformOpts.cliArgs['scenario-name']); + } + if (this.platformOpts.cliArgs.config) { this.artilleryArgs.push('--config'); const p = bom.files.filter( diff --git a/packages/artillery/test/cli/command-run.test.js b/packages/artillery/test/cli/command-run.test.js index 1825f071c9..edec7266d2 100644 --- a/packages/artillery/test/cli/command-run.test.js +++ b/packages/artillery/test/cli/command-run.test.js @@ -88,6 +88,52 @@ tap.test('Environment specified with -e should be used', async (t) => { t.ok(exitCode === 0 && !output.stdout.includes('ECONNREFUSED')); }); +tap.test('Can specify scenario to run by name', async (t) => { + const reportFile = 'report-with-scenario-by-name.json'; + const reportFilePath = await getRootPath(reportFile); + + const [exitCode, output] = await execute([ + 'run', + '--scenario-name', + 'Test Scenario 2', + '-o', + `${reportFilePath}`, + 'test/scripts/scenario-named/scenario.yml' + ]); + + t.ok( + exitCode === 0 && output.stdout.includes('Successfully running scenario 2') + ); + const json = JSON.parse(fs.readFileSync(reportFilePath, 'utf8')); + + t.ok( + deleteFile(reportFilePath) && + json.aggregate.counters['vusers.created_by_name.Test Scenario 2'] === 6 && + typeof json.aggregate.counters[ + 'vusers.created_by_name.Test Scenario 1' + ] === 'undefined' + ); +}); + +tap.test( + 'Errors correctly when specifying a non-existing scenario by name', + async (t) => { + const [exitCode, output] = await execute([ + 'run', + '--scenario-name', + 'Test Scenario 3', + 'test/scripts/scenario-named/scenario.yml' + ]); + + t.equal(exitCode, 11); + t.ok( + output.stdout.includes( + 'Error: Scenario Test Scenario 3 not found in script. Make sure your chosen scenario matches the one in your script exactly.' + ) + ); + } +); + tap.test('Run a script with one payload command line', async (t) => { const [, output] = await execute([ 'run', diff --git a/packages/artillery/test/scripts/scenario-named/scenario.yml b/packages/artillery/test/scripts/scenario-named/scenario.yml new file mode 100644 index 0000000000..f0abf966da --- /dev/null +++ b/packages/artillery/test/scripts/scenario-named/scenario.yml @@ -0,0 +1,13 @@ +config: + target: http://asciiart.artillery.io:8080 + phases: + - duration: 3 + arrivalRate: 2 + +scenarios: + - name: Test Scenario 1 + flow: + - log: "Successfully running scenario 1" + - name: Test Scenario 2 + flow: + - log: "Successfully running scenario 2" \ No newline at end of file diff --git a/packages/core/lib/runner.js b/packages/core/lib/runner.js index a562638c63..07d467a9ff 100644 --- a/packages/core/lib/runner.js +++ b/packages/core/lib/runner.js @@ -200,7 +200,13 @@ function run(script, ee, options, runState, contextVars) { if (runState.pendingScenarios >= spec.maxVusers) { metrics.counter('vusers.skipped', 1); } else { - scenarioContext = runScenario(script, metrics, runState, contextVars); + scenarioContext = runScenario( + script, + metrics, + runState, + contextVars, + options + ); } }); phaser.on('phaseStarted', function (spec) { @@ -242,7 +248,7 @@ function run(script, ee, options, runState, contextVars) { phaser.run(); } -function runScenario(script, metrics, runState, contextVars) { +function runScenario(script, metrics, runState, contextVars, options) { const start = process.hrtime(); // @@ -263,7 +269,7 @@ function runScenario(script, metrics, runState, contextVars) { const w = engineUtil.template(scenario.weight, { vars: variableValues }); - scenario.weight = isNaN(parseInt(w)) ? 0 : parseInt(w); + scenario.weight = isNaN(parseInt(w)) ? 0 : parseInt(w); //eslint-disable-line radix debug( `scenario ${scenario.name} weight has been set to ${scenario.weight}` ); @@ -315,8 +321,29 @@ function runScenario(script, metrics, runState, contextVars) { ); } + //default to weighted picked scenario let i = runState.picker()[0]; + if (options.scenarioName) { + let foundIndex; + const foundScenario = script.scenarios.filter((scenario, index) => { + foundIndex = index; + return new RegExp(options.scenarioName).test(scenario.name); + }); + + if (foundScenario?.length === 0) { + throw new Error( + `Scenario ${options.scenarioName} not found in script. Make sure your chosen scenario matches the one in your script exactly.` + ); + } else if (foundScenario.length > 1) { + throw new Error( + `Multiple scenarios for ${options.scenarioName} found in script. Make sure you give unique names to your scenarios in your script.` + ); + } else { + debug(`Scenario ${options.scenarioName} found in script. running it!`); + i = foundIndex; + } + } debug( 'picking scenario %s (%s) weight = %s', i,