Skip to content

Commit

Permalink
1. Add the option to create request that run once before test
Browse files Browse the repository at this point in the history
2. Fix vulnerabilities Dina Yakovlev
3. remove entries from aggregate data
  • Loading branch information
Dina Yakovlev committed Jul 5, 2018
1 parent fb681c1 commit 982c785
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 123 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ lib-cov
artillery_report*
coverage/*
.vagrant/
.vscode
.vscode
.history
253 changes: 145 additions & 108 deletions core/lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const Engines = {
socketio: {}
};

let contextVars;

JSCK.Draft4 = JSCK.draft4;

const schema = new JSCK.Draft4(require('./schemas/artillery_test_script.json'));
Expand Down Expand Up @@ -120,6 +122,10 @@ function runner(script, payload, options, callback) {
}
);

if (script.before) {
handleBeforeRequests(script, runnableScript, runnerEngines, ee);
}

//
// load plugins:
//
Expand Down Expand Up @@ -244,71 +250,72 @@ function runner(script, payload, options, callback) {
}

function run(script, ee, options, runState) {
let intermediate = Stats.create();
let aggregate = [];
let intermediate = Stats.create();
let aggregate = [];

let phaser = createPhaser(script.config.phases);
phaser.on('arrival', function() {
runScenario(script, intermediate, runState);
});
phaser.on('phaseStarted', function(spec) {
ee.emit('phaseStarted', spec);
});
phaser.on('phaseCompleted', function(spec) {
ee.emit('phaseCompleted', spec);
});
phaser.on('done', function() {
debug('All phases launched');
let phaser = createPhaser(script.config.phases);
phaser.on('arrival', function() {
runScenario(script, intermediate, runState);
});
phaser.on('phaseStarted', function(spec) {
ee.emit('phaseStarted', spec);
});
phaser.on('phaseCompleted', function(spec) {
ee.emit('phaseCompleted', spec);
});
phaser.on('done', function() {
debug('All phases launched');

const doneYet = setInterval(function checkIfDone() {
if (runState.pendingScenarios === 0) {
if (runState.pendingRequests !== 0) {
debug('DONE. Pending requests: %s', runState.pendingRequests);
}
const doneYet = setInterval(function checkIfDone() {
if (runState.pendingScenarios === 0) {
if (runState.pendingRequests !== 0) {
debug('DONE. Pending requests: %s', runState.pendingRequests);
}

clearInterval(doneYet);
clearInterval(periodicStatsTimer);
clearInterval(doneYet);
clearInterval(periodicStatsTimer);

sendStats();
sendStats();

intermediate.free();
intermediate.free();

let aggregateReport = Stats.combine(aggregate).report();
return ee.emit('done', aggregateReport);
} else {
debug('Pending requests: %s', runState.pendingRequests);
debug('Pending scenarios: %s', runState.pendingScenarios);
}
}, 500);
});
let aggregateReport = Stats.combine(aggregate).report();
return ee.emit('done', aggregateReport);
} else {
debug('Pending requests: %s', runState.pendingRequests);
debug('Pending scenarios: %s', runState.pendingScenarios);
}
}, 500);
});

const periodicStatsTimer = setInterval(sendStats, options.periodicStats * 1000);
const periodicStatsTimer = setInterval(sendStats, options.periodicStats * 1000);

function sendStats() {
aggregate.push(intermediate.clone());
intermediate._concurrency = runState.pendingScenarios;
intermediate._pendingRequests = runState.pendingRequests;
ee.emit('stats', intermediate.clone());
intermediate.reset();
}
function sendStats() {
intermediate._concurrency = runState.pendingScenarios;
intermediate._pendingRequests = runState.pendingRequests;
ee.emit('stats', intermediate.clone());
delete intermediate._entries;
aggregate.push(intermediate.clone());
intermediate.reset();
}

phaser.run();
phaser.run();
}

function runScenario(script, intermediate, runState) {
const start = process.hrtime();

//
// Compile scenarios if needed
//
if (!runState.compiledScenarios) {
_.each(script.scenarios, function(scenario) {
if (!scenario.weight) {
scenario.weight = 1;
}
});
const start = process.hrtime();

//
// Compile scenarios if needed
//
if (!runState.compiledScenarios) {
_.each(script.scenarios, function(scenario) {
if (!scenario.weight) {
scenario.weight = 1;
}
});

runState.picker = wl(script.scenarios);
runState.picker = wl(script.scenarios);

runState.scenarioEvents = new EventEmitter();
runState.scenarioEvents.on('counter', function(name, value) {
Expand All @@ -330,74 +337,83 @@ function runScenario(script, intermediate, runState) {
runState.scenarioEvents.on('request', function() {
intermediate.newRequest();

runState.pendingRequests++;
});
runState.scenarioEvents.on('match', function() {
intermediate.addMatch();
});
runState.scenarioEvents.on('response', function(delta, code, uid) {
intermediate.completedRequest();
intermediate.addLatency(delta);
intermediate.addCode(code);
runState.pendingRequests++;
});
runState.scenarioEvents.on('match', function() {
intermediate.addMatch();
});
runState.scenarioEvents.on('response', function(delta, code, uid) {
intermediate.completedRequest();
intermediate.addLatency(delta);
intermediate.addCode(code);

let entry = [Date.now(), uid, delta, code];
intermediate.addEntry(entry);
let entry = [Date.now(), uid, delta, code];

runState.pendingRequests--;
});
intermediate.addEntry(entry);

runState.compiledScenarios = _.map(
script.scenarios,
function(scenarioSpec) {
const name = scenarioSpec.engine || 'http';
const engine = runState.engines.find((e) => e.__name === name);
return engine.createScenario(scenarioSpec, runState.scenarioEvents);
}
);
}
runState.pendingRequests--;
});

runState.compiledScenarios = _.map(
script.scenarios,
function(scenarioSpec) {
const name = scenarioSpec.engine || 'http';
const engine = runState.engines.find((e) => e.__name === name);
return engine.createScenario(scenarioSpec, runState.scenarioEvents);
}
);
}

let i = runState.picker()[0];
let i = runState.picker()[0];

debug('picking scenario %s (%s) weight = %s',
debug('picking scenario %s (%s) weight = %s',
i,
script.scenarios[i].name,
script.scenarios[i].weight);

intermediate.newScenario(script.scenarios[i].name || i);

const scenarioStartedAt = process.hrtime();
const scenarioContext = createContext(script);
const finish = process.hrtime(start);
const runScenarioDelta = (finish[0] * 1e9) + finish[1];
debugPerf('runScenarioDelta: %s', Math.round(runScenarioDelta / 1e6 * 100) / 100);
runState.compiledScenarios[i](scenarioContext, function(err, context) {
runState.pendingScenarios--;
if (err) {
debug(err);
} else {
const scenarioFinishedAt = process.hrtime(scenarioStartedAt);
const delta = (scenarioFinishedAt[0] * 1e9) + scenarioFinishedAt[1];
intermediate.addScenarioLatency(delta);
intermediate.completedScenario();
}
});
intermediate.newScenario(script.scenarios[i].name || i);

const scenarioStartedAt = process.hrtime();
const scenarioContext = createContext(script);
const finish = process.hrtime(start);
const runScenarioDelta = (finish[0] * 1e9) + finish[1];
debugPerf('runScenarioDelta: %s', Math.round(runScenarioDelta / 1e6 * 100) / 100);
runState.compiledScenarios[i](scenarioContext, function(err, context) {
runState.pendingScenarios--;
if (err) {
debug(err);
} else {
const scenarioFinishedAt = process.hrtime(scenarioStartedAt);
const delta = (scenarioFinishedAt[0] * 1e9) + scenarioFinishedAt[1];
intermediate.addScenarioLatency(delta);
intermediate.completedScenario();
}
});
}

/**
* Create initial context for a scenario.
*/
* Create initial context for a scenario.
*/
function createContext(script) {
const INITIAL_CONTEXT = {
vars: {
target: script.config.target,
$environment: script._environment
},
funcs: {
$randomNumber: $randomNumber,
$randomString: $randomString
}
let initialContext = {};
if (contextVars) {
initialContext = {
vars: contextVars
};
} else {
initialContext = {
vars: {
target: script.config.target,
$environment: script._environment
}
};
}
initialContext.funcs = {
$randomNumber: $randomNumber,
$randomString: $randomString
};
let result = _.cloneDeep(INITIAL_CONTEXT);

let result = _.cloneDeep(initialContext);

//
// variables from payloads
Expand Down Expand Up @@ -434,9 +450,30 @@ function createContext(script) {
// Generator functions for template strings:
//
function $randomNumber(min, max) {
return _.random(min, max);
return _.random(min, max);
}

function $randomString(length) {
return Math.random().toString(36).substr(2, length);
return Math.random().toString(36).substr(2, length);
}

function handleBeforeRequests(script, runnableScript, runnerEngines, testEvents) {
let ee = new EventEmitter();
ee.on('request', function() {
testEvents.emit('beforeTestRequest');
});
ee.on('error', function(error) {
testEvents.emit('beforeTestError', error);
});
let name = runnableScript.before.engine || 'http';
let engine = runnerEngines.find((e) => e.__name === name);
let beforeTestScenario = engine.createScenario(runnableScript.before, ee);
let beforeTestContext = createContext(script);
beforeTestScenario(beforeTestContext, function(err, context) {
if (err) {
debug(err);
} else {
contextVars = context.vars;
}
});
}
12 changes: 12 additions & 0 deletions core/lib/schemas/artillery_test_script.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@
}
}
},
"before": {
"type": "object",
"properties": {
"flow": {
"type": "array",
"items": {
"type": "object"
}
}
},
"required": ["flow"]
},
"scenarios": {
"type": "array"
}
Expand Down
7 changes: 1 addition & 6 deletions core/lib/stats2.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ function create() {
function combine(statsObjects) {
let result = create();
L.each(statsObjects, function(stats) {
L.each(stats._entries, function(entry) {
result._entries.push(entry);
});
L.each(stats._latencies, function(latency) {
result._latencies.push(latency);
});
Expand Down Expand Up @@ -169,9 +166,7 @@ Stats.prototype.report = function() {
result.scenariosCompleted = this._completedScenarios;
result.requestsCompleted = this._completedRequests;

let latencies = L.map(this._entries, (e) => {
return e[2];
});
let latencies = this._latencies;

result.latency = {
min: round(L.min(latencies) / 1e6, 1),
Expand Down
Loading

0 comments on commit 982c785

Please sign in to comment.