mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-14 06:16:35 +00:00
HTTP test code.
This commit is contained in:
parent
0034efafe4
commit
c6a918d996
5
tests/http/README.md
Normal file
5
tests/http/README.md
Normal file
@ -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.
|
||||
|
224
tests/http/agent.js
Normal file
224
tests/http/agent.js
Normal file
@ -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);
|
||||
});
|
||||
});
|
16
tests/http/package.json
Normal file
16
tests/http/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
48
tests/http/server.js
Normal file
48
tests/http/server.js
Normal file
@ -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('');
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user