123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- const _ = require('lodash');
- const assert = require('chai').assert;
- const Promise = require('bluebird');
- const { Provider } = require('nconf');
- const nconf = new Provider();
- const rpc = require('jrpc2');
- const getPort = require('get-port');
- const temp = require('temp');
- const fs = require('fs');
- 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');
- Promise.promisifyAll(fs);
- Promise.promisifyAll(temp);
- let rpcControlServer = new ControlServer(nconf);
- let rpcControlPort;
- let rpcClient;
- describe('ControlServer - RPC Interface', function () {
- before('setup control server', async function () {
- rpcControlPort = await getPort();
- await rpcControlServer.listen(rpcControlPort);
- rpcClient = new rpc.Client(new rpc.tcpTransport({ port: rpcControlPort, hostname: 'localhost' }));
- Promise.promisifyAll(rpcClient);
- });
- describe('#createInstances(number_of_instances)', function () {
- this.timeout(WAIT_FOR_CREATE*2);
- it('should create an instance', async function () {
- await rpcClient.invokeAsync('createInstances', [{ Name: 'instance-1', Group: "foo" }]);
- });
- });
- describe('#queryInstanceNames()', function () {
- it("should have an instance named \"instance-1\"", async function () {
- let raw = await rpcClient.invokeAsync('queryInstanceNames', [ ]);
- let instances = JSON.parse(raw).result;
- assert.deepEqual(instances, [ 'instance-1' ]);
- });
- });
- describe('#queryGroupNames()', function () {
- it("should have a group named \"foo\"", async function () {
- let raw = await rpcClient.invokeAsync('queryGroupNames', [ ]);
- let groups = JSON.parse(raw).result;
- assert.deepEqual(groups, [ 'foo' ]);
- });
- });
- describe('#queryInstancesByGroup()', function () {
- it("should return an instance named \"instance-1\"", async function () {
- let raw = await rpcClient.invokeAsync('queryInstancesByGroup', [ 'foo' ]);
- let instances = JSON.parse(raw).result;
- assert.equal(instances.length, 1);
- assert.ok(instances[0]);
- assert.equal(instances[0].name, 'instance-1');
- });
- });
- describe('#queryInstances()', function () {
- this.timeout(3000);
- it('should return a list of instances', async function () {
- let raw = await rpcClient.invokeAsync('queryInstances', []);
- let instances = JSON.parse(raw).result;
- assert.isArray(instances, 'Did not return an array');
- assert.isNotEmpty(instances, 'Returned an empty array');
- assert.isTrue(instances.every((instance) => ( typeof(instance.name) !== 'undefined' ) && ( instance.name !== null )), 'Objects were not valid');
- });
- });
- describe('#addInstances(definitions)', function () {
- this.timeout(WAIT_FOR_CREATE);
- it("should add an instance based on a defintion", async function () {
- let def = {
- Name: 'instance-2',
- Group: 'bar'
- };
- await rpcClient.invokeAsync('addInstances', [ def ]);
- });
- it("tor pool should now contain and instance that has the same name as the name specified in the defintion", function () {
- assert.ok(rpcControlServer.tor_pool.instance_by_name('instance-2'));
- });
- });
- describe('#queryInstanceByName(instance_name)', function () {
- this.timeout(3000);
- it('should return a single instance by name', async function () {
- let raw = await rpcClient.invokeAsync('queryInstanceByName', ['instance-1']);
-
- let instance = JSON.parse(raw).result;
-
- assert.isOk(instance);
- });
- });
- describe('#queryInstanceAt(index)', function () {
- this.timeout(3000);
- it('should return a single instance by index', async function () {
- let raw = await rpcClient.invokeAsync('queryInstanceAt', [0]);
-
- let instance = JSON.parse(raw).result;
-
- assert.isOk(instance);
- });
- });
- describe('#addInstanceToGroupByName()', function () {
- it(`should add "instance-1" to baz`, async function () {
- await rpcClient.invokeAsync('addInstanceToGroupByName', [ 'baz', "instance-1" ]);
- });
- it('"instance-1" should be added to "baz"', function () {
- assert.include(rpcControlServer.tor_pool.instances_by_group('baz').map((i) => i.instance_name), "instance-1");
- });
- after('remove from group', function () {
- rpcControlServer.tor_pool.groups['baz'].remove_by_name('instance-1');
- });
- });
- describe('#addInstanceToGroupAt()', function () {
- it(`should add "instance-1" to baz`, async function () {
- await rpcClient.invokeAsync('addInstanceToGroupAt', [ 'baz', 0 ]);
- });
- it('"instance-1" should be added to "baz"', function () {
- assert.include(rpcControlServer.tor_pool.instances_by_group('baz').map((i) => i.instance_name), "instance-1");
- });
- after('remove from group', function () {
- rpcControlServer.tor_pool.groups['baz'].remove_by_name('instance-1');
- });
- });
- describe('#removeInstanceFromGroupByName()', function () {
- before('add to group', function () {
- rpcControlServer.tor_pool.groups['baz'].add_by_name('instance-1');
- });
- it(`should remove "instance-1" from baz`, async function () {
- await rpcClient.invokeAsync('removeInstanceFromGroupByName', [ 'baz', "instance-1" ]);
- });
- it('"instance-1" should be remove from to "baz"', function () {
- assert.notInclude(rpcControlServer.tor_pool.group_names, "baz");
- });
- });
- describe('#removeInstanceFromGroupAt()', function () {
- before('add to group', function () {
- rpcControlServer.tor_pool.groups['baz'].add_by_name('instance-1');
- });
- it(`should remove "instance-1" from baz`, async function () {
- await rpcClient.invokeAsync('removeInstanceFromGroupAt', [ 'baz', 0 ]);
- });
- it('"instance-1" should be remove from to "baz"', function () {
- assert.notInclude(rpcControlServer.tor_pool.group_names, "baz");
- });
- });
-
- describe('#newIdentites()', function () {
- this.timeout(3000);
- it('should request new identities for all instances', async function () {
- await rpcClient.invokeAsync('newIdentites', []);
- });
- });
- describe('#newIdentityByName(instance_name)', function () {
- this.timeout(3000);
- it('should request new identities for all instances', async function () {
- await rpcClient.invokeAsync('newIdentityByName', ['instance-1']);
- });
- });
- describe('#newIdentityAt(index)', function () {
- this.timeout(3000);
- it('should request new identities for all instances', async function () {
- await rpcClient.invokeAsync('newIdentityAt', [0]);
- });
- });
- describe('#newIdentitiesByGroup()', function () {
- it(`should get new identites for all instances in group`, async function () {
- await rpcClient.invokeAsync('newIdentitiesByGroup', [ 'foo' ]);
- });
- });
- describe("#setTorConfig(config_object)", function () {
- this.timeout(3000);
- it('should set several config variables on all instances', async function () {
- await rpcClient.invokeAsync('setTorConfig', [ { TestSocks: 1, ProtocolWarnings: 1 } ]);
- });
- it('all instances should have the modified variables', async function() {
- await Promise.all(rpcControlServer.tor_pool.instances.map(async (instance) => {
- let var1 = await instance.get_config('TestSocks');
- let var2 = await instance.get_config('ProtocolWarnings');
- assert.equal(var1, 1);
- assert.equal(var2, 1);
- }));
- });
- after('unset config variables', async function () {
- await rpcControlServer.tor_pool.set_config_all('TestSocks', 0);
- await rpcControlServer.tor_pool.set_config_all('ProtocolWarnings', 0);
- });
- });
- describe('#setConfig(key, value)', function () {
- it('should set the default config of new instances', async function () {
- this.timeout(3000);
- await rpcClient.invokeAsync('setConfig', [ 'foo', 'bar' ]);
- });
- it('a new instance should be created with the modified property', function () {
- assert.equal(nconf.get('foo'), 'bar');;
- });
- after('remove instance', function () {
- nconf.reset();
- });
- });
- describe('#setTorConfigByGroup()', function () {
- it(`should set the config value on all instances`, async function () {
- await rpcClient.invokeAsync('setTorConfigByGroup', [ 'foo', { 'ProtocolWarnings': 1 } ]);
- });
- it('all instances should have the config value set', async function () {
- let values = _.flatten(await Promise.all(rpcControlServer.tor_pool.instances_by_group('foo').map((i) => i.get_config('ProtocolWarnings'))));
- assert.isTrue(values.every((v) => v === "1"));
- });
- after('unset config values', async function () {
- rpcControlServer.tor_pool.set_config_by_group('foo', 'ProtocolWarnings', 0);
- });
- });
- describe('#getConfig()', function () {
- before('set a property', function () {
- nconf.set('foo', 'bar');
- });
- it('should return the property that was set', async function () {
- this.timeout(6000);
- let raw = await rpcClient.invokeAsync('getConfig', [ 'foo' ]);
- let value = JSON.parse(raw).result;
- assert.equal(value, 'bar');
- });
- after('unset property', function () {
- nconf.reset();
- });
- });
- describe('#saveConfig()', function () {
- let file_path;
- before('set a property and create temp file', async function () {
- file_path = temp.path({ suffix: '.json' });
- nconf.remove('memory');
- nconf.file({ file: file_path });
- nconf.set('foo', 'bar');
- });
- it('should save the config to the the temp file', async function () {
- this.timeout(6000);
- await rpcClient.invokeAsync('saveConfig', []);
- });
- it('the temp file should contain the property', async function () {
- let tmp_file = await fs.readFileAsync(file_path, 'utf8');
- let tmp_json = JSON.parse(tmp_file);
- assert.equal(tmp_json.foo, 'bar');
- });
- after('unset property and delete file', async function () {
- nconf.remove('file');
- nconf.use('memory');
- nconf.reset();
- await fs.unlinkAsync(file_path);
- });
- });
- describe('#loadConfig()', function () {
- let file;
- before('create temp file with property', async function () {
- file = await temp.openAsync({ suffix: '.json' });
- await fs.writeFileAsync(file.fd, JSON.stringify({ foo: 'bar' }));
- nconf.remove('memory');
- nconf.file({ file: file.path });
- });
- it('should load the config from the the temp file', async function () {
- this.timeout(6000);
- await rpcClient.invokeAsync('loadConfig', []);
- });
- it("the application's config should contain the property", async function () {
- assert.equal(nconf.get('foo'), 'bar');
- });
- after('unset property and delete file', async function () {
- nconf.remove('file');
- nconf.use('memory');
- nconf.reset();
- await fs.unlinkAsync(file.path);
- });
- });
- describe('#getLoadBalanceMethod()', function () {
- this.timeout(3000);
- before(function () {
- rpcControlServer.tor_pool.load_balance_method = 'round_robin';
- });
- it('should return the current load balance method', async function () {
- let raw = await rpcClient.invokeAsync('getLoadBalanceMethod', []);
- let lb_method = JSON.parse(raw).result;
- assert.equal(lb_method, 'round_robin');
- });
- });
- describe('#setLoadBalanceMethod(load_balance_method)', function () {
- this.timeout(3000);
- it('should set the load balance method', async function () {
- await rpcClient.invokeAsync('setLoadBalanceMethod', ['weighted']);
- });
- it('the load balance method should be changed', function () {
- assert.equal(rpcControlServer.tor_pool.load_balance_method, 'weighted');
- });
- after(function () {
- rpcControlServer.tor_pool.load_balance_method = 'round_robin';
- });
- });
- describe("#getInstanceConfigByName(instance_name)", function () {
- this.timeout(3000);
- before('set config property', async function () {
- await rpcControlServer.tor_pool.instance_by_name('instance-1').set_config('TestSocks', 1);
- });
- 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.isNotEmpty(values);
- assert.equal(values[0], "1");
- });
- after('unset config property', async function () {
- await rpcControlServer.tor_pool.instance_by_name('instance-1').set_config('TestSocks', 0);
- });
- });
- describe("#getInstanceConfigAt(index)", function () {
- this.timeout(3000);
- before('set config property', async function () {
- await rpcControlServer.tor_pool.instance_at(0).set_config('TestSocks', 1);
- });
- it('should retrieve the property from the tor instance', async function () {
- let raw = await rpcClient.invokeAsync('getInstanceConfigAt', [0, "TestSocks"]);
- let values = JSON.parse(raw).result;
- assert.isNotEmpty(values);
- assert.equal(values[0], "1");
- });
- after('unset config property', async function () {
- await rpcControlServer.tor_pool.instance_at(0).set_config('TestSocks', 0);
- });
- });
- describe("#setInstanceConfigByName(instance_name)", function () {
- this.timeout(3000);
- before('set config property', async function () {
- await rpcControlServer.tor_pool.instance_by_name('instance-1').set_config('TestSocks', 0);
- });
- it('should set the property for the tor instance', async function () {
- await rpcClient.invokeAsync('setInstanceConfigByName', ['instance-1', 'TestSocks', 1]);
- });
- it('tor instance should have the modified property', async function () {
- let value = await rpcControlServer.tor_pool.instance_by_name('instance-1').get_config('TestSocks');
- assert.equal(value, 1);
- });
- after('unset config property', async function () {
- await rpcControlServer.tor_pool.instance_by_name('instance-1').set_config('TestSocks', 0);
- });
- });
- describe("#setInstanceConfigAt(index)", function () {
- this.timeout(3000);
- before('set config property', async function () {
- await rpcControlServer.tor_pool.instance_at(0).set_config('TestSocks', 0);
- });
- it('should set the property for the tor instance', async function () {
- await rpcClient.invokeAsync('setInstanceConfigAt', [0, 'TestSocks', 1]);
- });
- it('tor instance should have the modified property', async function () {
- let value = await rpcControlServer.tor_pool.instance_at(0).get_config('TestSocks');
- assert.equal(value, 1);
- });
- after('unset config property', async function () {
- await rpcControlServer.tor_pool.instance_at(0).set_config('TestSocks', 0);
- });
- });
- describe('#signalAllInstances(signal)', function () {
- this.timeout(3000);
- it('should signal to all interfaces', async function () {
- await rpcClient.invokeAsync('signalAllInstances', [ 'DEBUG' ]);
- });
- });
- describe('#signalInstanceAt(signal)', function () {
- this.timeout(3000);
- it('should signal to all interfaces', async function () {
- await rpcClient.invokeAsync('signalInstanceAt', [ 0, 'DEBUG' ]);
- });
- });
- describe('#signalAllInstances(signal)', function () {
- this.timeout(3000);
- it('should signal to all interfaces', async function () {
- await rpcClient.invokeAsync('signalInstanceByName', [ 'instance-1', 'DEBUG' ]);
- });
- });
- describe('#signalInstancesByGroup()', function () {
- it(`should get new identites for all instances in group`, async function () {
- await rpcClient.invokeAsync('signalInstancesByGroup', [ 'foo', 'DEBUG' ]);
- });
- });
- describe("#nextInstance()", function () {
- this.timeout(3000);
- let instance_name;
- it('should rotate the 0th item in the instances array', async function () {
- instance_name = rpcControlServer.tor_pool.instances[0].instance_name;
- await rpcClient.invokeAsync('nextInstance', []);
- });
- it('0th item in the instances array should be different after nextInstance is called', function () {
- assert.notEqual(rpcControlServer.tor_pool.instances[0].instance_name, instance_name);
- });
- });
- describe('#nextInstanceByGroup(group)', function () {
- before('add "instance-1" to "foo"', function () {
- rpcControlServer.tor_pool.add_instance_to_group_by_name('foo', 'instance-2');
- });
- it('should rotate the instances in group "foo"', async function () {
- this.timeout(5000);
- let first_instance_name_before = rpcControlServer.tor_pool.groups['foo'][0].instance_name;
- await rpcClient.invokeAsync('nextInstanceByGroup', [ 'foo' ]);
- let first_instance_name_after = rpcControlServer.tor_pool.groups['foo'][0].instance_name;
-
- assert.notEqual(first_instance_name_after, first_instance_name_before);
- });
- after('remove "instance-1" from "foo"', function () {
- rpcControlServer.tor_pool.remove_instance_from_group_by_name('foo', 'instance-2');
- })
- });
- var instance_num1, instance_num2, i_num;
- describe('#removeInstanceAt(index)', function () {
- this.timeout(10000);
- it("should remove an instance at the position specified", async function () {
- instance_num1 = rpcControlServer.tor_pool.instances.length;
- await rpcClient.invokeAsync('removeInstanceAt', [0]);
- });
- it('the tor pool should contain one instance fewer', function () {
- assert.equal(rpcControlServer.tor_pool.instances.length, (instance_num1 - 1));
- });
- });
- describe('#removeInstanceByName(instance_name)', function () {
- this.timeout(10000);
- it("should remove an instance at the position specified", async function () {
- instance_num2 = rpcControlServer.tor_pool.instances.length;
- await rpcClient.invokeAsync('removeInstanceByName', [ "instance-1" ]);
- });
- it('the tor pool should contain one instance fewer', function () {
- assert.equal(rpcControlServer.tor_pool.instances.length, (instance_num2 - 1));
- });
- });
- describe('#closeInstances()', function () {
- this.timeout(10000);
- it('should shutdown all instances', async function () {
- instance_num = rpcControlServer.tor_pool.instances.length;
- await rpcClient.invokeAsync('closeInstances', [ ]);
- });
- it('no instances should be present in the pool', function () {
- assert.equal(rpcControlServer.tor_pool.instances.length, 0);
- });
- });
- after('shutdown tor pool', async function () {
- this.timeout(10000);
- await rpcControlServer.tor_pool.exit();
- });
- });
|