mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
288 lines
8.7 KiB
JavaScript
288 lines
8.7 KiB
JavaScript
// Gun is supposed to be able to gracefully handle peers going offline and then
|
|
// coming back online. If a client has subscribed to some piece of data via the
|
|
// gun.on() API method, the subscription should continue to work if a peer goes
|
|
// offline briefly and then comes back online. This test confirms that such is
|
|
// the case, or fails otherwise.
|
|
|
|
// Important: It turns out that it's very important that both browsers tabs be
|
|
// 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,
|
|
servers: 2,
|
|
browsers: 2,
|
|
route: {
|
|
'/': __dirname + '/index.html',
|
|
'/gun.js': __dirname + '/../../gun.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) {
|
|
config.route[req.url] && require('fs').createReadStream(config.route[req.url]).pipe(res);
|
|
}).listen(config.port);
|
|
|
|
|
|
var manager = require('panic-manager')();
|
|
|
|
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 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] || {};
|
|
|
|
// 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
|
|
});
|
|
});
|
|
|
|
before("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");
|
|
});
|
|
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(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();
|
|
});
|
|
});
|
|
|
|
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);
|
|
});
|
|
});
|
|
});
|
|
});
|