Breaks the mocha test into individual files so tests can be run independently. Uses Promises in the mocha test. Adds a listen method to all servers

This commit is contained in:
Zachary Boyd 2018-09-09 15:42:34 -04:00
parent 1c29679024
commit b65fa27ba8
21 changed files with 208 additions and 109 deletions

View file

@ -5,4 +5,5 @@ npm-debug.log
docker-compose.yml
.env
README.md
Jenkinsfile
.vscode
.DS_Store

4
.gitignore vendored
View file

@ -1,3 +1,5 @@
node_modules
npm-debug.log
.env
.env
.vscode
.DS_Store

View file

@ -1,4 +1,5 @@
node_modules
npm-debug.log
.env
Jenkinsfile
.vscode
.DS_Store

View file

@ -2,10 +2,14 @@
## [4.0.0] - 2018-09-09
### Added
- All servers (DNS, HTTP, SOCKS and Control) all have a `listen` method which returns a Promise that will resolve when the server is listening.
### Changes
- All methods now return promises instead of accepting callbacks. Methods now take advantage of async/await to increase readability.
- The `logger` argument to the constructor's of all classes is now optional
- The mocha test has been split into individual files
- The `Config` property of instance definitions will now inherit from `TorPool.default_tor_config`.
- The mocha test has been split into individual files all under `test/`
### Removes
- The `new_ips` and `new_ip_at` TorPool and `new_ip` TorProcess have been removed. Use `new_identites`, `new_identity_at` and `new_identity` instead.

View file

@ -41,7 +41,7 @@ For example: `tor-router -j 3 -s 9050` would start the proxy with 3 tor instance
## Testing
Tests are written in mocha and can be found under `test/test.js` and can be run with `npm test`
Tests are written in mocha and can be found under `test/` and can be run with `npm test`
## Configuration

View file

@ -11,7 +11,7 @@
},
"scripts": {
"start": "bin/tor-router -s -d -j 1",
"test": "mocha --exit test/index.js",
"test": "mocha --exit test",
"debug": "node --inspect-brk bin/tor-router"
},
"devDependencies": {

View file

@ -6,7 +6,7 @@ const rpc = require('jrpc2');
class ControlServer {
constructor(logger, nconf) {
this.torPool = new TorPool(nconf.get('torPath'), null, nconf.get('parentDataDirectory'), nconf.get('loadBalanceMethod'), nconf.get('granaxOptions'),logger);
this.torPool = new TorPool(nconf.get('torPath'), (() => nconf.get('torConfig')), nconf.get('parentDataDirectory'), nconf.get('loadBalanceMethod'), nconf.get('granaxOptions'), logger);
this.logger = logger || require('./winston-silent-logger');
this.nconf = nconf;
@ -22,9 +22,9 @@ class ControlServer {
server.expose('queryInstances', (async () => {
if (!this.torPool)
throw new Error('No instances created');
throw new Error('No Tor Pool created');
this.torPool.instances.map(instance_info);
return this.torPool.instances.map(instance_info);
}).bind(this));
server.expose('queryInstanceByName', (async (instance_name) => {
@ -36,7 +36,7 @@ class ControlServer {
if (!instance)
throw new Error(`Instance "${instance_name}"" does not exist`);
return instance_info(i)
return instance_info(instance);
}).bind(this));
server.expose('queryInstanceAt', (async (index) => {
@ -51,9 +51,17 @@ class ControlServer {
return instance_info(this.torPool.instance_at(index));
}).bind(this));
server.expose('createInstances', this.torPool.create.bind(this.torPool));
server.expose('addInstances', this.torPool.add.bind(this.torPool));
server.expose('createInstances', (async (num) => {
let instances = await this.torPool.create(num);
return instances.map(instance_info);
}).bind(this));
server.expose('addInstances', (async (defs) => {
let instances = await this.torPool.create(defs);
return instances.map(instance_info);
}).bind(this));
server.expose('removeInstances', this.torPool.remove.bind(this.torPool));
@ -67,7 +75,7 @@ class ControlServer {
server.expose('newIdentityByName', this.torPool.new_identity_by_name.bind(this.torPool));
server.expose('nextInstance', (async () => this.torPool.next()).bind(this));
server.expose('nextInstance', (async () => instance_info( await this.torPool.next() )).bind(this));
server.expose('closeInstances', (async () => this.torPool.exit()).bind(this));
@ -81,7 +89,7 @@ class ControlServer {
server.expose('setTorConfig', (async (config) => {
await Promise.all(Object.keys(config).map((key) => {
var value = config[key];
let value = config[key];
return this.torPool.set_config_all(key, value);
}));
@ -124,23 +132,23 @@ class ControlServer {
return this.torPool;
}
createSOCKSServer(port) {
async createSOCKSServer(port) {
this.socksServer = new SOCKSServer(this.torPool, this.logger);
this.socksServer.listen(port || 9050);
await this.socksServer.listen(port || 9050);
this.logger.info(`[socks]: Listening on ${port}`);
this.socksServer;
}
createHTTPServer(port) {
async createHTTPServer(port) {
this.httpServer = new HTTPServer(this.torPool, this.logger);
this.httpServer.listen(port || 9080);
await this.httpServer.listen(port || 9080);
this.logger.info(`[http]: Listening on ${port}`);
this.httpServer;
}
createDNSServer(port) {
async createDNSServer(port) {
this.dnsServer = new DNSServer(this.torPool, this.nconf.get('dns:options'), this.nconf.get('dns:timeout'), this.logger);
this.dnsServer.serve(port || 9053);
await this.dnsServer.serve(port || 9053);
this.logger.info(`[dns]: Listening on ${port}`);
this.dnsServer;
}

View file

@ -1,7 +1,29 @@
const dns = require('native-dns');
const { UDPServer } = require('native-dns');
const Promise = require('bluebird');
class DNSServer extends UDPServer {
async listen() {
let args = Array.from(arguments);
let inner_func = super.serve;
if (!args[1])
args[1] = null;
return await new Promise((resolve, reject) => {
args.push(() => {
let args = Array.from(arguments);
resolve.apply(args);
});
try {
inner_func.apply(this, args);
} catch (error) {
reject(error);
}
});
}
constructor(tor_pool, dns_options, dns_timeout, logger) {
super(dns_options);
this.logger = logger || require('./winston-silent-logger');

View file

@ -2,12 +2,25 @@ const http = require('http');
const URL = require('url');
const { Server } = http;
const Promise = require('bluebird');
const socks = require('socksv5');
const SocksProxyAgent = require('socks-proxy-agent');
const TOR_ROUTER_PROXY_AGENT = 'tor-router';
class HTTPServer extends Server {
async listen() {
return await new Promise((resolve, reject) => {
let args = Array.from(arguments);
let inner_func = super.listen;
args.push(() => {
let args = Array.from(arguments);
resolve.apply(args);
});
inner_func.apply(this, args);
});
}
constructor(tor_pool, logger) {
let handle_http_connections = (req, res) => {
let url = URL.parse(req.url);
@ -26,12 +39,12 @@ class HTTPServer extends Server {
req.on('data', onIncomingData);
req.on('end', preConnectClosed);
req.on('error', function (err) {
logger.error("[http-proxy]: an error occured: "+err.message);
this.logger.error("[http-proxy]: an error occured: "+err.message);
});
let connect = (tor_instance) => {
let socks_port = tor_instance.socks_port;
logger.verbose(`[http-proxy]: ${req.connection.remoteAddress}:${req.connection.remotePort} → 127.0.0.1:${socks_port}${url.hostname}:${url.port}`);
this.logger.verbose(`[http-proxy]: ${req.connection.remoteAddress}:${req.connection.remotePort} → 127.0.0.1:${socks_port}${url.hostname}:${url.port}`);
let proxy_req = http.request({
method: req.method,
@ -74,7 +87,7 @@ class HTTPServer extends Server {
if (tor_pool.instances.length) {
connect(tor_pool.next());
} else {
logger.debug(`[http-proxy]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
this.logger.debug(`[http-proxy]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
tor_pool.once('instance_created', connect);
}
};
@ -85,7 +98,7 @@ class HTTPServer extends Server {
let connect = (tor_instance) => {
let socks_port = tor_instance.socks_port;
logger && logger.verbose(`[http-connect]: ${req.connection.remoteAddress}:${req.connection.remotePort} → 127.0.0.1:${socks_port}${tor_instance.definition.Name ? ' ('+tor_instance.definition.Name+')' : '' }${hostname}:${port}`)
this.logger && this.logger.verbose(`[http-connect]: ${req.connection.remoteAddress}:${req.connection.remotePort} → 127.0.0.1:${socks_port}${tor_instance.definition.Name ? ' ('+tor_instance.definition.Name+')' : '' }${hostname}:${port}`)
var outbound_socket;
let onClose = (error) => {
@ -125,14 +138,14 @@ class HTTPServer extends Server {
if (tor_pool.instances.length) {
connect(tor_pool.next());
} else {
logger.debug(`[http-connect]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
this.logger.debug(`[http-connect]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
tor_pool.once('instance_created', connect);
}
};
super(handle_http_connections);
this.on('connect', handle_connect_connections);
this.logger = logger || require('./winston-silent-logger');
this.tor_pool = tor_pool;
}

View file

@ -1,7 +1,20 @@
const socks = require('socksv5');
const Promise = require('bluebird');
const { Server } = socks;
class SOCKSServer extends Server{
async listen() {
return await new Promise((resolve, reject) => {
let args = Array.from(arguments);
let inner_func = super.listen;
args.push(() => {
let args = Array.from(arguments);
resolve.apply(args);
});
inner_func.apply(this, args);
});
}
constructor(tor_pool, logger) {
let handleConnection = (info, accept, deny) => {
let inbound_socket = accept(true);
@ -28,7 +41,7 @@ class SOCKSServer extends Server{
let connect = (tor_instance) => {
let socks_port = tor_instance.socks_port;
logger.verbose(`[socks]: ${info.srcAddr}:${info.srcPort} → 127.0.0.1:${socks_port}${tor_instance.definition.Name ? ' ('+tor_instance.definition.Name+')' : '' }${info.dstAddr}:${info.dstPort}`)
this.logger.verbose(`[socks]: ${info.srcAddr}:${info.srcPort} → 127.0.0.1:${socks_port}${tor_instance.definition.Name ? ' ('+tor_instance.definition.Name+')' : '' }${info.dstAddr}:${info.dstPort}`)
socks.connect({
host: info.dstAddr,
@ -60,7 +73,7 @@ class SOCKSServer extends Server{
if (tor_pool.instances.length) {
connect(tor_pool.next());
} else {
logger.debug(`[socks]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
this.logger.debug(`[socks]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
tor_pool.once('instance_created', connect);
}
};

View file

@ -29,20 +29,33 @@ const WeightedList = require('js-weighted-list');
const TorProcess = require('./TorProcess');
Promise.promisifyAll(fs);
class TorPool extends EventEmitter {
constructor(tor_path, default_config, data_directory, load_balance_method, granax_options, logger) {
if (!data_directory)
throw new Error('Invalid "data_directory"');
super();
this._instances = [];
default_config = _.extend({}, (default_config || {}));
this.default_tor_config = default_config;
this._default_tor_config = default_config;
this.data_directory = data_directory;
this.load_balance_method = load_balance_method;
!fs.existsSync(this.data_directory) && fs.mkdirSync(this.data_directory);
this.tor_path = tor_path;
this.logger = logger || require('./winston-silent-logger');
this.granax_options = granax_options;
}
get default_tor_config() {
if (typeof(this._default_tor_config) === 'function')
return this._default_tor_config();
else if (this._default_tor_config)
return _.cloneDeep(this._default_tor_config);
else
return {};
}
set default_tor_config(value) { this._default_tor_config = value; }
static get load_balance_methods() {
return {
round_robin: function (instances) {
@ -68,9 +81,11 @@ class TorPool extends EventEmitter {
}
async create_instance(instance_definition) {
if (!(fs.existsSync(this.data_directory)))
await fs.mkdirAsync(this.data_directory);
this._instances._weighted_list = void(0);
if (!instance_definition.Config)
instance_definition.Config = _.extend({}, this.default_tor_config);
instance_definition.Config = _.extend(_.cloneDeep(this.default_tor_config), (instance_definition.Config || {}));
let instance_id = nanoid();
instance_definition.Config.DataDirectory = instance_definition.Config.DataDirectory || path.join(this.data_directory, (instance_definition.Name || instance_id));
@ -138,7 +153,7 @@ class TorPool extends EventEmitter {
}
next() {
this._instances = load_balance_methods[this.load_balance_method](this._instances);
this._instances = TorPool.load_balance_methods[this.load_balance_method](this._instances);
return this.instances[0];
}
@ -148,7 +163,7 @@ class TorPool extends EventEmitter {
}
async new_identites() {
await Promise.all(this.instances.map((instance) => instance.new_identity(next)));
await Promise.all(this.instances.map((instance) => instance.new_identity()));
}
async new_identity_at(index) {
@ -201,7 +216,7 @@ class TorPool extends EventEmitter {
}
async signal_all(signal) {
await Promise.all(this.instances.map((instance) => instance.signal(signal, next)));
await Promise.all(this.instances.map((instance) => instance.signal(signal)));
}
async signal_by_name(name, signal) {

View file

@ -112,7 +112,7 @@ class TorProcess extends EventEmitter {
let configFile = await temp.openAsync('tor-router');
let configPath = configFile.path;
fs.writeFileAsync(configPath, text);
await fs.writeFileAsync(configPath, text);
let tor = spawn(this.tor_path, ['-f', configPath], {
stdio: ['ignore', 'pipe', 'pipe'],

View file

@ -24,6 +24,7 @@ async function main(nconf, logger) {
let control = new ControlServer(logger, nconf);
try {
await control.listen(control_port);
if (socks_port) {
if (typeof(socks_port) === 'boolean') {
@ -50,13 +51,11 @@ async function main(nconf, logger) {
}
if (instances) {
logger.info(`[tor]: starting ${Array.isArray(instances) ? instances.length : instances} tor instances...`)
logger.info(`[tor]: starting ${Array.isArray(instances) ? instances.length : instances} tor instance(s)...`)
await control.torPool.create(instances);
logger.info('[tor]: tor started');
}
await control.listen(control_port);
logger.info(`[control]: control Server listening on ${control_port}`);
} catch (error) {
logger.error(`[global]: error starting application: ${error.stack}`);
@ -160,6 +159,8 @@ nconf
let nconf_config = nconf.get('config');
if (nconf_config) {
nconf.file(nconf_config);
} else {
nconf.use('memory');
}
nconf.defaults(require(`${__dirname}/../src/default_config.js`));

View file

@ -1,18 +1,17 @@
const _ = require('lodash');
const assert = require('chai').assert;
const rpc = require('jrpc2');
const Promise = require('bluebird');
const nconf = require('nconf');
const getPort = require('get-port');
const logger = require('../src/winston-silent-logger');
nconf.use('memory');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
const { ControlServer } = require('../');
const { ControlServer, TorPool, HTTPServer, SOCKSServer, DNSServer } = require('../');
let controlServer = new ControlServer(logger, nconf);
let controlServer = new ControlServer(null, nconf);
let controlPort;
describe('ControlServer', function () {
describe('#listen(port)', function () {
it('should bind to a given port', async function () {
@ -24,7 +23,7 @@ describe('ControlServer', function () {
it('should create a TorPool with a given configuration', function () {
let torPool = controlServer.createTorPool({ ProtocolWarnings: 1 });
assert.ok((controlServer.torPool instanceof (TorRouter.TorPool)));
assert.instanceOf(controlServer.torPool, TorPool);
assert.equal(1, torPool.default_tor_config.ProtocolWarnings);
});
});
@ -59,6 +58,4 @@ describe('ControlServer', function () {
after('shutdown tor pool', async function () {
await controlServer.torPool.exit();
});
});
require('./RPCServer');
});

View file

@ -3,15 +3,18 @@ const nconf = require('nconf');
const getPort = require('get-port');
const dns = require('native-dns');
const logger = require('../src/winston-silent-logger');
const { TorPool, DNSServer } = require('../');
const { WAIT_FOR_CREATE } = require('./constants');
nconf.use('memory');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
let dnsServerTorPool;
let dnsServer;
describe('DNSServer', function () {
dnsServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
dnsServer = new DNSServer(dnsServerTorPool, {}, 10000, logger);
dnsServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null);
dnsServer = new DNSServer(dnsServerTorPool, {}, 10000);
let dnsPort;
before('start up server', async function (){
this.timeout(WAIT_FOR_CREATE);
@ -19,7 +22,7 @@ describe('DNSServer', function () {
await dnsServerTorPool.create(1);
dnsPort = await getPort();
dnsServer.serve(dnsPort);
await dnsServer.listen(dnsPort);
});
describe('#handle_dns_request(req, res)', function () {
@ -32,7 +35,7 @@ describe('DNSServer', function () {
type: 'A'
}),
server: { address: '127.0.0.1', port: dnsPort, type: 'udp' },
timeout: 1000,
timeout: 10000,
});
req.on('timeout', function () {

View file

@ -3,18 +3,18 @@ const request = require('request-promise');
const getPort = require('get-port');
const ProxyAgent = require('proxy-agent');
const logger = require('../src/winston-silent-logger');
const { TorPool, HTTPServer } = require('../');
const { WAIT_FOR_CREATE, PAGE_LOAD_TIME } = require('./constants');
nconf.use('memory');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
let httpServerTorPool;
let httpServer;
describe('HTTPServer', function () {
httpServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
httpServer = new HTTPServer(httpServerTorPool, logger);
httpServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null);
httpServer = new HTTPServer(httpServerTorPool);
let httpPort;
before('start up server', async function (){
this.timeout(WAIT_FOR_CREATE);
@ -22,7 +22,7 @@ describe('HTTPServer', function () {
await httpServerTorPool.create(1);
httpPort = await getPort();
httpServer.listen(httpPort);
await httpServer.listen(httpPort);
});
describe('#handle_http_connections(req, res)', function () {
@ -31,7 +31,7 @@ describe('HTTPServer', function () {
await request({
url: 'http://example.com',
agent: new ProxyAgent(`http://localhost:${httpPort}`)
agent: new ProxyAgent(`http://127.0.0.1:${httpPort}`)
});
});
});
@ -42,7 +42,7 @@ describe('HTTPServer', function () {
await request({
url: 'https://example.com',
agent: new ProxyAgent(`http://localhost:${httpPort}`)
agent: new ProxyAgent(`http://127.0.0.1:${httpPort}`)
});
});
});

View file

@ -1,21 +1,21 @@
const _ = require('lodash');
const assert = require('chai').assert;
const rpc = require('jrpc2');
const Promise = require('bluebird');
const nconf = require('nconf');
const rpc = require('jrpc2');
const getPort = require('get-port');
const logger = require('../src/winston-silent-logger');
nconf.use('memory');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
const { ControlServer } = require('../');
const { WAIT_FOR_CREATE } = require('./constants');
let rpcControlServer = new ControlServer(logger, nconf);
let rpcControlServer = new ControlServer(null, nconf);
let rpcControlPort;
let rpcClient;
describe('ControlServer - RPC', function () {
describe('ControlServer - RPC Interface', function () {
before('setup control server', async function () {
rpcControlPort = await getPort();
await rpcControlServer.listen(rpcControlPort);
@ -35,11 +35,11 @@ describe('ControlServer - RPC', function () {
it('should return a list of instances', async function () {
let raw = await rpcClient.invokeAsync('queryInstances', []);
var instances = JSON.parse(raw).result;
let instances = JSON.parse(raw).result;
assert.isArray(instances, 'Did not return an array');
assert.isNotEmpty(instances);
assert.isTrue(instances.every((instance) => ( typeof(instance.name) !== 'undefined' ) && ( instance.name !== null )));
assert.isNotEmpty(instances, 'Returned an empty array');
assert.isTrue(instances.every((instance) => ( typeof(instance.name) !== 'undefined' ) && ( instance.name !== null )), 'Objects were not valid');
});
});
@ -62,7 +62,7 @@ describe('ControlServer - RPC', function () {
it('should return a single instance by name', async function () {
let raw = await rpcClient.invokeAsync('queryInstanceByName', ['instance-1']);
var instance = JSON.parse(raw).result;
let instance = JSON.parse(raw).result;
assert.isOk(instance);
});
@ -73,7 +73,7 @@ describe('ControlServer - RPC', function () {
it('should return a single instance by index', async function () {
let raw = await rpcClient.invokeAsync('queryInstanceAt', [0]);
var instance = JSON.parse(raw).result;
let instance = JSON.parse(raw).result;
assert.isOk(instance);
});
@ -132,9 +132,10 @@ describe('ControlServer - RPC', function () {
this.timeout(WAIT_FOR_CREATE);
await rpcControlServer.torPool.create_instance({ Name: 'config-test' });
let value = await rpcControlServer.torPool.instance_by_name('config-test').get_config('TestSocks');
let values = await rpcControlServer.torPool.instance_by_name('config-test').get_config('TestSocks');
assert.equal(value, 1);
assert.isNotEmpty(values);
assert.equal(values[0], "1");
});
after('remove instance', async function () {
@ -150,8 +151,8 @@ describe('ControlServer - RPC', function () {
});
it('should return a tor config with a modified property', async function () {
this.timeout(3000);
let raw = await rpcClient.invokeAsync('getDefaultTorConfig', [ { } ]);
this.timeout(6000);
let raw = await rpcClient.invokeAsync('getDefaultTorConfig', [ ]);
let config = JSON.parse(raw).result;
assert.equal(config.TestSocks, 1);
@ -198,11 +199,12 @@ describe('ControlServer - RPC', function () {
await rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 1);
});
it('should retrieve the property from the tor instance', async function (done) {
let raw = await rpcClient.invokeAsync('getInstanceConfigByName', ['instance-1']);
let value = JSON.parse(raw).result;
it('should retrieve the property from the tor instance', async function () {
let raw = await rpcClient.invokeAsync('getInstanceConfigByName', ['instance-1', "TestSocks"]);
let values = JSON.parse(raw).result;
assert.equal(value, 1);
assert.isNotEmpty(values);
assert.equal(values[0], "1");
});
after('unset config property', async function () {
@ -218,10 +220,11 @@ describe('ControlServer - RPC', function () {
});
it('should retrieve the property from the tor instance', async function () {
let raw = await rpcClient.invokeAsync('getInstanceConfigByName', [0]);
let value = JSON.parse(raw).result;
let raw = await rpcClient.invokeAsync('getInstanceConfigAt', [0, "TestSocks"]);
let values = JSON.parse(raw).result;
assert.equal(value, 1);
assert.isNotEmpty(values);
assert.equal(values[0], "1");
});
after('unset config property', async function () {

View file

@ -3,18 +3,18 @@ const request = require('request-promise');
const getPort = require('get-port');
const ProxyAgent = require('proxy-agent');
const logger = require('../src/winston-silent-logger');
const { TorPool, SOCKSServer } = require('../');
const { WAIT_FOR_CREATE, PAGE_LOAD_TIME } = require('./constants');
nconf.use('memory');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
let socksServerTorPool;
let socksServer;
describe('SOCKSServer', function () {
socksServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
socksServer = new SOCKSServer(socksServerTorPool, logger);
socksServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null);
socksServer = new SOCKSServer(socksServerTorPool);
let socksPort;
before('start up server', async function (){
this.timeout(WAIT_FOR_CREATE);
@ -22,7 +22,7 @@ describe('SOCKSServer', function () {
await socksServerTorPool.create(1);
socksPort = await getPort();
socksServer.listen(socksPort);
await socksServer.listen(socksPort);
});
describe('#handleConnection(socket)', function () {
@ -31,7 +31,7 @@ describe('SOCKSServer', function () {
await request({
url: 'http://example.com',
agent: new ProxyAgent(`socks://localhost:${socksPort}`)
agent: new ProxyAgent(`socks://127.0.0.1:${socksPort}`)
});
});
});

View file

@ -5,14 +5,13 @@ const _ = require('lodash');
const { TorPool } = require('../');
const { WAIT_FOR_CREATE } = require('./constants');
const logger = require('../src/winston-silent-logger');
nconf.use('memory');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
let torPool;
describe('TorPool', function () {
torPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
const torPoolFactory = () => new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null);
describe('#create_instance(instance_defintion)', function () {
let instance_defintion = {
@ -22,6 +21,9 @@ describe('TorPool', function () {
}
};
let torPool;
before('create tor pool', () => { torPool = torPoolFactory(); })
it('should create one tor instance based on the provided definition', async function () {
this.timeout(WAIT_FOR_CREATE);
await torPool.create_instance(instance_defintion);
@ -51,9 +53,12 @@ describe('TorPool', function () {
{ Name: 'instance-2', Config: { ProtocolWarnings: 1 } }
];
let torPool;
before('create tor pool', () => { torPool = torPoolFactory(); })
it('should create instances from several instance definitions', async function () {
this.timeout(WAIT_FOR_CREATE*2);
await torPool.add(instance_defintions)
await torPool.add(_.cloneDeep(instance_defintions))
});
it('2 instances should exist in the pool', function () {
@ -61,19 +66,21 @@ describe('TorPool', function () {
});
it('the created instances should have the same defintion properties as the input definitions', function () {
assert.deepEqual(instance_defintions, torPool.instances.map((instance) => {
let live_instance_definitions = torPool.instances.map((instance) => {
let def_clone = _.cloneDeep(instance.definition);
delete def_clone.Config.DataDirectory;
return def_clone;
}).sort(function(a,b) {return (a.Name > b.Name) ? 1 : ((b.Name > a.Name) ? -1 : 0);}));
}).sort((a,b) => (a.Name > b.Name) ? 1 : ((b.Name > a.Name) ? -1 : 0));
assert.deepEqual(instance_defintions, live_instance_definitions);
});
it('the created instances should have the same config properties specified in the definiton', async function (done) {
it('the created instances should have the same config properties specified in the definiton', async function () {
this.timeout(10000);
let values = await Promise.all(torPool.instances.map((instance) => instance.get_config('ProtocolWarnings')));
assert.isTrue( values.every((value) => value === 1) );
values = _.flatten(values);
assert.isTrue( values.every((value) => value === "1") );
});
after('shutdown tor pool', async function () {
@ -82,7 +89,13 @@ describe('TorPool', function () {
});
describe('#create(number_of_instances)', function () {
torPool.default_tor_config = { TestSocks: 1 };
let torPool;
before('create tor pool', () => {
torPool = torPoolFactory();
torPool.default_tor_config = { TestSocks: 1 };
})
it('should create 2 instances with the default config', async function () {
this.timeout(WAIT_FOR_CREATE*2);
await torPool.create(2);
@ -95,19 +108,21 @@ describe('TorPool', function () {
it('the created instances should have the same config properties specified in the default config', async function () {
this.timeout(10000);
let values = await Promise.all(torPool.instances.map((instance) => instance.get_config('ProtocolWarnings')));
assert.isTrue( values.every((value) => value === 1) );
let values = await Promise.all(torPool.instances.map((instance) => instance.get_config('TestSocks')));
values = _.flatten(values);
assert.isTrue( values.every((value) => value === "1") );
});
after('shutdown tor pool', async function () {
torPool.default_tor_config = {};
await torPool.exit(done);
await torPool.exit();
});
});
let torPool;
describe('#next()', function () {
before('create tor pool', () => { torPool = torPoolFactory(); })
before('create tor instances', async function () {
this.timeout(WAIT_FOR_CREATE * 3);
await torPool.add([
@ -127,8 +142,8 @@ describe('TorPool', function () {
});
it('result of next should be different if run twice', function () {
var t1 = torPool.next().instance_name;
var t2 = torPool.next().instance_name;
let t1 = torPool.next().instance_name;
let t2 = torPool.next().instance_name;
assert.notEqual(t1, t2);
});
});
@ -192,8 +207,8 @@ describe('TorPool', function () {
this.timeout(5000);
let values = await Promise.all(torPool.instances.map((instance) => instance.get_config('TestSocks')));
assert.isTrue( values.every((value) => value === 1) );
values = _.flatten(values);
assert.isTrue( values.every((value) => value === "1") );
});
after('unset config options', async function () {

View file

@ -3,13 +3,13 @@ const assert = require('chai').assert;
const { TorProcess } = require('../');
const { WAIT_FOR_CREATE } = require('./constants');
const logger = require('../src/winston-silent-logger');
nconf.use('memory');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
describe('TorProcess', function () {
let tor = new TorProcess(nconf.get('torPath'), { DataDirectory: nconf.get('parentDataDirectory'), ProtocolWarnings: 0 }, null, logger);
let tor = new TorProcess(nconf.get('torPath'), { DataDirectory: nconf.get('parentDataDirectory'), ProtocolWarnings: 0 }, null);
describe('#create()', function () {
this.timeout(WAIT_FOR_CREATE);

View file

@ -5,4 +5,5 @@ describe("TorRouter", function () {
require('./HTTPServer');
require('./DNSServer');
require('./ControlServer');
require('./RPCInterface');
});