2018-03-14 02:01:23 +00:00
|
|
|
|
const { assert } = require('chai');
|
2018-04-10 22:09:29 +00:00
|
|
|
|
const sinon = require('sinon');
|
2018-03-14 02:01:23 +00:00
|
|
|
|
|
|
|
|
|
const Message = require('../../../js/modules/types/message');
|
2018-03-23 19:49:22 +00:00
|
|
|
|
const { stringToArrayBuffer } = require('../../../js/modules/string_to_array_buffer');
|
2018-03-14 02:01:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
describe('Message', () => {
|
2018-04-04 22:57:18 +00:00
|
|
|
|
describe('createAttachmentDataWriter', () => {
|
2018-04-04 01:10:34 +00:00
|
|
|
|
it('should ignore messages that didn’t go through attachment migration', async () => {
|
|
|
|
|
const input = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
schemaVersion: 2,
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
schemaVersion: 2,
|
|
|
|
|
};
|
|
|
|
|
const writeExistingAttachmentData = () => {};
|
|
|
|
|
|
2018-04-04 22:57:18 +00:00
|
|
|
|
const actual =
|
|
|
|
|
await Message.createAttachmentDataWriter(writeExistingAttachmentData)(input);
|
2018-04-04 01:10:34 +00:00
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should ignore messages without attachments', async () => {
|
|
|
|
|
const input = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
schemaVersion: 4,
|
|
|
|
|
attachments: [],
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
schemaVersion: 4,
|
|
|
|
|
attachments: [],
|
|
|
|
|
};
|
|
|
|
|
const writeExistingAttachmentData = () => {};
|
|
|
|
|
|
2018-04-04 22:57:18 +00:00
|
|
|
|
const actual =
|
|
|
|
|
await Message.createAttachmentDataWriter(writeExistingAttachmentData)(input);
|
2018-04-04 01:10:34 +00:00
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should write attachments to file system on original path', async () => {
|
|
|
|
|
const input = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
schemaVersion: 4,
|
|
|
|
|
attachments: [{
|
|
|
|
|
path: 'ab/abcdefghi',
|
|
|
|
|
data: stringToArrayBuffer('It’s easy if you try'),
|
|
|
|
|
}],
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
schemaVersion: 4,
|
|
|
|
|
attachments: [{
|
|
|
|
|
path: 'ab/abcdefghi',
|
|
|
|
|
}],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const writeExistingAttachmentData = (attachment) => {
|
|
|
|
|
assert.equal(attachment.path, 'ab/abcdefghi');
|
|
|
|
|
assert.deepEqual(attachment.data, stringToArrayBuffer('It’s easy if you try'));
|
|
|
|
|
};
|
|
|
|
|
|
2018-04-04 22:57:18 +00:00
|
|
|
|
const actual =
|
|
|
|
|
await Message.createAttachmentDataWriter(writeExistingAttachmentData)(input);
|
2018-04-04 01:10:34 +00:00
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2018-03-14 15:45:35 +00:00
|
|
|
|
describe('initializeSchemaVersion', () => {
|
2018-03-14 02:01:23 +00:00
|
|
|
|
it('should ignore messages with previously inherited schema', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
schemaVersion: 2,
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
schemaVersion: 2,
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-14 15:45:35 +00:00
|
|
|
|
const actual = Message.initializeSchemaVersion(input);
|
2018-03-14 02:01:23 +00:00
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
context('for message without attachments', () => {
|
|
|
|
|
it('should initialize schema version to zero', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
attachments: [],
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
attachments: [],
|
|
|
|
|
schemaVersion: 0,
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-14 15:45:35 +00:00
|
|
|
|
const actual = Message.initializeSchemaVersion(input);
|
2018-03-14 02:01:23 +00:00
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
context('for message with attachments', () => {
|
|
|
|
|
it('should inherit existing attachment schema version', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
attachments: [{
|
|
|
|
|
contentType: 'image/jpeg',
|
|
|
|
|
fileName: 'lennon.jpg',
|
|
|
|
|
schemaVersion: 7,
|
|
|
|
|
}],
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
body: 'Imagine there is no heaven…',
|
|
|
|
|
attachments: [{
|
|
|
|
|
contentType: 'image/jpeg',
|
|
|
|
|
fileName: 'lennon.jpg',
|
|
|
|
|
}],
|
|
|
|
|
schemaVersion: 7,
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-14 15:45:35 +00:00
|
|
|
|
const actual = Message.initializeSchemaVersion(input);
|
2018-03-14 02:01:23 +00:00
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
2018-03-14 03:45:19 +00:00
|
|
|
|
|
|
|
|
|
describe('upgradeSchema', () => {
|
|
|
|
|
it('should upgrade an unversioned message to the latest version', async () => {
|
|
|
|
|
const input = {
|
|
|
|
|
attachments: [{
|
|
|
|
|
contentType: 'application/json',
|
2018-03-15 00:45:33 +00:00
|
|
|
|
data: stringToArrayBuffer('It’s easy if you try'),
|
2018-03-14 03:45:19 +00:00
|
|
|
|
fileName: 'test\u202Dfig.exe',
|
|
|
|
|
size: 1111,
|
|
|
|
|
}],
|
|
|
|
|
schemaVersion: 0,
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
attachments: [{
|
|
|
|
|
contentType: 'application/json',
|
2018-03-15 00:45:33 +00:00
|
|
|
|
path: 'abc/abcdefg',
|
2018-03-14 03:45:19 +00:00
|
|
|
|
fileName: 'test\uFFFDfig.exe',
|
|
|
|
|
size: 1111,
|
|
|
|
|
}],
|
|
|
|
|
schemaVersion: Message.CURRENT_SCHEMA_VERSION,
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-15 00:45:33 +00:00
|
|
|
|
const expectedAttachmentData = stringToArrayBuffer('It’s easy if you try');
|
|
|
|
|
const context = {
|
2018-04-04 01:06:29 +00:00
|
|
|
|
writeNewAttachmentData: async (attachmentData) => {
|
2018-03-15 00:45:33 +00:00
|
|
|
|
assert.deepEqual(attachmentData, expectedAttachmentData);
|
|
|
|
|
return 'abc/abcdefg';
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const actual = await Message.upgradeSchema(input, context);
|
2018-03-14 03:45:19 +00:00
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
context('with multiple upgrade steps', () => {
|
|
|
|
|
it('should return last valid message when any upgrade step fails', async () => {
|
|
|
|
|
const input = {
|
|
|
|
|
attachments: [{
|
|
|
|
|
contentType: 'application/json',
|
|
|
|
|
data: null,
|
|
|
|
|
fileName: 'test\u202Dfig.exe',
|
|
|
|
|
size: 1111,
|
|
|
|
|
}],
|
|
|
|
|
schemaVersion: 0,
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
attachments: [{
|
|
|
|
|
contentType: 'application/json',
|
|
|
|
|
data: null,
|
|
|
|
|
fileName: 'test\u202Dfig.exe',
|
|
|
|
|
size: 1111,
|
|
|
|
|
}],
|
|
|
|
|
hasUpgradedToVersion1: true,
|
|
|
|
|
schemaVersion: 1,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const v1 = async message =>
|
|
|
|
|
Object.assign({}, message, { hasUpgradedToVersion1: true });
|
|
|
|
|
const v2 = async () => {
|
|
|
|
|
throw new Error('boom');
|
|
|
|
|
};
|
|
|
|
|
const v3 = async message =>
|
|
|
|
|
Object.assign({}, message, { hasUpgradedToVersion3: true });
|
|
|
|
|
|
2018-03-14 15:45:35 +00:00
|
|
|
|
const toVersion1 = Message._withSchemaVersion(1, v1);
|
|
|
|
|
const toVersion2 = Message._withSchemaVersion(2, v2);
|
|
|
|
|
const toVersion3 = Message._withSchemaVersion(3, v3);
|
2018-03-14 03:45:19 +00:00
|
|
|
|
|
|
|
|
|
const upgradeSchema = async message =>
|
|
|
|
|
toVersion3(await toVersion2(await toVersion1(message)));
|
|
|
|
|
|
|
|
|
|
const actual = await upgradeSchema(input);
|
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should skip out-of-order upgrade steps', async () => {
|
|
|
|
|
const input = {
|
|
|
|
|
attachments: [{
|
|
|
|
|
contentType: 'application/json',
|
|
|
|
|
data: null,
|
|
|
|
|
fileName: 'test\u202Dfig.exe',
|
|
|
|
|
size: 1111,
|
|
|
|
|
}],
|
|
|
|
|
schemaVersion: 0,
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
attachments: [{
|
|
|
|
|
contentType: 'application/json',
|
|
|
|
|
data: null,
|
|
|
|
|
fileName: 'test\u202Dfig.exe',
|
|
|
|
|
size: 1111,
|
|
|
|
|
}],
|
|
|
|
|
schemaVersion: 2,
|
|
|
|
|
hasUpgradedToVersion1: true,
|
|
|
|
|
hasUpgradedToVersion2: true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const v1 = async attachment =>
|
|
|
|
|
Object.assign({}, attachment, { hasUpgradedToVersion1: true });
|
|
|
|
|
const v2 = async attachment =>
|
|
|
|
|
Object.assign({}, attachment, { hasUpgradedToVersion2: true });
|
|
|
|
|
const v3 = async attachment =>
|
|
|
|
|
Object.assign({}, attachment, { hasUpgradedToVersion3: true });
|
|
|
|
|
|
2018-03-14 15:45:35 +00:00
|
|
|
|
const toVersion1 = Message._withSchemaVersion(1, v1);
|
|
|
|
|
const toVersion2 = Message._withSchemaVersion(2, v2);
|
|
|
|
|
const toVersion3 = Message._withSchemaVersion(3, v3);
|
2018-03-14 03:45:19 +00:00
|
|
|
|
|
|
|
|
|
// NOTE: We upgrade to 3 before 2, i.e. the pipeline should abort:
|
|
|
|
|
const upgradeSchema = async attachment =>
|
|
|
|
|
toVersion2(await toVersion3(await toVersion1(attachment)));
|
|
|
|
|
|
|
|
|
|
const actual = await upgradeSchema(input);
|
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2018-03-14 15:45:35 +00:00
|
|
|
|
describe('_withSchemaVersion', () => {
|
2018-03-14 03:45:19 +00:00
|
|
|
|
it('should require a version number', () => {
|
|
|
|
|
const toVersionX = () => {};
|
|
|
|
|
assert.throws(
|
2018-03-14 15:45:35 +00:00
|
|
|
|
() => Message._withSchemaVersion(toVersionX, 2),
|
2018-04-11 19:44:52 +00:00
|
|
|
|
"'schemaVersion' is invalid"
|
2018-03-14 03:45:19 +00:00
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should require an upgrade function', () => {
|
|
|
|
|
assert.throws(
|
2018-03-14 15:45:35 +00:00
|
|
|
|
() => Message._withSchemaVersion(2, 3),
|
2018-04-11 19:44:52 +00:00
|
|
|
|
"'upgrade' must be a function"
|
2018-03-14 03:45:19 +00:00
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should skip upgrading if message has already been upgraded', async () => {
|
|
|
|
|
const upgrade = async message =>
|
|
|
|
|
Object.assign({}, message, { foo: true });
|
2018-03-14 15:45:35 +00:00
|
|
|
|
const upgradeWithVersion = Message._withSchemaVersion(3, upgrade);
|
2018-03-14 03:45:19 +00:00
|
|
|
|
|
|
|
|
|
const input = {
|
|
|
|
|
id: 'guid-guid-guid-guid',
|
|
|
|
|
schemaVersion: 4,
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
id: 'guid-guid-guid-guid',
|
|
|
|
|
schemaVersion: 4,
|
|
|
|
|
};
|
|
|
|
|
const actual = await upgradeWithVersion(input);
|
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should return original message if upgrade function throws', async () => {
|
|
|
|
|
const upgrade = async () => {
|
|
|
|
|
throw new Error('boom!');
|
|
|
|
|
};
|
2018-03-14 15:45:35 +00:00
|
|
|
|
const upgradeWithVersion = Message._withSchemaVersion(3, upgrade);
|
2018-03-14 03:45:19 +00:00
|
|
|
|
|
|
|
|
|
const input = {
|
|
|
|
|
id: 'guid-guid-guid-guid',
|
|
|
|
|
schemaVersion: 0,
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
id: 'guid-guid-guid-guid',
|
|
|
|
|
schemaVersion: 0,
|
|
|
|
|
};
|
|
|
|
|
const actual = await upgradeWithVersion(input);
|
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should return original message if upgrade function returns null', async () => {
|
|
|
|
|
const upgrade = async () => null;
|
2018-03-14 15:45:35 +00:00
|
|
|
|
const upgradeWithVersion = Message._withSchemaVersion(3, upgrade);
|
2018-03-14 03:45:19 +00:00
|
|
|
|
|
|
|
|
|
const input = {
|
|
|
|
|
id: 'guid-guid-guid-guid',
|
|
|
|
|
schemaVersion: 0,
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
id: 'guid-guid-guid-guid',
|
|
|
|
|
schemaVersion: 0,
|
|
|
|
|
};
|
|
|
|
|
const actual = await upgradeWithVersion(input);
|
|
|
|
|
assert.deepEqual(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
});
|
2018-04-10 22:09:29 +00:00
|
|
|
|
|
|
|
|
|
describe('_mapQuotedAttachments', () => {
|
|
|
|
|
it('handles message with no quote', async () => {
|
|
|
|
|
const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called"));
|
|
|
|
|
const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment);
|
|
|
|
|
|
|
|
|
|
const message = {
|
|
|
|
|
body: 'hey there!',
|
|
|
|
|
};
|
|
|
|
|
const result = await upgradeVersion(message);
|
|
|
|
|
assert.deepEqual(result, message);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('handles quote with no attachments', async () => {
|
|
|
|
|
const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called"));
|
|
|
|
|
const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment);
|
|
|
|
|
|
|
|
|
|
const message = {
|
|
|
|
|
body: 'hey there!',
|
|
|
|
|
quote: {
|
|
|
|
|
text: 'hey!',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
body: 'hey there!',
|
|
|
|
|
quote: {
|
|
|
|
|
text: 'hey!',
|
|
|
|
|
attachments: [],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const result = await upgradeVersion(message);
|
|
|
|
|
assert.deepEqual(result, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('handles zero attachments', async () => {
|
|
|
|
|
const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called"));
|
|
|
|
|
const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment);
|
|
|
|
|
|
|
|
|
|
const message = {
|
|
|
|
|
body: 'hey there!',
|
|
|
|
|
quote: {
|
|
|
|
|
text: 'hey!',
|
|
|
|
|
attachments: [],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const result = await upgradeVersion(message);
|
|
|
|
|
assert.deepEqual(result, message);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('calls provided async function for each quoted attachment', async () => {
|
2018-04-13 02:02:20 +00:00
|
|
|
|
const upgradeAttachment = sinon.stub().resolves({
|
2018-04-10 22:09:29 +00:00
|
|
|
|
path: '/new/path/on/disk',
|
2018-04-13 02:02:20 +00:00
|
|
|
|
});
|
2018-04-10 22:09:29 +00:00
|
|
|
|
const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment);
|
|
|
|
|
|
|
|
|
|
const message = {
|
|
|
|
|
body: 'hey there!',
|
|
|
|
|
quote: {
|
|
|
|
|
text: 'hey!',
|
|
|
|
|
attachments: [{
|
|
|
|
|
data: 'data is here',
|
|
|
|
|
}],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const expected = {
|
|
|
|
|
body: 'hey there!',
|
|
|
|
|
quote: {
|
|
|
|
|
text: 'hey!',
|
|
|
|
|
attachments: [{
|
|
|
|
|
path: '/new/path/on/disk',
|
|
|
|
|
}],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const result = await upgradeVersion(message);
|
|
|
|
|
assert.deepEqual(result, expected);
|
|
|
|
|
});
|
|
|
|
|
});
|
2018-03-14 02:01:23 +00:00
|
|
|
|
});
|