From b65fa27ba863dd106996813119e7c070033d0267 Mon Sep 17 00:00:00 2001 From: Zachary Boyd Date: Sun, 9 Sep 2018 15:42:34 -0400 Subject: [PATCH] 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 --- .dockerignore | 3 +- .gitignore | 4 +- .npmignore | 3 +- CHANGELOG.md | 6 ++- README.md | 2 +- package.json | 2 +- src/ControlServer.js | 38 ++++++++++-------- src/DNSServer.js | 22 +++++++++++ src/HTTPServer.js | 25 +++++++++--- src/SOCKSServer.js | 17 ++++++++- src/TorPool.js | 31 +++++++++++---- src/TorProcess.js | 2 +- src/launch.js | 7 ++-- test/ControlServer.js | 17 ++++----- test/DNSServer.js | 13 ++++--- test/HTTPServer.js | 12 +++--- test/{RPCServer.js => RPCInterface.js} | 45 ++++++++++++---------- test/SOCKSServer.js | 10 ++--- test/TorPool.js | 53 +++++++++++++++++--------- test/TorProcess.js | 4 +- test/index.js | 1 + 21 files changed, 208 insertions(+), 109 deletions(-) rename test/{RPCServer.js => RPCInterface.js} (91%) diff --git a/.dockerignore b/.dockerignore index 2ea33b4..fb2fd99 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,4 +5,5 @@ npm-debug.log docker-compose.yml .env README.md -Jenkinsfile \ No newline at end of file +.vscode +.DS_Store \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8e480e4..a78ebe3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules npm-debug.log -.env \ No newline at end of file +.env +.vscode +.DS_Store \ No newline at end of file diff --git a/.npmignore b/.npmignore index 90e2a80..a78ebe3 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,5 @@ node_modules npm-debug.log .env -Jenkinsfile \ No newline at end of file +.vscode +.DS_Store \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e327189..a09eae5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/README.md b/README.md index f82a4e3..2ffd5b6 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/package.json b/package.json index 8fefe89..58abe16 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/src/ControlServer.js b/src/ControlServer.js index 728e958..a81b9de 100644 --- a/src/ControlServer.js +++ b/src/ControlServer.js @@ -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; } diff --git a/src/DNSServer.js b/src/DNSServer.js index 6c7301d..18a4c07 100644 --- a/src/DNSServer.js +++ b/src/DNSServer.js @@ -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'); diff --git a/src/HTTPServer.js b/src/HTTPServer.js index a06696b..bfbdce2 100644 --- a/src/HTTPServer.js +++ b/src/HTTPServer.js @@ -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; } diff --git a/src/SOCKSServer.js b/src/SOCKSServer.js index 85b7268..eed0d47 100644 --- a/src/SOCKSServer.js +++ b/src/SOCKSServer.js @@ -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); } }; diff --git a/src/TorPool.js b/src/TorPool.js index e776221..8f7146c 100644 --- a/src/TorPool.js +++ b/src/TorPool.js @@ -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) { diff --git a/src/TorProcess.js b/src/TorProcess.js index ca7cc9b..ea0e006 100644 --- a/src/TorProcess.js +++ b/src/TorProcess.js @@ -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'], diff --git a/src/launch.js b/src/launch.js index d7d4d3d..aeda8de 100644 --- a/src/launch.js +++ b/src/launch.js @@ -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`)); diff --git a/test/ControlServer.js b/test/ControlServer.js index 10db111..81c7826 100644 --- a/test/ControlServer.js +++ b/test/ControlServer.js @@ -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'); \ No newline at end of file +}); \ No newline at end of file diff --git a/test/DNSServer.js b/test/DNSServer.js index 8461708..5beadf3 100644 --- a/test/DNSServer.js +++ b/test/DNSServer.js @@ -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 () { diff --git a/test/HTTPServer.js b/test/HTTPServer.js index c022663..32370a6 100644 --- a/test/HTTPServer.js +++ b/test/HTTPServer.js @@ -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}`) }); }); }); diff --git a/test/RPCServer.js b/test/RPCInterface.js similarity index 91% rename from test/RPCServer.js rename to test/RPCInterface.js index 96fde2c..8397b62 100644 --- a/test/RPCServer.js +++ b/test/RPCInterface.js @@ -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 () { diff --git a/test/SOCKSServer.js b/test/SOCKSServer.js index 4ee48cf..e26aff3 100644 --- a/test/SOCKSServer.js +++ b/test/SOCKSServer.js @@ -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}`) }); }); }); diff --git a/test/TorPool.js b/test/TorPool.js index a4a8565..e7d5e8e 100644 --- a/test/TorPool.js +++ b/test/TorPool.js @@ -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 () { diff --git a/test/TorProcess.js b/test/TorProcess.js index a191848..3e43e35 100644 --- a/test/TorProcess.js +++ b/test/TorProcess.js @@ -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); diff --git a/test/index.js b/test/index.js index fe25a5f..d309446 100644 --- a/test/index.js +++ b/test/index.js @@ -5,4 +5,5 @@ describe("TorRouter", function () { require('./HTTPServer'); require('./DNSServer'); require('./ControlServer'); + require('./RPCInterface'); }); \ No newline at end of file