You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/ts/test/session/sending/MessageQueue_test.ts

370 lines
12 KiB
TypeScript

5 years ago
import { expect } from 'chai';
import Sinon, * as sinon from 'sinon';
5 years ago
import { GroupUtils, SyncMessageUtils } from '../../../session/utils';
5 years ago
import { Stubs, TestUtils } from '../../../test/test-utils';
5 years ago
import { MessageQueue } from '../../../session/sending/MessageQueue';
5 years ago
import {
ChatMessage,
ClosedGroupMessage,
OpenGroupMessage,
} from '../../../session/messages/outgoing';
5 years ago
import { PubKey, RawMessage } from '../../../session/types';
5 years ago
import { UserUtil } from '../../../util';
import { MessageSender } from '../../../session/sending';
5 years ago
import { toRawMessage } from '../../../session/utils/Messages';
import { SessionProtocol } from '../../../session/protocols';
import { PendingMessageCache } from '../../../session/sending/PendingMessageCache';
5 years ago
import { generateChatMessage, generateFakePubkey } from '../../test-utils/testUtils';
5 years ago
5 years ago
// Equivalent to Data.StorageItem
interface StorageItem {
id: string;
value: any;
}
5 years ago
5 years ago
describe('MessageQueue', () => {
5 years ago
// Initialize new stubbed cache
let data: StorageItem;
5 years ago
const sandbox = sinon.createSandbox();
5 years ago
const ourDevice = TestUtils.generateFakePubkey();
const ourNumber = ourDevice.key;
5 years ago
const pairedDevices = TestUtils.generateMemberList(2).map(m => m.key);
5 years ago
// Initialize new stubbed queue
5 years ago
let messageQueueStub: MessageQueue;
// Spies
5 years ago
let sendToOpenGroupSpy: sinon.SinonSpy;
let sendMessageToDevicesSpy: sinon.SinonSpy;
let sendSyncMessageSpy: sinon.SinonSpy;
5 years ago
// Message Sender Stubs
5 years ago
let sendStub: sinon.SinonStub<[RawMessage, (number | undefined)?]>;
let sendToOpenGroupStub: sinon.SinonStub<[OpenGroupMessage]>;
5 years ago
// Group Utils Stubs
let groupMembersStub: sinon.SinonStub;
// Session Protocol Stubs
5 years ago
let hasSessionStub: sinon.SinonStub<[PubKey]>;
let sendSessionRequestIfNeededStub: sinon.SinonStub;
// Helper function returns a promise that resolves after all other promise mocks,
// even if they are chained like Promise.resolve().then(...)
// Technically: this is designed to resolve on the next macrotask
async function tick() {
return new Promise(resolve => {
// tslint:disable-next-line: no-string-based-set-timeout
setTimeout(resolve, 0);
});
}
5 years ago
beforeEach(async () => {
5 years ago
// Stub out methods which touch the database
const storageID = 'pendingMessages';
data = {
id: storageID,
value: '[]',
};
// Pending Message Cache Data Stubs
TestUtils.stubData('getItemById')
.withArgs('pendingMessages')
.callsFake(async () => {
return data;
});
TestUtils.stubData('createOrUpdateItem').callsFake((item: StorageItem) => {
if (item.id === storageID) {
data = item;
}
});
5 years ago
5 years ago
// Utils Stubs
sandbox.stub(UserUtil, 'getCurrentDevicePubKey').resolves(ourNumber);
5 years ago
TestUtils.stubData('getPairedDevicesFor').resolves(pairedDevices);
5 years ago
TestUtils.stubWindow('libsignal', {
SignalProtocolAddress: sandbox.stub(),
SessionCipher: Stubs.SessionCipherStub,
} as any);
5 years ago
// Message Sender Stubs
sendStub = sandbox.stub(MessageSender, 'send').resolves();
5 years ago
sendToOpenGroupStub = sandbox
.stub(MessageSender, 'sendToOpenGroup')
.resolves(true);
5 years ago
5 years ago
// Group Utils Stubs
sandbox.stub(GroupUtils, 'isMediumGroup').returns(false);
5 years ago
groupMembersStub = sandbox
.stub(GroupUtils, 'getGroupMembers' as any)
5 years ago
.callsFake(async () => TestUtils.generateMemberList(10));
5 years ago
5 years ago
// Session Protocol Stubs
5 years ago
sandbox.stub(SessionProtocol, 'sendSessionRequest').resolves();
5 years ago
hasSessionStub = sandbox.stub(SessionProtocol, 'hasSession').resolves(true);
sendSessionRequestIfNeededStub = sandbox
.stub(SessionProtocol, 'sendSessionRequestIfNeeded')
.resolves();
5 years ago
// Pending Mesage Cache Stubs
const chatMessages = Array.from(
{ length: 10 },
TestUtils.generateChatMessage
);
5 years ago
const rawMessage = toRawMessage(
5 years ago
TestUtils.generateFakePubkey(),
TestUtils.generateChatMessage()
5 years ago
);
5 years ago
5 years ago
sandbox.stub(PendingMessageCache.prototype, 'add').resolves(rawMessage);
5 years ago
sandbox.stub(PendingMessageCache.prototype, 'remove').resolves();
5 years ago
sandbox
.stub(PendingMessageCache.prototype, 'getDevices')
5 years ago
.returns(TestUtils.generateMemberList(10));
5 years ago
sandbox
.stub(PendingMessageCache.prototype, 'getForDevice')
.returns(
chatMessages.map(m => toRawMessage(TestUtils.generateFakePubkey(), m))
);
5 years ago
// Spies
5 years ago
sendToOpenGroupSpy = sandbox.spy(MessageSender, 'sendToOpenGroup');
sendSyncMessageSpy = sandbox.spy(MessageQueue.prototype, 'sendSyncMessage');
sendMessageToDevicesSpy = sandbox.spy(
MessageQueue.prototype,
'sendMessageToDevices'
);
// Init Queue
5 years ago
messageQueueStub = new MessageQueue();
});
afterEach(() => {
TestUtils.restoreStubs();
5 years ago
sandbox.restore();
5 years ago
});
5 years ago
describe('send', () => {
it('can send to a single device', async () => {
const device = TestUtils.generateFakePubkey();
const message = TestUtils.generateChatMessage();
5 years ago
const promise = messageQueueStub.send(device, message);
await expect(promise).to.be.fulfilled;
});
5 years ago
it('can send sync message', async () => {
const devices = TestUtils.generateMemberList(3);
const message = TestUtils.generateChatMessage();
5 years ago
const promise = messageQueueStub.sendSyncMessage(message, devices);
expect(promise).to.be.fulfilled;
});
5 years ago
});
5 years ago
5 years ago
describe('processPending', () => {
it('will send sync message if no session', async () => {
hasSessionStub.resolves(false);
5 years ago
const device = TestUtils.generateFakePubkey();
const promise = messageQueueStub.processPending(device);
5 years ago
expect(promise).to.be.fulfilled;
5 years ago
await tick();
expect(sendSessionRequestIfNeededStub.callCount).to.equal(1);
});
5 years ago
it('will send message is session exists', () => {
//
//
//
//
//
//
});
});
describe('sendUsingMultiDevice', () => {
it('can send using multidevice', async () => {
const device = TestUtils.generateFakePubkey();
const message = TestUtils.generateChatMessage();
const promise = messageQueueStub.sendUsingMultiDevice(device, message);
5 years ago
expect(promise).to.be.fulfilled;
// Ensure the arguments passed into sendMessageToDevices are correct
await tick();
5 years ago
const previousArgs = sendMessageToDevicesSpy.lastCall.args as [
Array<PubKey>,
ChatMessage
];
5 years ago
// Check that instances are equal
expect(previousArgs).to.have.length(2);
5 years ago
const argsPairedDevices = previousArgs[0];
const argsChatMessage = previousArgs[1];
5 years ago
expect(argsChatMessage instanceof ChatMessage).to.equal(
true,
'message passed into sendMessageToDevices was not a valid ChatMessage'
);
expect(argsChatMessage.isEqual(message)).to.equal(
true,
'message passed into sendMessageToDevices has been mutated'
);
5 years ago
argsPairedDevices.forEach((argsPaired: PubKey, index: number) => {
5 years ago
expect(argsPaired instanceof PubKey).to.equal(
true,
'a device passed into sendMessageToDevices was not a PubKey'
);
5 years ago
expect(argsPaired.key).to.equal(pairedDevices[index]);
});
});
});
describe('sendMessageToDevices', () => {
it('can send to many devices', async () => {
const devices = TestUtils.generateMemberList(10);
const message = TestUtils.generateChatMessage();
5 years ago
const promise = messageQueueStub.sendMessageToDevices(devices, message);
await expect(promise).to.be.fulfilled;
});
5 years ago
5 years ago
it('can send sync message and confirm canSync is valid', async () => {
const devices = TestUtils.generateMemberList(3);
const message = TestUtils.generateChatMessage();
const ourDevices = [...pairedDevices, ourNumber].sort();
5 years ago
const promise = messageQueueStub.sendMessageToDevices(devices, message);
expect(promise).to.be.fulfilled;
// Check sendSyncMessage parameters
await tick();
const previousArgs = sendSyncMessageSpy.lastCall.args as [
ChatMessage,
Array<PubKey>
];
expect(sendSyncMessageSpy.callCount).to.equal(1);
// Check that instances are equal
expect(previousArgs).to.have.length(2);
const argsChatMessage = previousArgs[0];
const argsPairedKeys = [...previousArgs[1]].map(d => d.key).sort();
expect(argsChatMessage instanceof ChatMessage).to.equal(
true,
'message passed into sendMessageToDevices was not a valid ChatMessage'
);
expect(argsChatMessage.isEqual(message)).to.equal(
true,
'message passed into sendMessageToDevices has been mutated'
);
argsPairedKeys.forEach((argsPaired: string, index: number) => {
expect(argsPaired).to.equal(ourDevices[index]);
});
});
5 years ago
});
5 years ago
5 years ago
describe('sendToGroup', () => {
it('can send to closed group', async () => {
const message = TestUtils.generateClosedGroupMessage();
const success = await messageQueueStub.sendToGroup(message);
5 years ago
expect(success).to.equal(true, 'sending to group failed');
});
it('uses correct parameters for sendToGroup with ClosedGroupMessage', async () => {
const message = TestUtils.generateClosedGroupMessage();
const success = await messageQueueStub.sendToGroup(message);
5 years ago
expect(success).to.equal(true, 'sending to group failed');
5 years ago
// Check parameters
await tick();
const previousArgs = sendMessageToDevicesSpy.lastCall.args as [
Array<PubKey>,
ClosedGroupMessage
];
expect(previousArgs).to.have.length(2);
const argsClosedGroupMessage = previousArgs[1];
expect(argsClosedGroupMessage instanceof ClosedGroupMessage).to.equal(
true,
'message passed into sendMessageToDevices was not a ClosedGroupMessage'
);
});
it("won't send to invalid groupId", async () => {
const message = TestUtils.generateClosedGroupMessage('invalid-group-id');
const success = await messageQueueStub.sendToGroup(message);
expect(message instanceof ClosedGroupMessage).to.equal(
true,
'message passed into sendToGroup was not a ClosedGroupMessage'
);
expect(success).to.equal(
false,
'invalid ClosedGroupMessage was propogated through sendToGroup'
);
});
5 years ago
it('wont send message to empty closed group', async () => {
groupMembersStub.callsFake(async () => TestUtils.generateMemberList(0));
5 years ago
const message = TestUtils.generateClosedGroupMessage();
const response = await messageQueueStub.sendToGroup(message);
5 years ago
expect(response).to.equal(
false,
'sendToGroup send a message to an empty group'
);
});
5 years ago
it('wont send invalid message type to closed group', async () => {
// Regular chat message should return false
const message = TestUtils.generateChatMessage();
const response = await messageQueueStub.sendToGroup(message);
5 years ago
expect(response).to.equal(
false,
'sendToGroup considered an invalid message type as valid'
);
5 years ago
// These should not be called; early exit
expect(sendMessageToDevicesSpy.callCount).to.equal(0);
expect(sendToOpenGroupSpy.callCount).to.equal(0);
});
5 years ago
it('can send to open group', async () => {
const message = TestUtils.generateOpenGroupMessage();
const success = await messageQueueStub.sendToGroup(message);
expect(success).to.equal(true, 'sending to group failed');
});
5 years ago
});
5 years ago
describe('MessageQueue events', () => {
console.log('[vince] messageQueueStub.events:', messageQueueStub);
console.log('[vince] messageQueueStub.events:', messageQueueStub);
// console.log('[vince] messageQueueStub.events:', messageQueueStub.events);
const successSpy = sandbox.spy();
messageQueueStub.events.on('success', successSpy);
// messageQueueStub.events.on('success', successSpy);
// const device = generateFakePubkey();
// const promise = messageQueueStub.processPending(device);
// expect(promise).to.be.fulfilled;
console.log('[vince] successSpy.callCount:', successSpy.callCount);
});
5 years ago
});