const path = require('path');
const { startRelay } = require('./helpers/relay');
const { setupPanic, genMsgId, teardownPanic } = require('./helpers/setup');
const binPath = path.resolve(__dirname, '../../target/debug/beam');
const config = {
panicPort: 8765,
relayPort: 9000,
soul: 'panic/concurrent-get/' + Date.now(),
};
const { clients, alice, rest } = setupPanic({ numClients: 3, panicPort: config.panicPort });
const carl = rest.pluck(1);
const dave = rest.excluding(carl).pluck(1);
describe('5. Concurrent Get: simultaneous requests don\'t conflict', function () {
this.timeout(60000);
it('Three clients connected to panic-server', function () {
return clients.atLeast(3);
});
it('BEAM relay started', function () {
this.timeout(10000);
startRelay({ binPath, port: config.relayPort });
return new Promise((resolve) => setTimeout(resolve, 2000));
});
it('Alice puts data then disconnects (offline save)', function () {
this.timeout(15000);
return alice.run(function (test) {
test.async();
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:' + test.props.relayPort);
ws.on('open', () => {
ws.send(JSON.stringify({
'#': 'aliceput',
put: {
[test.props.soul]: {
_: { '#': test.props.soul, '>': { msg: Date.now() } },
msg: 'concurrent-get-works',
},
},
}));
});
ws.on('message', (raw) => {
const m = JSON.parse(raw.toString());
if (m['@'] === 'aliceput') {
ws.close();
test.done();
}
});
ws.on('error', (err) => test.fail('WS error: ' + err.message));
setTimeout(() => test.fail('timeout — no ack in 5s'), 5000);
}, { soul: config.soul, relayPort: config.relayPort });
});
it('Carl and Dave simultaneously Get — both receive data', function () {
this.timeout(15000);
const carlP = carl.run(function (test) {
test.async();
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:' + test.props.relayPort);
let gotData = null;
ws.on('message', (raw) => {
const m = JSON.parse(raw.toString());
if (m.put && m.put[test.props.soul] && m.put[test.props.soul].msg) {
gotData = m.put[test.props.soul].msg;
}
});
ws.on('open', () => {
setTimeout(() => {
ws.send(JSON.stringify({
get: { '#': test.props.soul },
'#': 'carlget' + Math.random().toString(36).slice(2),
}));
}, 200);
});
ws.on('error', (err) => test.fail('WS error: ' + err.message));
const start = Date.now();
const check = setInterval(() => {
if (gotData === 'concurrent-get-works') {
clearInterval(check);
ws.close();
test.done();
} else if (Date.now() - start > 5000) {
clearInterval(check);
test.fail('timeout — Carl got no data in 5s');
}
}, 100);
}, { soul: config.soul, relayPort: config.relayPort });
const daveP = dave.run(function (test) {
test.async();
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:' + test.props.relayPort);
let gotData = null;
ws.on('message', (raw) => {
const m = JSON.parse(raw.toString());
if (m.put && m.put[test.props.soul] && m.put[test.props.soul].msg) {
gotData = m.put[test.props.soul].msg;
}
});
ws.on('open', () => {
setTimeout(() => {
ws.send(JSON.stringify({
get: { '#': test.props.soul },
'#': 'daveget' + Math.random().toString(36).slice(2),
}));
}, 200);
});
ws.on('error', (err) => test.fail('WS error: ' + err.message));
const start = Date.now();
const check = setInterval(() => {
if (gotData === 'concurrent-get-works') {
clearInterval(check);
ws.close();
test.done();
} else if (Date.now() - start > 5000) {
clearInterval(check);
test.fail('timeout — Dave got no data in 5s');
}
}, 100);
}, { soul: config.soul, relayPort: config.relayPort });
return Promise.all([carlP, daveP]);
});
after(function () {
teardownPanic();
});
});