summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2015-10-28 12:50:48 -0700
committerAdam Ierymenko <adam.ierymenko@gmail.com>2015-10-28 12:50:48 -0700
commitc6a918d9962dcf2354483b709b8bf0fffbbc3983 (patch)
tree54f8b9f631c011479c54a75cbf90f00e9c905480 /tests
parent0034efafe4f141d06d07464e7df2e151f4304294 (diff)
downloadinfinitytier-c6a918d9962dcf2354483b709b8bf0fffbbc3983.tar.gz
infinitytier-c6a918d9962dcf2354483b709b8bf0fffbbc3983.zip
HTTP test code.
Diffstat (limited to 'tests')
-rw-r--r--tests/http/README.md5
-rw-r--r--tests/http/agent.js224
-rw-r--r--tests/http/package.json16
-rw-r--r--tests/http/server.js48
4 files changed, 293 insertions, 0 deletions
diff --git a/tests/http/README.md b/tests/http/README.md
new file mode 100644
index 00000000..ae7f08f1
--- /dev/null
+++ b/tests/http/README.md
@@ -0,0 +1,5 @@
+HTTP one-to-all test
+======
+
+This code can be deployed across a large number of VMs or containers to test and benchmark HTTP traffic within a virtual network at scale. The agent acts as a server and can query other agents, while the server collects agent data and tells agents about each other. It's designed to use RFC4193-based ZeroTier IPv6 addresses within the cluster, which allows the easy provisioning of a large cluster without IP conflicts.
+
diff --git a/tests/http/agent.js b/tests/http/agent.js
new file mode 100644
index 00000000..14964d87
--- /dev/null
+++ b/tests/http/agent.js
@@ -0,0 +1,224 @@
+// ---------------------------------------------------------------------------
+// Customizable parameters:
+
+// How frequently in ms to run tests
+//var RUN_TEST_EVERY = (60 * 5 * 1000);
+var RUN_TEST_EVERY = 1000;
+
+// Maximum test duration in milliseconds (must be less than RUN_TEST_EVERY)
+var TEST_DURATION = (60 * 1000);
+
+// Where should I contact to register and query a list of other nodes?
+var SERVER_HOST = '127.0.0.1';
+var SERVER_PORT = 18080;
+
+// Which port should agents use for their HTTP?
+var AGENT_PORT = 18888;
+
+// Payload size in bytes
+var PAYLOAD_SIZE = 4096;
+
+// ---------------------------------------------------------------------------
+
+var ipaddr = require('ipaddr.js');
+var os = require('os');
+var http = require('http');
+var async = require('async');
+
+var express = require('express');
+var app = express();
+
+// Find our ZeroTier-assigned RFC4193 IPv6 address
+var thisAgentId = null;
+var interfaces = os.networkInterfaces();
+if (!interfaces) {
+ console.error('FATAL: os.networkInterfaces() failed.');
+ process.exit(1);
+}
+for(var ifname in interfaces) {
+ var ifaddrs = interfaces[ifname];
+ if (Array.isArray(ifaddrs)) {
+ for(var i=0;i<ifaddrs.length;++i) {
+ if (ifaddrs[i].family == 'IPv6') {
+ try {
+ var ipbytes = ipaddr.parse(ifaddrs[i].address).toByteArray();
+ if ((ipbytes.length === 16)&&(ipbytes[0] == 0xfd)&&(ipbytes[9] == 0x99)&&(ipbytes[10] == 0x93)) {
+ thisAgentId = '';
+ for(var j=0;j<16;++j) {
+ var tmp = ipbytes[j].toString(16);
+ if (tmp.length === 1)
+ thisAgentId += '0';
+ thisAgentId += tmp;
+ }
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ }
+ }
+}
+if (thisAgentId === null) {
+ console.error('FATAL: no ZeroTier-assigned RFC4193 IPv6 addresses found on any local interface!');
+ process.exit(1);
+}
+
+//console.log(thisAgentId);
+
+// Create a random (and therefore not very compressable) payload
+var payload = '';
+while (payload.length < PAYLOAD_SIZE) {
+ payload += String.fromCharCode(Math.round(Math.random() * 255.0));
+}
+
+// Incremented for each test
+var testCounter = 0;
+
+function registerAndGetPeers(callback)
+{
+ http.get({
+ host: SERVER_HOST,
+ port: SERVER_PORT,
+ path: '/'+thisAgentId
+ },function(res) {
+ var body = '';
+ res.on('data',function(chunk) { body += chunk.toString(); });
+ res.on('end',function() {
+ try {
+ var peers = JSON.parse(body);
+ if (Array.isArray(peers))
+ return callback(null,peers);
+ else return callback(new Error('invalid JSON response from server'),null);
+ } catch (e) {
+ return callback(new Error('invalid JSON response from server'),null);
+ }
+ });
+ }).on('error',function(e) {
+ return callback(e,null);
+ });
+};
+
+function performTestOnAllPeers(peers,callback)
+{
+ var allResults = {};
+ var timedOut = false;
+ var endOfTestTimer = setTimeout(function() {
+ timedOut = true;
+ return callback(allResults);
+ },TEST_DURATION);
+ var testStartTime = Date.now();
+
+ async.each(peers,function(peer,next) {
+ if (timedOut)
+ return next(null);
+ if (peer.length !== 32)
+ return next(null);
+
+ var connectionStartTime = Date.now();
+ allResults[peer] = {
+ testStart: testStartTime,
+ start: connectionStartTime,
+ end: null,
+ error: null,
+ bytes: 0,
+ test: testCounter
+ };
+
+ var peerHost = '';
+ peerHost += peer.substr(0,4);
+ peerHost += ':';
+ peerHost += peer.substr(4,4);
+ peerHost += ':';
+ peerHost += peer.substr(8,4);
+ peerHost += ':';
+ peerHost += peer.substr(12,4);
+ peerHost += ':';
+ peerHost += peer.substr(16,4);
+ peerHost += ':';
+ peerHost += peer.substr(20,4);
+ peerHost += ':';
+ peerHost += peer.substr(24,4);
+ peerHost += ':';
+ peerHost += peer.substr(28,4);
+
+ http.get({
+ host: peerHost,
+ port: AGENT_PORT,
+ path: '/'
+ },function(res) {
+ var bytes = 0;
+ res.on('data',function(chunk) { bytes += chunk.length; });
+ res.on('end',function() {
+ if (timedOut)
+ return next(null);
+ allResults[peer] = {
+ testStart: testStartTime,
+ start: connectionStartTime,
+ end: Date.now(),
+ error: null,
+ bytes: bytes,
+ test: testCounter
+ };
+ return next(null);
+ });
+ }).on('error',function(e) {
+ if (timedOut)
+ return next(null);
+ allResults[peer] = {
+ testStart: testStartTime,
+ start: connectionStartTime,
+ end: Date.now(),
+ error: e.toString(),
+ bytes: 0,
+ test: testCounter
+ };
+ return next(null);
+ });
+ },function(err) {
+ if (!timedOut) {
+ clearTimeout(endOfTestTimer);
+ return callback(allResults);
+ }
+ });
+};
+
+// Agents just serve up a test payload
+app.get('/',function(req,res) {
+ return res.status(200).send(payload);
+});
+
+var expressServer = app.listen(AGENT_PORT,function () {
+ registerAndGetPeers(function(err,peers) {
+ if (err) {
+ console.error('FATAL: unable to contact or query server: '+err.toString());
+ process.exit(1);
+ }
+
+ setInterval(function() {
+ ++testCounter;
+
+ registerAndGetPeers(function(err,peers) {
+ if (err) {
+ console.error('WARNING: unable to contact or query server, test aborted: '+err.toString());
+ return;
+ }
+
+ performTestOnAllPeers(peers,function(results) {
+ console.log(results);
+
+ var submit = http.request({
+ host: SERVER_HOST,
+ port: SERVER_PORT,
+ path: '/'+thisAgentId,
+ method: 'POST'
+ },function(res) {
+ }).on('error',function(e) {
+ console.error('WARNING: unable to submit results to server: '+err.toString());
+ });
+ submit.write(JSON.stringify(results));
+ submit.end();
+ });
+ });
+ },RUN_TEST_EVERY);
+ });
+});
diff --git a/tests/http/package.json b/tests/http/package.json
new file mode 100644
index 00000000..173a6f99
--- /dev/null
+++ b/tests/http/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "zerotier-test-http",
+ "version": "1.0.0",
+ "description": "ZeroTier in-network HTTP test",
+ "main": "agent.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "ZeroTier, Inc.",
+ "license": "GPL-3.0",
+ "dependencies": {
+ "async": "^1.5.0",
+ "express": "^4.13.3",
+ "ipaddr.js": "^1.0.3"
+ }
+}
diff --git a/tests/http/server.js b/tests/http/server.js
new file mode 100644
index 00000000..221dcda9
--- /dev/null
+++ b/tests/http/server.js
@@ -0,0 +1,48 @@
+// ---------------------------------------------------------------------------
+// Customizable parameters:
+
+var SERVER_PORT = 18080;
+
+// ---------------------------------------------------------------------------
+
+var express = require('express');
+var app = express();
+
+app.use(function(req,res,next) {
+ req.rawBody = '';
+ req.on('data', function(chunk) { req.rawBody += chunk.toString(); });
+ req.on('end', function() { return next(); });
+});
+
+var knownAgents = {};
+
+app.get('/:agentId',function(req,res) {
+ var agentId = req.params.agentId;
+ if ((!agentId)||(agentId.length !== 32))
+ return res.status(404).send('');
+ knownAgents[agentId] = Date.now();
+ return res.status(200).send(JSON.stringify(Object.keys(knownAgents)));
+});
+
+app.post('/:agentId',function(req,res) {
+ var agentId = req.params.agentId;
+ if ((!agentId)||(agentId.length !== 32))
+ return res.status(404).send('');
+ var resultData = null;
+ try {
+ resultData = JSON.parse(req.rawBody);
+ } catch (e) {
+ resultData = req.rawBody;
+ }
+ result = {
+ agentId: agentId,
+ result: resultData
+ };
+ console.log(result);
+ return res.status(200).send('');
+});
+
+var expressServer = app.listen(SERVER_PORT,function () {
+ console.log('LISTENING ON '+SERVER_PORT);
+ console.log('');
+});