Comparing version 0.1.14 to 0.1.15
@@ -151,5 +151,14 @@ 'use strict'; | ||
{ | ||
var errorCode = null; | ||
if (error) | ||
{ | ||
log.debug('Connection %s failed: %s', id, error); | ||
if (result) | ||
{ | ||
errorCode = result; | ||
} | ||
else | ||
{ | ||
errorCode = '-1'; | ||
} | ||
} | ||
@@ -160,3 +169,3 @@ else | ||
} | ||
operation.latency.end(id); | ||
operation.latency.end(id, errorCode); | ||
var callback; | ||
@@ -186,3 +195,3 @@ if (!params.requestsPerSecond) | ||
{ | ||
callback('Connection ' + id + ' failed: ' + error); | ||
callback('Connection ' + id + ' failed: ' + error, '1'); | ||
}); | ||
@@ -193,3 +202,3 @@ connection.on('end', function(result) | ||
{ | ||
return callback('Status code ' + connection.statusCode); | ||
return callback('Status code ' + connection.statusCode, connection.statusCode); | ||
} | ||
@@ -263,3 +272,2 @@ callback(null, false); | ||
var requests = 0; | ||
var errors = 0; | ||
var showTimer; | ||
@@ -278,3 +286,3 @@ | ||
} | ||
showTimer = new timing.HighResolutionTimer(SHOW_INTERVAL_MS, showPartial); | ||
showTimer = new timing.HighResolutionTimer(SHOW_INTERVAL_MS, self.latency.showPartial); | ||
} | ||
@@ -288,6 +296,2 @@ | ||
requests += 1; | ||
if (error) | ||
{ | ||
errors += 1; | ||
} | ||
if (options.maxRequests) | ||
@@ -356,15 +360,2 @@ { | ||
} | ||
/** | ||
* Show partial results. | ||
*/ | ||
function showPartial() | ||
{ | ||
self.latency.showPartial(); | ||
if (errors) | ||
{ | ||
var percent = Math.round(100 * 10 * errors / requests) / 10; | ||
log.info('Errors: %s, %s% of total requests', errors, percent); | ||
} | ||
} | ||
} | ||
@@ -371,0 +362,0 @@ |
@@ -87,2 +87,24 @@ 'use strict'; | ||
/** | ||
* Repeat the given string a few times. | ||
* Based on: http://stackoverflow.com/a/5450113/978796 | ||
*/ | ||
String.prototype.repeat = function(count) | ||
{ | ||
if (count < 1) | ||
{ | ||
return ''; | ||
} | ||
var result = '', pattern = this.valueOf(); | ||
while (count > 0) | ||
{ | ||
if (count & 1) | ||
{ | ||
result += pattern; | ||
} | ||
count >>= 1, pattern += pattern; | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Run tests for string prototypes. | ||
@@ -89,0 +111,0 @@ */ |
@@ -38,2 +38,3 @@ 'use strict'; | ||
var partialTime = 0; | ||
var partialErrors = 0; | ||
var lastShown = microtime.now(); | ||
@@ -43,4 +44,6 @@ var initialTime = microtime.now(); | ||
var totalTime = 0; | ||
var totalErrors = 0; | ||
var maxLatencyMs = 0; | ||
var histogramMs = {}; | ||
var errorCodes = {}; | ||
var running = true; | ||
@@ -70,4 +73,5 @@ | ||
* Compute elapsed time and add the measurement. | ||
* Accepts an optional error code signaling an error. | ||
*/ | ||
self.end = function(requestId) | ||
self.end = function(requestId, errorCode) | ||
{ | ||
@@ -83,3 +87,3 @@ if (!(requestId in requests)) | ||
} | ||
add(microtime.now() - requests[requestId]); | ||
add(microtime.now() - requests[requestId], errorCode); | ||
delete requests[requestId]; | ||
@@ -90,4 +94,5 @@ } | ||
* Add a new measurement, possibly removing an old one. | ||
* Accepts an optional error code signaling an error. | ||
*/ | ||
function add(time) | ||
function add(time, errorCode) | ||
{ | ||
@@ -99,2 +104,13 @@ log.debug('New value: %s', time); | ||
totalRequests++; | ||
if (errorCode) | ||
{ | ||
errorCode = '' + errorCode; | ||
partialErrors++; | ||
totalErrors++; | ||
if (!(errorCode in errorCodes)) | ||
{ | ||
errorCodes[errorCode] = 0; | ||
} | ||
errorCodes[errorCode] += 1; | ||
} | ||
log.debug('Partial requests: %s', partialRequests); | ||
@@ -135,4 +151,10 @@ var rounded = Math.floor(time / 1000); | ||
log.info('Requests: %s%s, requests per second: %s, mean latency: %s ms', totalRequests, percent, results.rps, results.meanLatencyMs); | ||
if (totalErrors) | ||
{ | ||
var percent = Math.round(100 * 10 * totalErrors / totalRequests) / 10; | ||
log.info('Errors: %s, accumulated errors: %s, %s% of total requests', partialErrors, totalErrors, percent); | ||
} | ||
partialTime = 0; | ||
partialRequests = 0; | ||
partialErrors = 0; | ||
lastShown = microtime.now(); | ||
@@ -183,2 +205,3 @@ } | ||
totalRequests: totalRequests, | ||
totalErrors: totalErrors, | ||
totalTimeSeconds: elapsedSeconds, | ||
@@ -188,2 +211,3 @@ rps: Math.round(totalRequests / elapsedSeconds), | ||
percentiles: self.computePercentiles(), | ||
errorCodes: errorCodes, | ||
} | ||
@@ -244,2 +268,13 @@ } | ||
log.info(' 100% %s ms (longest request)', maxLatencyMs); | ||
if (results.totalErrors) | ||
{ | ||
log.info(''); | ||
log.info('Total errors: %s', results.totalErrors); | ||
log.info(''); | ||
for (var errorCode in results.errorCodes) | ||
{ | ||
var padding = ' '.repeat(4 - errorCode.length); | ||
log.info(' %s%s: %s errors', padding, errorCode, results.errorCodes[errorCode]); | ||
} | ||
} | ||
} | ||
@@ -281,8 +316,19 @@ } | ||
}; | ||
var latency = new exports.Latency(options, callback); | ||
for (var i = 0; i < 10; i++) | ||
var errorCode = '500'; | ||
var latency = new exports.Latency(options, function(error, result) | ||
{ | ||
testing.check(error, 'Could not compute latency', callback); | ||
testing.assertEquals(result.totalRequests, 10, 'Invalid total requests', callback); | ||
testing.assertEquals(result.totalErrors, 1, 'Invalid total errors', callback); | ||
testing.assert(errorCode in result.errorCodes, 'Error code not found', callback); | ||
testing.assertEquals(result.errorCodes[errorCode], 1, 'Should have one ' + errorCode, callback); | ||
testing.success(callback); | ||
}); | ||
for (var i = 0; i < 9; i++) | ||
{ | ||
var id = latency.start(); | ||
latency.end(id); | ||
} | ||
var id = latency.start(); | ||
latency.end(id, errorCode); | ||
} | ||
@@ -289,0 +335,0 @@ |
{ | ||
"name": "loadtest", | ||
"version": "0.1.14", | ||
"version": "0.1.15", | ||
"description": "Run load tests for your web application. Mostly ab-compatible interface, with an option to force requests per second. API for automated load testing.", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/alexfernandez/loadtest", |
@@ -70,3 +70,4 @@ | ||
Controls the number of requests per second for each client. Can be fractional, e.g. --rps 0.5 sends one request every two seconds per client. | ||
Controls the number of requests per second for each client. | ||
Can be fractional, e.g. --rps 0.5 sends one request every two seconds per client. | ||
@@ -79,2 +80,8 @@ #### --agent | ||
#### --keepalive | ||
Use agentkeepalive, which includes 'Connection: Keep-alive' | ||
and is better performing than the default node.js agent. | ||
https://npmjs.org/package/agentkeepalive | ||
#### --quiet | ||
@@ -84,2 +91,6 @@ | ||
#### --debug | ||
Show debug messages. | ||
### Server | ||
@@ -156,3 +167,3 @@ | ||
The results passed to your callback at the end of the load test contains a full set of data, including: mean latency, and percentiles. | ||
The results passed to your callback at the end of the load test contains a full set of data, including: mean latency, number of errors and percentiles. | ||
An example follows: | ||
@@ -170,3 +181,8 @@ | ||
totalTimeSeconds: 0.354108, | ||
meanLatencyMs: 7.72 | ||
meanLatencyMs: 7.72, | ||
totalErrors: 3, | ||
errors: { | ||
'0': 1, | ||
'500': 2 | ||
} | ||
} | ||
@@ -173,0 +189,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
42737
1478
220