tests: Factor out USER_CHANGES/ACCEPT_COMMIT helpers
This will make it possible for other tests to reuse the code.pull/5331/head
parent
674a0ccedc
commit
02d1b90d30
|
@ -1,6 +1,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const AttributePool = require('../../static/js/AttributePool');
|
||||||
const apiHandler = require('../../node/handler/APIHandler');
|
const apiHandler = require('../../node/handler/APIHandler');
|
||||||
|
const assert = require('assert').strict;
|
||||||
const io = require('socket.io-client');
|
const io = require('socket.io-client');
|
||||||
const log4js = require('log4js');
|
const log4js = require('log4js');
|
||||||
const process = require('process');
|
const process = require('process');
|
||||||
|
@ -185,6 +187,58 @@ exports.handshake = async (socket, padId) => {
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience wrapper around `socket.send()` that waits for acknowledgement.
|
||||||
|
*/
|
||||||
|
exports.sendMessage = async (socket, message) => await new Promise((resolve, reject) => {
|
||||||
|
socket.send(message, (errInfo) => {
|
||||||
|
if (errInfo != null) {
|
||||||
|
const {name, message} = errInfo;
|
||||||
|
const err = new Error(message);
|
||||||
|
err.name = name;
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to send a USER_CHANGES message. Waits for acknowledgement.
|
||||||
|
*/
|
||||||
|
exports.sendUserChanges = async (socket, data) => await exports.sendMessage(socket, {
|
||||||
|
type: 'COLLABROOM',
|
||||||
|
component: 'pad',
|
||||||
|
data: {
|
||||||
|
type: 'USER_CHANGES',
|
||||||
|
apool: new AttributePool(),
|
||||||
|
...data,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function that waits for an ACCEPT_COMMIT message. Asserts that the new revision
|
||||||
|
* matches the expected revision.
|
||||||
|
*
|
||||||
|
* Note: To avoid a race condition, this should be called before the USER_CHANGES message is sent.
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* await Promise.all([
|
||||||
|
* common.waitForAcceptCommit(socket, rev + 1),
|
||||||
|
* common.sendUserChanges(socket, {baseRev: rev, changeset}),
|
||||||
|
* ]);
|
||||||
|
*/
|
||||||
|
exports.waitForAcceptCommit = async (socket, wantRev) => {
|
||||||
|
const msg = await exports.waitForSocketEvent(socket, 'message');
|
||||||
|
assert.deepEqual(msg, {
|
||||||
|
type: 'COLLABROOM',
|
||||||
|
data: {
|
||||||
|
type: 'ACCEPT_COMMIT',
|
||||||
|
newRev: wantRev,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
|
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -36,27 +36,10 @@ describe(__filename, function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('USER_CHANGES', function () {
|
describe('USER_CHANGES', function () {
|
||||||
const sendUserChanges = (changeset, apool = new AttributePool()) => {
|
const sendUserChanges =
|
||||||
socket.json.send({
|
async (changeset) => await common.sendUserChanges(socket, {baseRev: rev, changeset});
|
||||||
type: 'COLLABROOM',
|
|
||||||
component: 'pad',
|
|
||||||
data: {
|
|
||||||
type: 'USER_CHANGES',
|
|
||||||
baseRev: rev,
|
|
||||||
changeset,
|
|
||||||
apool: new AttributePool(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const assertAccepted = async (wantRev) => {
|
const assertAccepted = async (wantRev) => {
|
||||||
const msg = await common.waitForSocketEvent(socket, 'message');
|
await common.waitForAcceptCommit(socket, wantRev);
|
||||||
assert.deepEqual(msg, {
|
|
||||||
type: 'COLLABROOM',
|
|
||||||
data: {
|
|
||||||
type: 'ACCEPT_COMMIT',
|
|
||||||
newRev: wantRev,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
rev = wantRev;
|
rev = wantRev;
|
||||||
};
|
};
|
||||||
const assertRejected = async () => {
|
const assertRejected = async () => {
|
||||||
|
@ -65,38 +48,55 @@ describe(__filename, function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
it('changes are applied', async function () {
|
it('changes are applied', async function () {
|
||||||
sendUserChanges('Z:1>5+5$hello');
|
await Promise.all([
|
||||||
await assertAccepted(rev + 1);
|
assertAccepted(rev + 1),
|
||||||
|
sendUserChanges('Z:1>5+5$hello'),
|
||||||
|
]);
|
||||||
assert.equal(pad.text(), 'hello\n');
|
assert.equal(pad.text(), 'hello\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('bad changeset is rejected', async function () {
|
it('bad changeset is rejected', async function () {
|
||||||
sendUserChanges('this is not a valid changeset');
|
await Promise.all([
|
||||||
await assertRejected();
|
assertRejected(),
|
||||||
|
sendUserChanges('this is not a valid changeset'),
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('retransmission is accepted, has no effect', async function () {
|
it('retransmission is accepted, has no effect', async function () {
|
||||||
sendUserChanges('Z:1>5+5$hello');
|
const cs = 'Z:1>5+5$hello';
|
||||||
await assertAccepted(rev + 1);
|
await Promise.all([
|
||||||
|
assertAccepted(rev + 1),
|
||||||
|
sendUserChanges(cs),
|
||||||
|
]);
|
||||||
--rev;
|
--rev;
|
||||||
sendUserChanges('Z:1>5+5$hello');
|
await Promise.all([
|
||||||
await assertAccepted(rev + 1);
|
assertAccepted(rev + 1),
|
||||||
|
sendUserChanges(cs),
|
||||||
|
]);
|
||||||
assert.equal(pad.text(), 'hello\n');
|
assert.equal(pad.text(), 'hello\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('identity changeset is accepted, has no effect', async function () {
|
it('identity changeset is accepted, has no effect', async function () {
|
||||||
sendUserChanges('Z:1>5+5$hello');
|
await Promise.all([
|
||||||
await assertAccepted(rev + 1);
|
assertAccepted(rev + 1),
|
||||||
sendUserChanges('Z:6>0$');
|
sendUserChanges('Z:1>5+5$hello'),
|
||||||
await assertAccepted(rev);
|
]);
|
||||||
|
await Promise.all([
|
||||||
|
assertAccepted(rev),
|
||||||
|
sendUserChanges('Z:6>0$'),
|
||||||
|
]);
|
||||||
assert.equal(pad.text(), 'hello\n');
|
assert.equal(pad.text(), 'hello\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('non-identity changeset with no net change is accepted, has no effect', async function () {
|
it('non-identity changeset with no net change is accepted, has no effect', async function () {
|
||||||
sendUserChanges('Z:1>5+5$hello');
|
await Promise.all([
|
||||||
await assertAccepted(rev + 1);
|
assertAccepted(rev + 1),
|
||||||
sendUserChanges('Z:6>0-5+5$hello');
|
sendUserChanges('Z:1>5+5$hello'),
|
||||||
await assertAccepted(rev);
|
]);
|
||||||
|
await Promise.all([
|
||||||
|
assertAccepted(rev),
|
||||||
|
sendUserChanges('Z:6>0-5+5$hello'),
|
||||||
|
]);
|
||||||
assert.equal(pad.text(), 'hello\n');
|
assert.equal(pad.text(), 'hello\n');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue