Load Test Example

This example shows how to create a simple load tester for Union Server using OrbiterMicroNode. To simulate a high user load, the load tester connects multiple clients from a single Node.JS process. Clients are connected one at a time until the requested number of clients is reached. Each connected client generates traffic for load testing by sending one message to itself every n milliseconds for long as it is connected. Hence, if 10 clients are connected, and the specified message frequency is 1000 (i.e., send one message per 1000 milliseconds), then the load tester will generate 10 messages per second in total (plus additional messages for automatic client pings). The number of clients in the test and the message sending frequency are specified as command-line arguments.

To run the load test with 10 clients connecting to example.com on port 9100, follow these steps:

  1. Obtain and install Node.JS from http://nodejs.org/. The load tester has been tested up to Node 0.4.8.
  2. Download the load test code from http://www.unionplatform.com/samples/orbitermicronode/loadtest/.
  3. Unzip the file you downloaded in step 2. A folder named OrbiterMicroNodeLoadTest will be created.
  4. At your system's command prompt, from the OrbiterMicroNodeLoadTest directory, issue the following command :
    node OrbiterMicroNodeLoadTest.js example.com 9100 10 1000
    

Here is the source code for the load test:

//==============================================================================
// VARIABLES
//==============================================================================
// Application variables
var net;
var orbiter;
var msgManager;
var UPC;
var clients;

// Command-line arguments
var host;
var port;
var numClients;
var sendMessageFrequency;
var debugMode = false;

//==============================================================================
// BOOT FUNCTIONS
//==============================================================================
function main () {
  // Quit if command line args don't validate
  var args = process.argv.slice(2);
  if (args.length < 4) {
    usage();
    return;
  }

  out('');
  out('==============================');
  out('* OrbiterMicroNode Load Test *');
  out('==============================');
  out('Booting... Use [q] to exit.');

  // Parse command-line args
  host = args[0];
  port = parseInt(args[1]);
  numClients = parseInt(args[2]);;
  sendMessageFrequency = parseInt(args[3]);
  debugMode = args[4] == "debug";

  // Can't continue with invalid input
  if (isNaN(port) || port < 1) {
    out("Invalid port specified: " + args[1]);
    process.exit();
  }
  if (isNaN(numClients) || numClients < 1) {
    out("Invalid numClients specified: " + args[2]);
    process.exit();
  }
  if (isNaN(sendMessageFrequency) || sendMessageFrequency < 1) {
    out("Invalid messageFrequency specified: " + args[3]);
    process.exit();
  }

  // Load OrbiterMicroNode module
  net = require('OrbiterMicroNode_2.0.0.136_Release').net;

  // Listen for command-line input
  var stdin = process.openStdin();
  stdin.on('data', onStdInData);

  // Assign initial variable values
  UPC = net.user1.orbiter.UPC;
  clients = [];

  // Start the test
  run();
}

function usage() {
  out('Usage:');
  out('node OrbiterMicroNodeLoadTest.js [host] [port] [numClients] [messageFrequency] [debug]');
  out('  -debug (optional) enables debug logging')
  out('E.g. Ten clients; each client sends a message every 500ms (no debugging):');
  out('  node OrbiterMicroNodeLoadTest.js example.com 80 10 500');
  out('E.g. Two clients; each client sends a message every 1000ms (with debugging):');
  out('  node OrbiterMicroNodeLoadTest.js example.com 80 2 1000 debug');
  process.exit();
}

function run () {
  // Output the test parameters to the console
  out('Connecting ' + numClients + ' client(s) to ' + host + ':' + port
      + ' with messageFrequency: ' + sendMessageFrequency);
  // Connect the first client
  addClient();
}

//==============================================================================
// CLIENT CREATION
//==============================================================================
function addClient () {
  // Create the client
  orbiter = new net.user1.orbiter.Orbiter();
  orbiter.addEventListener(net.user1.orbiter.OrbiterEvent.READY, readyListener, this);
  orbiter.addEventListener(net.user1.orbiter.OrbiterEvent.CLOSE, closeListener, this);

  // Send a message to self every sendMessageFrequency milliseconds
  msgManager = orbiter.getMessageManager();
  var intervalID = setInterval (function () {
    if (orbiter.isReady()) {
      msgManager.sendUPC(UPC.SEND_MESSAGE_TO_CLIENTS, "TEST", orbiter.getClientID());
    } else {
      clearInterval(intervalID);
    }
  }, sendMessageFrequency);

  // Register for log events if requested
  if (debugMode) {
    orbiter.getLog().setLevel("debug");
    orbiter.getLog().addEventListener("UPDATE", logUpdateListener);
  }  

  // Add the client to the list of clients
  clients.push(orbiter);

  // Connect to Union Server
  orbiter.connect(host, port);
}

//==============================================================================
// ORBITER EVENT LISTENERS
//==============================================================================
// Triggered when a client's connection is ready
function readyListener (e) {
  // If the requested number of clients has not yet connected, connect another client
  if (clients.length < numClients) {
    if (clients.length % Math.floor(numClients/10) == 0) {
      out('    ' + clients.length + ' clients connected.');
    }
    addClient();
  } else {
    out('Done. Successfully connected ' + clients.length + ' client(s).');
    out('Test in progress...');
  }
}

// Triggered when a client connection is closed
function closeListener (e) {
  out("Orbiter connection closed.");
}

//==============================================================================
// LOG UPDATE LISTENER
//==============================================================================
function logUpdateListener (e) {
  out(e.getLevel() + ": " + e.getMessage());
}

//==============================================================================
// STD IN/OUT
//==============================================================================
function out (msg) {
  console.log(msg);
}

function onStdInData (data) {
  var data = data.toString().trim();
  var cmd = data.split(':')[0];
  var data = data.split(':')[1];
  switch (cmd) {
    case 'exit':
    case 'quit':
    case 'q':
      process.exit();
      break;
  }
}

//==============================================================================
// BOOT THE APP
//==============================================================================
main();