Skip to content

Commit

Permalink
feat(artillery): add ability to specify scenario to run by name (#2184)
Browse files Browse the repository at this point in the history
  • Loading branch information
bernardobridge authored Oct 18, 2023
1 parent 5b355f8 commit da56158
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 3 deletions.
3 changes: 3 additions & 0 deletions packages/artillery/lib/cmds/run-lambda.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
6 changes: 5 additions & 1 deletion packages/artillery/lib/cmds/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
})
};

Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions packages/artillery/lib/platform/aws-lambda/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
46 changes: 46 additions & 0 deletions packages/artillery/test/cli/command-run.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
13 changes: 13 additions & 0 deletions packages/artillery/test/scripts/scenario-named/scenario.yml
Original file line number Diff line number Diff line change
@@ -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"
31 changes: 29 additions & 2 deletions packages/core/lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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();

//
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit da56158

Please sign in to comment.