diff --git a/test/panic/on-recovery.js b/test/panic/on-recovery.js index 4fc6ffe6..adb19304 100644 --- a/test/panic/on-recovery.js +++ b/test/panic/on-recovery.js @@ -8,6 +8,9 @@ // visible/active throughout the tests, because an inactive tab will NOT // reconnect to the relay peer until the tab is active again. (Chrome 83) +// Uses a pattern described in https://stackoverflow.com/a/39286581/13564512 +// to run multiple configurations of a mocha test. + var config = { IP: require('ip').address(), port: 8765, @@ -16,209 +19,269 @@ var config = { route: { '/': __dirname + '/index.html', '/gun.js': __dirname + '/../../gun.js', - '/jquery.js': __dirname + '/../../examples/jquery.js' + '/jquery.js': __dirname + '/../../examples/jquery.js', + '/radix.js': __dirname + '/../../lib/radix.js', + '/radisk.js': __dirname + '/../../lib/radisk.js', + '/store.js': __dirname + '/../../lib/store.js', + '/rindexed.js': __dirname + '/../../lib/rindexed.js' + }, + /** Test variants to run */ + variants: ['default', 'radisk'], + /** Configuration details for each variant. If unspecified, variant will run with no additional configuration. */ + variantConfigs: { + radisk: { + /** Options to pass the Gun constructor */ + opts: { + localStorage: false + }, + /** Libraries to import before constructing Gun */ + imports: [ + 'radix.js', + 'radisk.js', + 'store.js', + 'rindexed.js' + ] + } } -} +}; +var {loadBrowserScripts} = require('./util/load-browser-scripts'); var panic = require('panic-server'); -panic.server().on('request', function(req, res){ +panic.server().on('request', function (req, res) { config.route[req.url] && require('fs').createReadStream(config.route[req.url]).pipe(res); }).listen(config.port); -var clients = panic.clients; + var manager = require('panic-manager')(); -manager.start({ - clients: Array(config.servers).fill().map(function(u, i){ - return { - type: 'node', - port: config.port + (i + 1) - } - }), - panic: 'http://' + config.IP + ':' + config.port -}); - +var clients = panic.clients; var servers = clients.filter('Node.js'); +/** The first relay peer */ var bob = servers.pluck(1); +/** The second relay peer */ var carl = servers.excluding(bob).pluck(1); var browsers = clients.excluding(servers); +/** The "sending" browser */ var alice = browsers.pluck(1); +/** The "receiving" browser */ var dave = browsers.excluding(alice).pluck(1); -describe("gun.on should receive updates after crashed relay peer comes back online", function(){ - this.timeout(10 * 60 * 1000); +// Describe the test itself +describe("gun.on should receive updates after crashed relay peer comes back online", function () { + this.timeout(10 * 1000); + config.variants.forEach((variant) => { + var variantConfig = config.variantConfigs[variant] || {}; - it("Servers have joined!", function(){ - return servers.atLeast(config.servers); - }); - - it("GUN started!", function(){ - return bob.run(function(test){ - var env = test.props; - var filepath = env.dir + '/data'; - test.async(); - var fs = require('fs'); - try { if (fs.existsSync(filepath)) { fs.rmdirSync(filepath, { recursive: true }); } } catch (e) { console.error(e); test.fail(''); } - var server = require('http').createServer(function(req, res){ - res.end("I AM BOB"); + // Describe the variant + describe(`with ${variant} plugin configuration`, function () { + before('PANIC manager setup servers', function () { + // we are terminating the gun servers after each test variant, so we need to start them up again before each test variant + manager.start({ + clients: Array(config.servers).fill().map(function (u, i) { + return { + type: 'node', + port: config.port + (i + 1) + } + }), + panic: 'http://' + config.IP + ':' + config.port + }); }); - var port = env.config.port + 1; - try { var Gun = require(env.dir + '/../../index.js'); } catch(e) { console.error(e); test.fail(''); } - var gun = Gun({file: filepath, web: server}); - server.listen(port, function(){ - test.done(); + + before("Servers have joined!", function () { + return servers.atLeast(config.servers); }); - }, {config: config, dir: __dirname}); - }); - it(config.browsers +" browser(s) have joined!", function(){ - require('./util/open').web(config.browsers, "http://"+ config.IP +":"+ config.port); - return browsers.atLeast(config.browsers); - }); - - it("Browsers initialized gun!", function(){ - var tests = [], i = 0; - browsers.each(function(client, id){ - tests.push(client.run(function(test){ - try{ localStorage.clear() }catch(e){} - try{ indexedDB.deleteDatabase('radata') }catch(e){} - var env = test.props; - var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun'); - window.ref = gun.get('a'); - }, {i: i += 1, config: config})); - }); - return Promise.all(tests); - }); - - it("Dave subscribed to updates using gun.on()", function(){ - return dave.run(function(test){ - console.log("I AM DAVE"); - test.async(); - ref.on(function(data){ - console.log("Just received data: ", data); - if(data.hello === 'world') { window.receivedFirst = true; } - if(data.foo === 'bar') { window.receivedSecond = true; } - }); - test.done(); - }); - }); - - it("Alice put first data", function(){ - return alice.run(function(test){ - console.log("I AM ALICE"); - test.async(); - ref.put({hello: 'world'}, function(ack){ - if(!ack.err) { - test.done(); - } - }); - }); - }); - - it("Dave received first data", function(){ - return dave.run(function(test){ - test.async(); - var myInterval; - myInterval = setInterval(function() { - if(window.receivedFirst) { - clearInterval(myInterval); - test.done(); - } - }, 10); - }); - }); - - it("Killed relay peer", function(){ - return bob.run(function(test){ - test.async(); - process.exit(); - }); - }); - - it("Waited 1 second", function(done){ - setTimeout(done, 1000); - }); - - it("Alice put second data", function(){ - return alice.run(function(test){ - test.async(); - ref.put({foo: 'bar'}, function(ack){ - if(!ack.err) { - test.done(); - } - }); - }); - }); - - // FIXME: Don't copy paste the entire block!! - it("Restored relay peer", function(){ - return carl.run(function(test){ - var env = test.props; - var filepath = env.dir + '/data'; - test.async(); - var fs = require('fs'); - try { if (fs.existsSync(filepath)) { fs.rmdirSync(filepath, { recursive: true }); } } catch (e) { console.error(e); test.fail(''); } - var server = require('http').createServer(function(req, res){ - res.end("I AM CARL"); - }); - var port = env.config.port + 1; - try { var Gun = require(env.dir + '/../../index.js'); } catch(e) { console.error(e); test.fail(''); } - var gun = Gun({file: filepath, web: server}); - server.listen(port, function(){ - test.done(); - }); - }, {config: config, dir: __dirname}); - }); - - it("Browsers reconnected", function() { - var tests = [], i = 0; - browsers.each(function(client, id){ - tests.push(client.run(function(test){ - test.async(); - var config = test.props.config; - var seconds = 15; - var timeout = Date.now() + seconds * 1000; - var url = "http://"+ config.IP +":"+ (config.port+1) +"/gun"; - var peers = ref.back(1)._.opt.peers; - var i; - i = setInterval(function() { - if(peers[url] && peers[url].wire.readyState === 1) { - clearInterval(i); + it("GUN started!", function () { + return bob.run(function (test) { + var env = test.props; + var filepath = env.dir + '/data'; + test.async(); + var fs = require('fs'); + try {if (fs.existsSync(filepath)) {fs.rmdirSync(filepath, {recursive: true});} } catch (e) {console.error(e); test.fail('');} + var server = require('http').createServer(function (req, res) { + res.end("I AM BOB"); + }); + var port = env.config.port + 1; + try {var Gun = require(env.dir + '/../../index.js');} catch (e) {console.error(e); test.fail('');} + var gun = Gun({file: filepath, web: server}); + server.listen(port, function () { test.done(); - return; - } - if(Date.now() >= timeout) { - test.fail('Timed out after ' + seconds + ' seconds'); - return; - } - }, 10); - }, {config: config})); - }); - return Promise.all(tests); - }); + }); + }, {config: config, dir: __dirname}); + }); - it("Dave received second data", function(){ - return dave.run(function(test){ - test.async(); - var seconds = 60; - var timeout = Date.now() + seconds * 1000; - var i; - i = setInterval(function() { - if(window.receivedSecond) { + it(config.browsers + " browser(s) have joined!", function () { + require('./util/open').web(config.browsers, "http://" + config.IP + ":" + config.port, { + headless: true, + }); + return browsers.atLeast(config.browsers); + }); + + it(`Browsers loaded ${variant} plugin libraries`, function () { + return loadBrowserScripts(browsers, variantConfig.imports); + }); + + it("Browsers initialized gun!", function () { + var tests = [], i = 0; + browsers.each(function (client, id) { + tests.push(client.run(function (test) { + try {localStorage.clear()} catch (e) { } + try {indexedDB.deleteDatabase('radata')} catch (e) { } + var env = test.props; + var configOpts = env.variantConfig.opts || {}; + var opts = { + peers: ['http://' + env.config.IP + ':' + (env.config.port + 1) + '/gun'], + ...configOpts + }; + + console.log('using constructor options: ', JSON.stringify(opts)); + var gun = Gun(opts); + window.ref = gun.get('a'); + }, {i: i += 1, config: config, variantConfig: variantConfig})); + }); + return Promise.all(tests); + }); + + it("Dave subscribed to updates using gun.on()", function () { + return dave.run(function (test) { + console.log("I AM DAVE"); + test.async(); + ref.on(function (data) { + console.log("Just received data: ", JSON.stringify(data)); + if (data.hello === 'world') {window.receivedFirst = true;} + if (data.foo === 'bar') {window.receivedSecond = true;} + }); test.done(); - return; - } - if(Date.now() >= timeout) { - test.fail('Timed out after ' + seconds + ' seconds'); - return; - } - }, 10); - }); - }); + }); + }); - after("Everything shut down.", function(){ - return require('./util/open').cleanup() || bob.run(function(){ - process.exit(); + it("Alice put first data", function () { + return alice.run(function (test) { + console.log("I AM ALICE"); + test.async(); + ref.put({hello: 'world'}, function (ack) { + if (!ack.err) { + test.done(); + } else { + console.log('ALICE WAS UNABLE TO PUT DATA!'); + test.fail(); + } + }); + }); + }); + + it("Dave received first data", function () { + return dave.run(function (test) { + test.async(); + var myInterval; + myInterval = setInterval(function () { + if (window.receivedFirst) { + clearInterval(myInterval); + test.done(); + } + }, 10); + }); + }); + + it("Killed relay peer", function () { + return bob.run(function (test) { + test.async(); + process.exit(); + }); + }); + + it("Waited 1 second", function (done) { + setTimeout(done, 1000); + }); + + it("Alice put second data", function () { + return alice.run(function (test) { + test.async(); + ref.put({foo: 'bar'}, function (ack) { + if (!ack.err) { + test.done(); + } + }); + }); + }); + + // FIXME: Don't copy paste the entire block!! + it("Restored relay peer", function () { + return carl.run(function (test) { + var env = test.props; + var filepath = env.dir + '/data'; + test.async(); + var fs = require('fs'); + try {if (fs.existsSync(filepath)) {fs.rmdirSync(filepath, {recursive: true});} } catch (e) {console.error(e); test.fail('');} + var server = require('http').createServer(function (req, res) { + res.end("I AM CARL"); + }); + var port = env.config.port + 1; + try {var Gun = require(env.dir + '/../../index.js');} catch (e) {console.error(e); test.fail('');} + var gun = Gun({file: filepath, web: server}); + server.listen(port, function () { + test.done(); + }); + }, {config: config, dir: __dirname}); + }); + + it("Browsers reconnected", function () { + var tests = [], i = 0; + browsers.each(function (client, id) { + tests.push(client.run(function (test) { + test.async(); + var config = test.props.config; + var seconds = 15; + var timeout = Date.now() + seconds * 1000; + var url = "http://" + config.IP + ":" + (config.port + 1) + "/gun"; + var peers = ref.back(1)._.opt.peers; + var i; + i = setInterval(function () { + if (peers[url] && peers[url].wire.readyState === 1) { + clearInterval(i); + test.done(); + return; + } + if (Date.now() >= timeout) { + test.fail('Timed out after ' + seconds + ' seconds'); + return; + } + }, 10); + }, {config: config})); + }); + return Promise.all(tests); + }); + + it("Dave received second data", function () { + return dave.run(function (test) { + test.async(); + var seconds = 60; + var timeout = Date.now() + seconds * 1000; + var i; + i = setInterval(function () { + if (window.receivedSecond) { + test.done(); + return; + } + if (Date.now() >= timeout) { + test.fail('Timed out after ' + seconds + ' seconds'); + return; + } + }, 10); + }); + }); + + it('Closed browsers & servers', function () { + var promises = []; + promises.push(bob.run(function () { + process.exit(); + })); + promises.push(carl.run(function () { + process.exit(); + })); + promises.push(require('./util/open').cleanup()); + return Promise.all(promises); + }); }); }); });