Socket
Socket
Sign inDemoInstall

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.0.2 to 0.0.3

index.js

267

lib/loadtest.js

@@ -15,15 +15,15 @@ 'use strict';

var prototypes = require('./prototypes.js');
var timing = require('./timing.js');
// globals
var log = new Log('info');
var concurrency = 10;
var requestsPerSecond = 20;
var secondsMeasured = 5;
var server = 'localhost:80';
var globalConcurrency = 100;
var globalRequestsPerSecond = 1;
var agent = true;
/**
* Latency measurements, global variable.
* A client for an HTTP connection.
*/
var latency = new function()
function HttpClient(url, requestsPerSecond)
{

@@ -34,77 +34,31 @@ // self-reference

// attributes
var requests = {};
var measurements = [];
var index = 0;
var max = concurrency * requestsPerSecond * secondsMeasured;
var total = 0;
var connection;
var lastCall;
/**
* Start the request with the given id.
* Start the HTTP client.
*/
self.start = function(requestId)
self.start = function()
{
requests[requestId] = new Date().getTime();
}
/**
* Compute elapsed time and add the measurement.
*/
self.end = function(requestId)
{
if (!(requestId in requests))
if (!requestsPerSecond)
{
console.error('Message id ' + requestId + ' not found');
log.error('No requests per second selected');
return;
}
add(new Date().getTime() - requests[requestId]);
delete requests[requestId];
var interval = Math.round(1000 / requestsPerSecond);
new timing.HighResolutionTimer(interval, makeRequest);
}
/**
* Add a new measurement, possibly removing an old one.
* Make a single request to the server.
*/
function add(value)
function makeRequest()
{
measurements.push(value);
total += value;
if (measurements.length > max)
var id = timing.latency.start(id);
var options = urlLib.parse(url);
if (!agent)
{
var removed = measurements.shift();
total -= removed;
options.agent = false;
}
index++;
debug('Index: ' + index);
if (index > max)
{
var mean = total / measurements.length;
info('Mean latency: ' + mean);
index = 0;
}
}
}
/**
* A client for an HTTP connection.
*/
function HttpClient(url)
{
// self-reference
var self = this;
// attributes
var connection;
var lastCall;
/**
* Start the HTTP client.
*/
self.start = function()
{
setInterval(get, Math.round(1000 / requestsPerSecond));
}
function get()
{
var options = urlLib.parse(url);
var get = http.get(url, connect);
var get = http.get(options, getConnect(id));
get.on('error', function(error)

@@ -117,12 +71,26 @@ {

/**
* Connect the player.
* Get a function to connect the player.
*/
function connect(connection)
function getConnect(id)
{
log.debug('HTTP client connected to %s', url);
connection.setEncoding('utf8');
connection.on('data', function(chunk)
return function(connection)
{
log.debug('Body: %s', chunk);
});
log.debug('HTTP client connected to %s with id %s', url, id);
connection.setEncoding('utf8');
connection.on('data', function(chunk)
{
log.debug('Body: %s', chunk);
});
connection.on('error', function(error)
{
log.error('Connection %s failed: %s', id, error);
timing.latency.end(id);
});
connection.on('end', function(result)
{
log.debug('Connection %s ended', id);
timing.latency.end(id);
});
};
}

@@ -134,3 +102,3 @@ }

*/
function WebsocketClient(url)
function WebsocketClient(url, requestsPerSecond)
{

@@ -155,3 +123,3 @@ // self-reference

client.connect(url, []);
info('WebSocket client connected to ' + url);
log.debug('WebSocket client connected to ' + url);
}

@@ -169,3 +137,3 @@

connection.on('close', function() {
info('Connection closed');
log.debug('Connection closed');
});

@@ -181,3 +149,3 @@ connection.on('message', function(message) {

var newCall = new Date().getTime();
latency.add(newCall - lastCall);
timing.latency.add(newCall - lastCall);
entry += ', latency: ' + (newCall - lastCall);

@@ -213,3 +181,3 @@ lastCall = null;

{
info('Starting game for ' + self.playerId);
log.debug('Starting game for ' + self.playerId);
setInterval(requestUpdate, Math.round(1000 / requestsPerSecond));

@@ -220,3 +188,3 @@ return;

{
latency.end(message.requestId);
timing.latency.end(message.requestId);
}

@@ -237,3 +205,3 @@ }

connection.sendUTF(JSON.stringify(update));
latency.start(update.requestId);
timing.latency.start(update.requestId);
}

@@ -244,2 +212,43 @@ }

/**
* Run a load test.
*/
exports.loadTest = function(url, concurrency, requestsPerSecond)
{
var constructor;
if (url.startsWith('ws://'))
{
constructor = function(url, requestsPerSecond)
{
return new WebsocketClient(url, requestsPerSecond);
};
}
else if (url.startsWith('http'))
{
constructor = function(url, requestsPerSecond)
{
return new HttpClient(url, requestsPerSecond);
};
}
else
{
return help();
}
startClients(url, concurrency, requestsPerSecond, constructor);
}
/**
* Start a number of measuring clients.
*/
function startClients(url, concurrency, requestsPerSecond, constructor)
{
for (var index = 0; index < concurrency; index++)
{
url = url.replaceAll('$index', index);
var client = constructor(url, requestsPerSecond);
// start each client 100 ms after the last
setTimeout(client.start, (index * 100) % 1000);
}
}
/**
* Display online help.

@@ -249,74 +258,82 @@ */

{
console.log('Usage: %s %s [concurrency] [reqs/s] [seconds measured] URL');
console.log('Usage: %s %s [options] [concurrency] [req/s] URL');
console.log(' where URL can be a regular HTTP or websocket URL.');
console.log(' If you want to add an index to the URL, place a $index in it.');
console.log(' Options:');
console.log(' --noagent: send Connection: close');
console.log(' --agent: send Connection: keep-alive (default)');
}
var numbersParsed = 0;
/**
* Process command line arguments.
* Parse one argument. Returns true if there are more.
*/
function processArgs(args)
function parseArgument(args)
{
if (args.length == 0)
if (args.length <= 1)
{
return help();
return false;
}
if (parseInt(args[0]))
var argument = args[0];
if (parseInt(argument))
{
concurrency = parseInt(args[0]);
args.splice(0, 1);
if (parseInt(args[0]))
if (numbersParsed == 0)
{
requestsPerSecond = parseInt(args[0]);
args.splice(0, 1);
if (parseInt(args[0]))
{
secondsMeasured = parseInt(args[0]);
args.splice(0, 1);
}
globalConcurrency = parseInt(argument);
}
else if (numbersParsed == 1)
{
globalRequestsPerSecond = parseInt(argument);
}
else
{
log.error('Too many numeric arguments');
return false;
}
args.splice(0, 1);
numbersParsed += 1;
return true;
}
if (args.length != 1)
if (!argument.startsWith('--'))
{
return help();
console.error('Unknown argument %s', argument);
return false;
}
var url = args[0];
var constructor;
if (url.startsWith('ws://'))
if (argument == '--noagent')
{
constructor = function(url)
{
return new WebsocketClient(url);
};
agent = false;
args.splice(0, 1);
return true;
}
else if (url.startsWith('http'))
if (argument == '--agent')
{
constructor = function(url)
{
return new HttpClient(url);
};
args.splice(0, 1);
return true;
}
else
{
return help();
}
startClients(url, constructor);
console.error('Unknown option %s', argument);
return false;
}
/**
* Start a number of measuring clients.
* Process command line arguments.
*/
function startClients(url, constructor)
function processArgs(args)
{
for (var index = 0; index < concurrency; index++)
while (parseArgument(args))
{
var url = url.replaceAll('$index', index);
var client = constructor(url);
// start each client 100 ms after the last
setTimeout(client.start, (index * 100) % 1000);
}
if (args.length != 1)
{
return help();
}
var url = args[0];
exports.loadTest(url, globalConcurrency, globalRequestsPerSecond);
}
// init
processArgs(process.argv.slice(2));
// start load test if invoked directly
if (__filename == process.argv[1])
{
processArgs(process.argv.slice(2));
}

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

// requires
var Log = require('log');
// globals
var log = new Log('info');
/**

@@ -34,1 +39,40 @@ * Find out if the string has the parameter at the beginning.

/**
* Run package tests.
*/
exports.test = function()
{
if (!'pepito'.startsWith('pe'))
{
log.error('Failed to match using startsWith()')
return false;
}
if ('pepito'.startsWith('po'))
{
log.error('Invalid match using startsWith()')
return false;
}
if (!'pepito'.endsWith('to'))
{
log.error('Failed to match using endsWith()')
return false;
}
if ('pepito'.startsWith('po'))
{
log.error('Invalid match using endsWith()')
return false;
}
if ('pepito'.replaceAll('p', 'c') != 'cecito')
{
log.error('Invalid replaceAll().');
return false;
}
return true;
}
// run tests if invoked directly
if (__filename == process.argv[1])
{
exports.test();
}
{
"name": "loadtest",
"version": "0.0.2",
"version": "0.0.3",
"description": "Load test scripts.",

@@ -15,2 +15,3 @@ "homepage": "http://milliearth.org/",

"websocket": "*",
"microtime": "*",
"log": "*"

@@ -22,3 +23,6 @@ },

},
"scripts": {
"test": "node test.js"
},
"private": false
}

@@ -9,2 +9,5 @@ loadtest

Just run:
$ npm install loadtest
Usage

@@ -14,12 +17,15 @@ -----

Run as a script to load test a URL:
$ node loadtest.js [URL] or [websocket URL]
To get online help run without parameters:
$ node loadtest.js
$ node lib/loadtest.js [URL] or [websocket URL]
To get online help, run loadtest.js without parameters:
$ node lib/loadtest.js
### Advanced Usage
Add your own values for concurrency, requests per second and seconds measured:
$ node loadtest.js [concurrency [request per second [seconds measured]]] ...
Add your own values for concurrency and requests per second:
$ node lib/loadtest.js [concurrency [request per second]] ...
## Concurrency

@@ -33,6 +39,17 @@

## Seconds Measured
## --noagent
How many seconds must be measured before showing the default latency.
Open connections without keep-alive: send header 'Connection: Close' instead of 'Connection: Keep-alive'.
Server
------
loadtest bundles a test server. To run it:
$ node lib/server.js [port]
It will show the number of requests received per second, the latency in answering requests and the headers for selected requests.
This server returns a short text 'OK' for every request, removing request processing from latency measurements.
License

@@ -39,0 +56,0 @@ -------

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