Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

loadtest

Package Overview
Dependencies
Maintainers
1
Versions
122
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

loadtest - npm Package Compare versions

Comparing version 0.2.0 to 0.2.1

bin/loadtest.js

10

CHANGELOG.md

@@ -19,1 +19,11 @@

### 2013-09-01: version 0.2.1
* Added bin/ files to avoid cross-platform issues.
Parse arguments using `optimist`.
Pull request #9 by https://github.com/zaphod1984
* Use native process.hrtime() instead of Microtime.
Pull request #8 by to https://github.com/zaphod1984
* Changed binary testserver to testserver-loadtest, to avoid conflicts.
Issue #4. Thanks to https://github.com/zaphod1984

152

lib/loadtest.js

@@ -17,2 +17,3 @@ 'use strict';

var websocket = require('./websocket.js');
var ce = require('cloneextend');

@@ -25,3 +26,3 @@ // globals

noAgent: true,
concurrency: 1,
concurrency: 1
};

@@ -115,3 +116,3 @@ var SHOW_INTERVAL_MS = 5000;

requestTimer = new timing.HighResolutionTimer(interval, self.makeRequest);
}
};

@@ -127,3 +128,3 @@ /**

}
}
};

@@ -151,3 +152,3 @@ /**

request.end();
}
};

@@ -267,3 +268,3 @@ /**

operation.start();
}
};

@@ -297,3 +298,3 @@ /**

showTimer = new timing.HighResolutionTimer(SHOW_INTERVAL_MS, self.latency.showPartial);
}
};

@@ -321,3 +322,3 @@ /**

}
}
};

@@ -361,6 +362,7 @@ /**

self.running = false;
for (var index in clients)
{
Object.keys(clients).forEach(function(index) {
clients[index].stop();
}
});
if (callback)

@@ -371,133 +373,11 @@ {

}
}
};
/**
* Display online help.
*/
function help()
{
console.log('Usage: loadtest [options] URL');
console.log(' where URL can be a regular HTTP or websocket URL:');
console.log(' runs a load test for the given URL');
console.log('Apache ab-compatible options are:');
console.log(' -n requests Number of requests to perform');
console.log(' -c concurrency Number of multiple requests to make');
console.log(' -t timelimit Seconds to max. wait for responses');
console.log(' -C name=value Send a cookie with the given name');
console.log(' -T content-type The MIME type for the body');
console.log(' -p POST-file Send the contents of the file as POST body');
console.log(' -u PUT-file Send the contents of the file as PUT body');
console.log(' -r Do not exit on socket receive errors');
console.log('Other options are:');
console.log(' --rps Requests per second for each client');
console.log(' --noagent Do not use http agent (default)');
console.log(' --agent Use http agent (Connection: keep-alive)');
console.log(' --keepalive Use a specialized keep-alive http agent (agentkeepalive)');
console.log(' --index param Replace the value of param with an index in the URL');
console.log(' --quiet Do not log any messages');
console.log(' --debug Show debug messages');
}
/**
* Parse one argument and change options accordingly.
* Returns true if there may be more arguments to parse.
*/
function parseArgument(args, options)
{
if (args.length <= 1)
{
return false;
}
if (!args[0].startsWith('-'))
{
return false;
}
// consume the argument
var argument = args.shift();
switch(argument)
{
case '-n':
options.maxRequests = args.shift();
return true;
case '-c':
options.concurrency = args.shift();
return true;
case '-t':
options.maxSeconds = args.shift();
return true;
case '-C':
addCookie(args.shift(), options);
return true;
case '-T':
options.contentType = args.shift();
return true;
case '-p':
options.method = 'POST';
options.body = fs.readFileSync(args.shift()).toString();
return true;
case '-u':
options.method = 'PUT';
options.body = fs.readFileSync(args.shift()).toString();
return true;
case '-r':
options.recover = true;
return true;
case '--rps':
options.requestsPerSecond = parseFloat(args.shift());
return true;
case '--noagent':
return true;
case '--agent':
options.noAgent = false;
return true;
case '--keepalive':
options.agentKeepAlive = true;
return true;
case '--quiet':
options.quiet = true;
return true;
case '--debug':
options.debug = true;
return true;
}
console.error('Unknown option %s', argument);
return false;
}
/**
* Add a cookie to the options.
*/
function addCookie(cookie, options)
{
if (!options.cookies)
{
options.cookies = [];
}
options.cookies.push(cookie);
}
/**
* Process command line arguments and run
*/
exports.run = function(args)
exports.run = function(options)
{
var options = DEFAULT_OPTIONS;
while (parseArgument(args, options))
{
}
if (args.length != 1)
{
if (args.length == 0)
{
console.error('Missing URL');
}
else
{
console.error('Unknown arguments %s', JSON.stringify(args));
}
return help();
}
options.url = args[0];
exports.loadTest(options);
}
exports.loadTest(ce.cloneextend(DEFAULT_OPTIONS, options));
};

@@ -504,0 +384,0 @@ // start load test if invoked directly

@@ -94,3 +94,3 @@ 'use strict';

testing.assertEquals(result.totalRequests, 100, 'Invalid total requests', callback);
testing.assert(result.meanLatencyMs > delay, 'Delay should be higher than %s, not %s', delay, result.meanLatencyMs, callback);
testing.assert(result.meanLatencyMs >= delay, 'Delay should be higher than %s, not %s', delay, result.meanLatencyMs, callback);
callback(null, result);

@@ -97,0 +97,0 @@ });

@@ -150,52 +150,4 @@ 'use strict';

return server.start(callback);
}
};
/**
* Display online help.
*/
function help()
{
console.log('Usage: testserver [options] [port]');
console.log(' starts a test server on the given port, default 80.');
console.log('Options are:');
console.log(' --delay Delay the response for the given milliseconds');
}
/**
* Process command line arguments.
*/
exports.run = function(args)
{
var options = {};
while (args.length > 0 && args[0].startsWith('--'))
{
var arg = args.shift();
if (arg == '--delay')
{
options.delay = parseInt(args.shift());
}
else
{
return help();
}
}
if (args.length > 1)
{
return help();
}
if (args.length == 1)
{
var arg = args[0];
if (parseInt(arg))
{
options.port = parseInt(arg);
}
else
{
return help();
}
}
exports.startServer(options);
}
// start server if invoked directly

@@ -202,0 +154,0 @@ if (__filename == process.argv[1])

@@ -14,3 +14,2 @@ 'use strict';

var Log = require('log');
var microtime = require('microtime');
var prototypes = require('./prototypes.js');

@@ -40,4 +39,4 @@

var partialErrors = 0;
var lastShown = microtime.now();
var initialTime = microtime.now();
var lastShown = getTime();
var initialTime = getTime();
var totalRequests = 0;

@@ -67,5 +66,5 @@ var totalTime = 0;

requestId = requestId || createId();
requests[requestId] = microtime.now();
requests[requestId] = getTime();
return requestId;
}
};

@@ -87,5 +86,5 @@ /**

}
add(microtime.now() - requests[requestId], errorCode);
add(getElapsed(requests[requestId]), errorCode);
delete requests[requestId];
}
};

@@ -115,3 +114,3 @@ /**

log.debug('Partial requests: %s', partialRequests);
var rounded = Math.floor(time / 1000);
var rounded = Math.floor(time);
if (rounded > maxLatencyMs)

@@ -138,12 +137,12 @@ {

{
var elapsedSeconds = (microtime.now() - lastShown) / 1000000;
var elapsedSeconds = getElapsed(lastShown) / 1000;
var meanTime = partialTime / partialRequests || 0.0;
var results = {
meanLatencyMs: Math.round(meanTime / 10) / 100,
rps: Math.round(partialRequests / elapsedSeconds),
}
meanLatencyMs: Math.round(meanTime / 10) * 10,
rps: Math.round(partialRequests / elapsedSeconds)
};
var percent = '';
if (options.maxRequests)
{
var percent = ' (' + Math.round(100 * totalRequests / options.maxRequests) + '%)';
percent = ' (' + Math.round(100 * totalRequests / options.maxRequests) + '%)';
}

@@ -153,3 +152,3 @@ log.info('Requests: %s%s, requests per second: %s, mean latency: %s ms', totalRequests, percent, results.rps, results.meanLatencyMs);

{
var percent = Math.round(100 * 10 * totalErrors / totalRequests) / 10;
percent = Math.round(100 * 10 * totalErrors / totalRequests) / 10;
log.info('Errors: %s, accumulated errors: %s, %s% of total requests', partialErrors, totalErrors, percent);

@@ -160,6 +159,24 @@ }

partialErrors = 0;
lastShown = microtime.now();
lastShown = getTime();
};
/**
* Returns the current high-resolution real time in a [seconds, nanoseconds] tuple Array
* @return {*}
*/
function getTime() {
return process.hrtime();
}
/**
* calculates the elapsed time between the assigned startTime and now
* @param startTime
* @return {Number} the elapsed time in milliseconds
*/
function getElapsed(startTime) {
var elapsed = process.hrtime(startTime);
return elapsed[0] * 1000 + elapsed[1] / 1000000;
}
/**
* Check out if the measures are finished.

@@ -175,3 +192,3 @@ */

}
var elapsedSeconds = (microtime.now() - initialTime) / 1000000;
var elapsedSeconds = getElapsed(initialTime) / 1000;
if (options.maxSeconds && elapsedSeconds >= maxSeconds)

@@ -203,3 +220,3 @@ {

{
var elapsedSeconds = (microtime.now() - initialTime) / 1000000;
var elapsedSeconds = getElapsed(initialTime) / 1000;
var meanTime = totalTime / totalRequests;

@@ -211,7 +228,7 @@ return {

rps: Math.round(totalRequests / elapsedSeconds),
meanLatencyMs: Math.round(meanTime / 10) / 100,
meanLatencyMs: Math.round(meanTime / 10) * 10,
percentiles: self.computePercentiles(),
errorCodes: errorCodes,
errorCodes: errorCodes
}
}
};

@@ -228,5 +245,6 @@ /**

95: false,
99: false,
99: false
};
var counted = 0;
for (var ms = 0; ms <= maxLatencyMs; ms++)

@@ -241,4 +259,4 @@ {

var percent = counted / totalRequests * 100;
for (var percentile in percentiles)
{
Object.keys(percentiles).forEach(function(percentile) {
log.debug('Checking percentile %s for %s', percentile, percent);

@@ -249,6 +267,6 @@ if (!percentiles[percentile] && percent > percentile)

}
}
});
}
return percentiles;
}
};

@@ -265,9 +283,10 @@ /**

log.info('Requests per second: %s', results.rps);
log.info('Mean latency: %s ms', results.meanLatencyMs);
log.info('Total time: %s s', results.totalTimeSeconds);
log.info('');
log.info('Percentage of the requests served within a certain time');
for (var percentile in results.percentiles)
{
Object.keys(results.percentiles).forEach(function(percentile) {
log.info(' %s% %s ms', percentile, results.percentiles[percentile]);
}
});
log.info(' 100% %s ms (longest request)', maxLatencyMs);

@@ -277,12 +296,12 @@ if (results.totalErrors)

log.info('');
log.info('Total errors: %s', results.totalErrors);
log.info(' 100% %s ms (longest request)', maxLatencyMs);
log.info('');
for (var errorCode in results.errorCodes)
{
Object.keys(results.errorCodes).forEach(function(errorCode) {
var padding = ' '.repeat(4 - errorCode.length);
log.info(' %s%s: %s errors', padding, errorCode, results.errorCodes[errorCode]);
}
});
}
}
}
};
};

@@ -332,8 +351,9 @@

});
var id;
for (var i = 0; i < 9; i++)
{
var id = latency.start();
id = latency.start();
latency.end(id);
}
var id = latency.start();
id = latency.start();
latency.end(id, errorCode);

@@ -348,3 +368,3 @@ }

var options = {
maxRequests: 10,
maxRequests: 10
};

@@ -354,6 +374,7 @@ var latency = new exports.Latency(options, function(error, result)

var percentiles = latency.getResults().percentiles;
for (var percentile in percentiles)
{
Object.keys(percentiles).forEach(function(percentile) {
testing.assert(percentiles[percentile] !== false, 'Empty percentile for %s', percentile, callback);
}
});
testing.success(percentiles, callback);

@@ -418,3 +439,3 @@ });

log.debug('Seconds: ' + Math.round(diff / 1000) + ', counter: ' + counter + ', drift: ' + drift);
}
};

@@ -427,3 +448,3 @@ /**

active = false;
}
};

@@ -433,3 +454,3 @@ // start timer

setTimeout(delayed, delayMs);
}
};

@@ -454,6 +475,6 @@ /**

latencyPercentiles: testLatencyPercentiles,
timer: testTimer,
timer: testTimer
};
testing.run(tests, callback);
}
};

@@ -460,0 +481,0 @@ // run tests if invoked directly

{
"name": "loadtest",
"version": "0.2.0",
"version": "0.2.1",
"description": "Run load tests for your web application. Mostly ab-compatible interface, with an option to force requests per second. Includes an API for automated load testing.",

@@ -15,6 +15,7 @@ "homepage": "https://github.com/alexfernandez/loadtest",

"websocket": "*",
"microtime": "*",
"testing": "*",
"agentkeepalive": "*",
"log": "*"
"log": "*",
"optimist": "~0.6.0",
"cloneextend": "0.0.3"
},

@@ -26,4 +27,4 @@ "keywords" : ["testing", "test", "load test", "load testing", "http", "performance", "black box"],

"bin": {
"loadtest": "lib/cli-wrapper.js",
"testserver": "lib/cli-wrapper.js"
"loadtest": "lib/bin/loadtest.js",
"testserver-loadtest": "lib/bin/testserver.js"
},

@@ -30,0 +31,0 @@ "preferGlobal": true,

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc