Merge pull request #1192 from Mikunj/send-to-group

Handle typing and expiration messages when sending to group
pull/1195/head
Mikunj Varsani 5 years ago committed by GitHub
commit 006b5760c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -417,13 +417,13 @@
libsession libsession
.getMessageQueue() .getMessageQueue()
.sendUsingMultiDevice(device, typingMessage) .sendUsingMultiDevice(device, typingMessage)
.ignore(); .catch(log.error);
} else { } else {
// the recipients on the case of a group are found by the messageQueue using message.groupId // the recipients on the case of a group are found by the messageQueue using message.groupId
libsession libsession
.getMessageQueue() .getMessageQueue()
.sendToGroup(typingMessage) .sendToGroup(typingMessage)
.ignore(); .catch(log.error);
} }
}, },
@ -1925,7 +1925,7 @@
libsession libsession
.getMessageQueue() .getMessageQueue()
.sendToGroup(groupUpdateMessage) .sendToGroup(groupUpdateMessage)
.ignore(); .catch(log.error);
}, },
sendGroupInfo(recipient) { sendGroupInfo(recipient) {
@ -1949,7 +1949,7 @@
libsession libsession
.getMessageQueue() .getMessageQueue()
.send(recipientPubKey, groupUpdateMessage) .send(recipientPubKey, groupUpdateMessage)
.ignore(); .catch(log.error);
} }
}, },

@ -96,7 +96,7 @@ describe('Conversation', () => {
it('adds conversation to message collection upon leaving group', async () => { it('adds conversation to message collection upon leaving group', async () => {
const convo = new Whisper.ConversationCollection().add({ const convo = new Whisper.ConversationCollection().add({
type: 'group', type: 'group',
id: 'a random string', id: '052d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab',
}); });
await convo.leaveGroup(); await convo.leaveGroup();
assert.notEqual(convo.messageCollection.length, 0); assert.notEqual(convo.messageCollection.length, 0);

@ -3,23 +3,26 @@ import { SignalService } from '../../../../protobuf';
import { TextEncoder } from 'util'; import { TextEncoder } from 'util';
import { MessageParams } from '../Message'; import { MessageParams } from '../Message';
import { StringUtils } from '../../../utils'; import { StringUtils } from '../../../utils';
import { PubKey } from '../../../types';
interface TypingMessageParams extends MessageParams { interface TypingMessageParams extends MessageParams {
isTyping: boolean; isTyping: boolean;
typingTimestamp?: number; typingTimestamp?: number;
groupId?: string; groupId?: string | PubKey;
} }
export class TypingMessage extends ContentMessage { export class TypingMessage extends ContentMessage {
private readonly isTyping: boolean; public readonly isTyping: boolean;
private readonly typingTimestamp?: number; public readonly typingTimestamp?: number;
private readonly groupId?: string; public readonly groupId?: PubKey;
constructor(params: TypingMessageParams) { constructor(params: TypingMessageParams) {
super({ timestamp: params.timestamp, identifier: params.identifier }); super({ timestamp: params.timestamp, identifier: params.identifier });
this.isTyping = params.isTyping; this.isTyping = params.isTyping;
this.typingTimestamp = params.typingTimestamp; this.typingTimestamp = params.typingTimestamp;
this.groupId = params.groupId;
const { groupId } = params;
this.groupId = groupId ? PubKey.cast(groupId) : undefined;
} }
public ttl(): number { public ttl(): number {
@ -41,7 +44,7 @@ export class TypingMessage extends ContentMessage {
const typingMessage = new SignalService.TypingMessage(); const typingMessage = new SignalService.TypingMessage();
if (this.groupId) { if (this.groupId) {
typingMessage.groupId = new Uint8Array( typingMessage.groupId = new Uint8Array(
StringUtils.encode(this.groupId, 'utf8') StringUtils.encode(this.groupId.key, 'utf8')
); );
} }
typingMessage.action = action; typingMessage.action = action;

@ -3,23 +3,26 @@ import { SignalService } from '../../../../../protobuf';
import { MessageParams } from '../../Message'; import { MessageParams } from '../../Message';
import { StringUtils } from '../../../../utils'; import { StringUtils } from '../../../../utils';
import { DataMessage } from './DataMessage'; import { DataMessage } from './DataMessage';
import { PubKey } from '../../../../types';
interface ExpirationTimerUpdateMessageParams extends MessageParams { interface ExpirationTimerUpdateMessageParams extends MessageParams {
groupId?: string; groupId?: string | PubKey;
expireTimer: number | null; expireTimer: number | null;
profileKey?: Uint8Array; profileKey?: Uint8Array;
} }
export class ExpirationTimerUpdateMessage extends DataMessage { export class ExpirationTimerUpdateMessage extends DataMessage {
private readonly groupId?: string; public readonly groupId?: PubKey;
private readonly expireTimer: number | null; public readonly expireTimer: number | null;
private readonly profileKey?: Uint8Array; public readonly profileKey?: Uint8Array;
constructor(params: ExpirationTimerUpdateMessageParams) { constructor(params: ExpirationTimerUpdateMessageParams) {
super({ timestamp: params.timestamp, identifier: params.identifier }); super({ timestamp: params.timestamp, identifier: params.identifier });
this.groupId = params.groupId;
this.expireTimer = params.expireTimer; this.expireTimer = params.expireTimer;
this.profileKey = params.profileKey; this.profileKey = params.profileKey;
const { groupId } = params;
this.groupId = groupId ? PubKey.cast(groupId) : undefined;
} }
public ttl(): number { public ttl(): number {
@ -32,7 +35,7 @@ export class ExpirationTimerUpdateMessage extends DataMessage {
const groupMessage = new SignalService.GroupContext(); const groupMessage = new SignalService.GroupContext();
if (this.groupId) { if (this.groupId) {
groupMessage.id = new Uint8Array( groupMessage.id = new Uint8Array(
StringUtils.encode(this.groupId, 'utf8') StringUtils.encode(this.groupId.key, 'utf8')
); );
groupMessage.type = SignalService.GroupContext.Type.DELIVER; groupMessage.type = SignalService.GroupContext.Type.DELIVER;
} }

@ -16,8 +16,7 @@ export abstract class ClosedGroupMessage extends DataMessage {
timestamp: params.timestamp, timestamp: params.timestamp,
identifier: params.identifier, identifier: params.identifier,
}); });
const { groupId } = params; this.groupId = PubKey.cast(params.groupId);
this.groupId = typeof groupId === 'string' ? new PubKey(groupId) : groupId;
} }
public ttl(): number { public ttl(): number {

@ -3,3 +3,4 @@ export * from './DeviceUnlinkMessage';
export * from './GroupInvitationMessage'; export * from './GroupInvitationMessage';
export * from './ChatMessage'; export * from './ChatMessage';
export * from './group'; export * from './group';
export * from './ExpirationTimerUpdateMessage';

@ -140,7 +140,7 @@ export class MultiDeviceProtocol {
public static async getPairingAuthorisations( public static async getPairingAuthorisations(
device: PubKey | string device: PubKey | string
): Promise<Array<PairingAuthorisation>> { ): Promise<Array<PairingAuthorisation>> {
const pubKey = typeof device === 'string' ? new PubKey(device) : device; const pubKey = PubKey.cast(device);
await this.fetchPairingAuthorisationsIfNeeded(pubKey); await this.fetchPairingAuthorisationsIfNeeded(pubKey);
return getPairingAuthorisationsFor(pubKey.key); return getPairingAuthorisationsFor(pubKey.key);
@ -153,7 +153,7 @@ export class MultiDeviceProtocol {
public static async removePairingAuthorisations( public static async removePairingAuthorisations(
device: PubKey | string device: PubKey | string
): Promise<void> { ): Promise<void> {
const pubKey = typeof device === 'string' ? new PubKey(device) : device; const pubKey = PubKey.cast(device);
return removePairingAuthorisationsFor(pubKey.key); return removePairingAuthorisationsFor(pubKey.key);
} }
@ -166,7 +166,7 @@ export class MultiDeviceProtocol {
public static async getAllDevices( public static async getAllDevices(
user: PubKey | string user: PubKey | string
): Promise<Array<PubKey>> { ): Promise<Array<PubKey>> {
const pubKey = typeof user === 'string' ? new PubKey(user) : user; const pubKey = PubKey.cast(user);
const authorisations = await this.getPairingAuthorisations(pubKey); const authorisations = await this.getPairingAuthorisations(pubKey);
if (authorisations.length === 0) { if (authorisations.length === 0) {
return [pubKey]; return [pubKey];
@ -190,7 +190,7 @@ export class MultiDeviceProtocol {
public static async getPrimaryDevice( public static async getPrimaryDevice(
user: PubKey | string user: PubKey | string
): Promise<PrimaryPubKey> { ): Promise<PrimaryPubKey> {
const pubKey = typeof user === 'string' ? new PubKey(user) : user; const pubKey = PubKey.cast(user);
const authorisations = await this.getPairingAuthorisations(pubKey); const authorisations = await this.getPairingAuthorisations(pubKey);
if (authorisations.length === 0) { if (authorisations.length === 0) {
return pubKey; return pubKey;
@ -237,7 +237,7 @@ export class MultiDeviceProtocol {
* @param device The device to check. * @param device The device to check.
*/ */
public static async isOurDevice(device: PubKey | string): Promise<boolean> { public static async isOurDevice(device: PubKey | string): Promise<boolean> {
const pubKey = typeof device === 'string' ? new PubKey(device) : device; const pubKey = PubKey.cast(device);
try { try {
const ourDevices = await this.getOurDevices(); const ourDevices = await this.getOurDevices();

@ -6,9 +6,11 @@ import {
import { import {
ClosedGroupMessage, ClosedGroupMessage,
ContentMessage, ContentMessage,
ExpirationTimerUpdateMessage,
OpenGroupMessage, OpenGroupMessage,
SessionRequestMessage, SessionRequestMessage,
SyncMessage, SyncMessage,
TypingMessage,
} from '../messages/outgoing'; } from '../messages/outgoing';
import { PendingMessageCache } from './PendingMessageCache'; import { PendingMessageCache } from './PendingMessageCache';
import { import {
@ -33,13 +35,16 @@ export class MessageQueue implements MessageQueueInterface {
void this.processAllPending(); void this.processAllPending();
} }
public async sendUsingMultiDevice(user: PubKey, message: ContentMessage) { public async sendUsingMultiDevice(
user: PubKey,
message: ContentMessage
): Promise<void> {
const userDevices = await MultiDeviceProtocol.getAllDevices(user.key); const userDevices = await MultiDeviceProtocol.getAllDevices(user.key);
await this.sendMessageToDevices(userDevices, message); await this.sendMessageToDevices(userDevices, message);
} }
public async send(device: PubKey, message: ContentMessage) { public async send(device: PubKey, message: ContentMessage): Promise<void> {
await this.sendMessageToDevices([device], message); await this.sendMessageToDevices([device], message);
} }
@ -75,26 +80,8 @@ export class MessageQueue implements MessageQueueInterface {
} }
public async sendToGroup( public async sendToGroup(
message: OpenGroupMessage | ClosedGroupMessage message: OpenGroupMessage | ContentMessage
): Promise<boolean> { ): Promise<void> {
// Closed groups
if (message instanceof ClosedGroupMessage) {
// Get devices in closed group
const recipients = await GroupUtils.getGroupMembers(message.groupId);
if (recipients.length === 0) {
return false;
}
// Send to all devices of members
await Promise.all(
recipients.map(async recipient =>
this.sendUsingMultiDevice(recipient, message)
)
);
return true;
}
// Open groups // Open groups
if (message instanceof OpenGroupMessage) { if (message instanceof OpenGroupMessage) {
// No queue needed for Open Groups; send directly // No queue needed for Open Groups; send directly
@ -108,20 +95,42 @@ export class MessageQueue implements MessageQueueInterface {
} else { } else {
this.events.emit('fail', message, error); this.events.emit('fail', message, error);
} }
return result;
} catch (e) { } catch (e) {
console.warn( console.warn(
`Failed to send message to open group: ${message.group.server}`, `Failed to send message to open group: ${message.group.server}`,
e e
); );
this.events.emit('fail', message, error); this.events.emit('fail', message, error);
}
return;
}
return false; let groupId: PubKey | undefined;
if (message instanceof ClosedGroupMessage) {
groupId = message.groupId;
} else if (message instanceof TypingMessage) {
groupId = message.groupId;
} else if (message instanceof ExpirationTimerUpdateMessage) {
groupId = message.groupId;
}
if (!groupId) {
throw new Error('Invalid group message passed in sendToGroup.');
} }
// Get devices in group
const recipients = await GroupUtils.getGroupMembers(groupId);
if (recipients.length === 0) {
return;
} }
return false; // Send to all devices of members
await Promise.all(
recipients.map(async recipient =>
this.sendUsingMultiDevice(recipient, message)
)
);
} }
public async sendSyncMessage(message: SyncMessage | undefined): Promise<any> { public async sendSyncMessage(message: SyncMessage | undefined): Promise<any> {

@ -17,8 +17,8 @@ export interface MessageQueueInterfaceEvents {
export interface MessageQueueInterface { export interface MessageQueueInterface {
events: TypedEventEmitter<MessageQueueInterfaceEvents>; events: TypedEventEmitter<MessageQueueInterfaceEvents>;
sendUsingMultiDevice(user: PubKey, message: ContentMessage): void; sendUsingMultiDevice(user: PubKey, message: ContentMessage): Promise<void>;
send(device: PubKey, message: ContentMessage): void; send(device: PubKey, message: ContentMessage): Promise<void>;
sendToGroup(message: GroupMessageType): void; sendToGroup(message: GroupMessageType): Promise<void>;
sendSyncMessage(message: SyncMessage | undefined): Promise<any>; sendSyncMessage(message: SyncMessage | undefined): Promise<any>;
} }

@ -5,11 +5,35 @@ export class PubKey {
); );
public readonly key: string; public readonly key: string;
/**
* A PubKey object.
* If `pubKeyString` is not valid then this will throw an `Error`.
*
* @param pubkeyString The public key string.
*/
constructor(pubkeyString: string) { constructor(pubkeyString: string) {
PubKey.validate(pubkeyString); if (!PubKey.validate(pubkeyString)) {
throw new Error(`Invalid pubkey string passed: ${pubkeyString}`);
}
this.key = pubkeyString; this.key = pubkeyString;
} }
/**
* Cast a `value` to a `PubKey`.
* If `value` is not valid then this will throw.
*
* @param value The value to cast.
*/
public static cast(value: string | PubKey): PubKey {
return typeof value === 'string' ? new PubKey(value) : value;
}
/**
* Try convert `pubKeyString` to `PubKey`.
*
* @param pubkeyString The public key string.
* @returns `PubKey` if valid otherwise returns `undefined`.
*/
public static from(pubkeyString: string): PubKey | undefined { public static from(pubkeyString: string): PubKey | undefined {
// Returns a new instance if the pubkey is valid // Returns a new instance if the pubkey is valid
if (PubKey.validate(pubkeyString)) { if (PubKey.validate(pubkeyString)) {

@ -6,22 +6,32 @@ import {
} from '../../../session/messages/outgoing'; } from '../../../session/messages/outgoing';
import { SignalService } from '../../../protobuf'; import { SignalService } from '../../../protobuf';
import { TextEncoder } from 'util'; import { TextEncoder } from 'util';
import { TestUtils } from '../../test-utils';
import { StringUtils } from '../../../session/utils';
import { PubKey } from '../../../session/types';
describe('ClosedGroupChatMessage', () => { describe('ClosedGroupChatMessage', () => {
let groupId: PubKey;
beforeEach(() => {
groupId = TestUtils.generateFakePubKey();
});
it('can create empty message with timestamp, groupId and chatMessage', () => { it('can create empty message with timestamp, groupId and chatMessage', () => {
const chatMessage = new ChatMessage({ const chatMessage = new ChatMessage({
timestamp: Date.now(), timestamp: Date.now(),
body: 'body', body: 'body',
}); });
const message = new ClosedGroupChatMessage({ const message = new ClosedGroupChatMessage({
groupId: '12', groupId,
chatMessage, chatMessage,
}); });
const plainText = message.plainTextBuffer(); const plainText = message.plainTextBuffer();
const decoded = SignalService.Content.decode(plainText); const decoded = SignalService.Content.decode(plainText);
expect(decoded.dataMessage) expect(decoded.dataMessage)
.to.have.property('group') .to.have.property('group')
.to.have.deep.property('id', new TextEncoder().encode('12')); .to.have.deep.property(
'id',
new Uint8Array(StringUtils.encode(groupId.key, 'utf8'))
);
expect(decoded.dataMessage) expect(decoded.dataMessage)
.to.have.property('group') .to.have.property('group')
.to.have.deep.property('type', SignalService.GroupContext.Type.DELIVER); .to.have.deep.property('type', SignalService.GroupContext.Type.DELIVER);
@ -39,7 +49,7 @@ describe('ClosedGroupChatMessage', () => {
timestamp: Date.now(), timestamp: Date.now(),
}); });
const message = new ClosedGroupChatMessage({ const message = new ClosedGroupChatMessage({
groupId: '12', groupId,
chatMessage, chatMessage,
}); });
expect(message.ttl()).to.equal(24 * 60 * 60 * 1000); expect(message.ttl()).to.equal(24 * 60 * 60 * 1000);
@ -50,7 +60,7 @@ describe('ClosedGroupChatMessage', () => {
timestamp: Date.now(), timestamp: Date.now(),
}); });
const message = new ClosedGroupChatMessage({ const message = new ClosedGroupChatMessage({
groupId: '12', groupId,
chatMessage, chatMessage,
}); });
expect(message.identifier).to.not.equal(null, 'identifier cannot be null'); expect(message.identifier).to.not.equal(null, 'identifier cannot be null');
@ -67,7 +77,7 @@ describe('ClosedGroupChatMessage', () => {
identifier: 'chatMessage', identifier: 'chatMessage',
}); });
const message = new ClosedGroupChatMessage({ const message = new ClosedGroupChatMessage({
groupId: '12', groupId,
chatMessage, chatMessage,
identifier: 'closedGroupMessage', identifier: 'closedGroupMessage',
}); });
@ -81,7 +91,7 @@ describe('ClosedGroupChatMessage', () => {
identifier: 'chatMessage', identifier: 'chatMessage',
}); });
const message = new ClosedGroupChatMessage({ const message = new ClosedGroupChatMessage({
groupId: '12', groupId,
chatMessage, chatMessage,
}); });
expect(message.identifier).to.be.equal('chatMessage'); expect(message.identifier).to.be.equal('chatMessage');

@ -5,6 +5,8 @@ import { SignalService } from '../../../protobuf';
import { TextEncoder } from 'util'; import { TextEncoder } from 'util';
import Long from 'long'; import Long from 'long';
import { toNumber } from 'lodash'; import { toNumber } from 'lodash';
import { StringUtils } from '../../../session/utils';
import { TestUtils } from '../../test-utils';
describe('TypingMessage', () => { describe('TypingMessage', () => {
it('has Action.STARTED if isTyping = true', () => { it('has Action.STARTED if isTyping = true', () => {
@ -60,7 +62,7 @@ describe('TypingMessage', () => {
}); });
it('has groupId set if a value given', () => { it('has groupId set if a value given', () => {
const groupId = '6666666666'; const groupId = TestUtils.generateFakePubKey();
const message = new TypingMessage({ const message = new TypingMessage({
timestamp: Date.now(), timestamp: Date.now(),
isTyping: true, isTyping: true,
@ -68,7 +70,9 @@ describe('TypingMessage', () => {
}); });
const plainText = message.plainTextBuffer(); const plainText = message.plainTextBuffer();
const decoded = SignalService.Content.decode(plainText); const decoded = SignalService.Content.decode(plainText);
const manuallyEncodedGroupId = new TextEncoder().encode(groupId); const manuallyEncodedGroupId = new Uint8Array(
StringUtils.encode(groupId.key, 'utf8')
);
expect(decoded.typingMessage?.groupId).to.be.deep.equal( expect(decoded.typingMessage?.groupId).to.be.deep.equal(
manuallyEncodedGroupId manuallyEncodedGroupId

@ -12,7 +12,7 @@ import { PubKey } from '../../../session/types';
describe('SessionProtocol', () => { describe('SessionProtocol', () => {
const sandbox = sinon.createSandbox(); const sandbox = sinon.createSandbox();
const ourNumber = 'ourNumber'; const ourNumber = 'ourNumber';
const pubkey = new PubKey('deviceid'); const pubkey = TestUtils.generateFakePubKey();
let getItemById: sinon.SinonStub; let getItemById: sinon.SinonStub;
let send: sinon.SinonStub; let send: sinon.SinonStub;
@ -88,14 +88,14 @@ describe('SessionProtocol', () => {
it('protocol: sendSessionRequest should add the deviceID to the sentMap', async () => { it('protocol: sendSessionRequest should add the deviceID to the sentMap', async () => {
expect(SessionProtocol.getSentSessionsTimestamp()) expect(SessionProtocol.getSentSessionsTimestamp())
.to.have.property('deviceid') .to.have.property(pubkey.key)
.to.be.approximately(Date.now(), 100); .to.be.approximately(Date.now(), 100);
}); });
it('protocol: sendSessionRequest should not have pendingSend set after', async () => { it('protocol: sendSessionRequest should not have pendingSend set after', async () => {
expect( expect(
SessionProtocol.getPendingSendSessionTimestamp() SessionProtocol.getPendingSendSessionTimestamp()
).to.not.have.property('deviceid'); ).to.not.have.property(pubkey.key);
}); });
}); });
@ -107,34 +107,32 @@ describe('SessionProtocol', () => {
it('protocol: onSessionEstablished should remove the device in sentTimestamps', async () => { it('protocol: onSessionEstablished should remove the device in sentTimestamps', async () => {
expect(SessionProtocol.getSentSessionsTimestamp()).to.have.property( expect(SessionProtocol.getSentSessionsTimestamp()).to.have.property(
'deviceid' pubkey.key
); );
await SessionProtocol.onSessionEstablished(pubkey); await SessionProtocol.onSessionEstablished(pubkey);
expect(SessionProtocol.getSentSessionsTimestamp()).to.not.have.property( expect(SessionProtocol.getSentSessionsTimestamp()).to.not.have.property(
'deviceid' pubkey.key
); );
}); });
it('protocol: onSessionEstablished should remove the device in sentTimestamps and ONLY that one', async () => { it('protocol: onSessionEstablished should remove the device in sentTimestamps and ONLY that one', async () => {
// add a second item to the map // add a second item to the map
await SessionProtocol.sendSessionRequest( const anotherPubKey = TestUtils.generateFakePubKey();
resetMessage, await SessionProtocol.sendSessionRequest(resetMessage, anotherPubKey);
new PubKey('deviceid2')
);
expect(SessionProtocol.getSentSessionsTimestamp()).to.have.property( expect(SessionProtocol.getSentSessionsTimestamp()).to.have.property(
'deviceid' pubkey.key
); );
expect(SessionProtocol.getSentSessionsTimestamp()).to.have.property( expect(SessionProtocol.getSentSessionsTimestamp()).to.have.property(
'deviceid2' anotherPubKey.key
); );
await SessionProtocol.onSessionEstablished(pubkey); await SessionProtocol.onSessionEstablished(pubkey);
expect(SessionProtocol.getSentSessionsTimestamp()).to.not.have.property( expect(SessionProtocol.getSentSessionsTimestamp()).to.not.have.property(
'deviceid' pubkey.key
); );
expect(SessionProtocol.getSentSessionsTimestamp()).to.have.property( expect(SessionProtocol.getSentSessionsTimestamp()).to.have.property(
'deviceid2' anotherPubKey.key
); );
}); });
}); });
@ -144,7 +142,7 @@ describe('SessionProtocol', () => {
const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey); const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey);
expect(hasSent).to.be.equal( expect(hasSent).to.be.equal(
false, false,
'hasSent should be false for `deviceid`' `hasSent should be false for ${pubkey.key}`
); );
}); });
@ -154,7 +152,7 @@ describe('SessionProtocol', () => {
const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey); const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey);
expect(hasSent).to.be.equal( expect(hasSent).to.be.equal(
true, true,
'hasSent should be true for `deviceid`' `hasSent should be true for ${pubkey.key}`
); );
}); });
@ -174,7 +172,7 @@ describe('SessionProtocol', () => {
const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey); const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey);
expect(hasSent).to.be.equal( expect(hasSent).to.be.equal(
true, true,
'hasSent should be true for `deviceid`' `hasSent should be true for ${pubkey.key}`
); );
}); });
@ -189,7 +187,7 @@ describe('SessionProtocol', () => {
const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey); const hasSent = await SessionProtocol.hasSentSessionRequest(pubkey);
expect(hasSent).to.be.equal( expect(hasSent).to.be.equal(
true, true,
'hasSent should be true for `deviceid`' `hasSent should be true for ${pubkey.key}`
); );
send.resetHistory(); send.resetHistory();
@ -207,7 +205,7 @@ describe('SessionProtocol', () => {
// trigger the requestProcessed and check the map is updated // trigger the requestProcessed and check the map is updated
await SessionProtocol.onSessionRequestProcessed(pubkey); await SessionProtocol.onSessionRequestProcessed(pubkey);
expect(SessionProtocol.getProcessedSessionsTimestamp()) expect(SessionProtocol.getProcessedSessionsTimestamp())
.to.have.property('deviceid') .to.have.property(pubkey.key)
.to.be.approximately(Date.now(), 5); .to.be.approximately(Date.now(), 5);
}); });
@ -217,14 +215,15 @@ describe('SessionProtocol', () => {
await SessionProtocol.onSessionRequestProcessed(pubkey); await SessionProtocol.onSessionRequestProcessed(pubkey);
expect(SessionProtocol.getProcessedSessionsTimestamp()) expect(SessionProtocol.getProcessedSessionsTimestamp())
.to.have.property('deviceid') .to.have.property(pubkey.key)
.to.be.approximately(Date.now(), 5); .to.be.approximately(Date.now(), 5);
await TestUtils.timeout(5); await TestUtils.timeout(5);
const oldTimestamp = SessionProtocol.getProcessedSessionsTimestamp() const oldTimestamp = SessionProtocol.getProcessedSessionsTimestamp()[
.deviceid; pubkey.key
];
await SessionProtocol.onSessionRequestProcessed(pubkey); await SessionProtocol.onSessionRequestProcessed(pubkey);
expect(SessionProtocol.getProcessedSessionsTimestamp()) expect(SessionProtocol.getProcessedSessionsTimestamp())
.to.have.property('deviceid') .to.have.property(pubkey.key)
.to.be.approximately(Date.now(), 5) .to.be.approximately(Date.now(), 5)
.to.not.be.equal(oldTimestamp); .to.not.be.equal(oldTimestamp);
}); });

@ -312,6 +312,13 @@ describe('MessageQueue', () => {
}); });
describe('sendToGroup', () => { describe('sendToGroup', () => {
it('should throw an error if invalid non-group message was passed', async () => {
const chatMessage = TestUtils.generateChatMessage();
await expect(
messageQueueStub.sendToGroup(chatMessage)
).to.be.rejectedWith('Invalid group message passed in sendToGroup.');
});
describe('closed groups', async () => { describe('closed groups', async () => {
it('can send to closed group', async () => { it('can send to closed group', async () => {
const members = TestUtils.generateFakePubKeys(4).map( const members = TestUtils.generateFakePubKeys(4).map(
@ -324,8 +331,7 @@ describe('MessageQueue', () => {
.resolves(); .resolves();
const message = TestUtils.generateClosedGroupMessage(); const message = TestUtils.generateClosedGroupMessage();
const success = await messageQueueStub.sendToGroup(message); await messageQueueStub.sendToGroup(message);
expect(success).to.equal(true, 'sending to group failed');
expect(sendUsingMultiDeviceStub.callCount).to.equal(members.length); expect(sendUsingMultiDeviceStub.callCount).to.equal(members.length);
const arg = sendUsingMultiDeviceStub.getCall(0).args; const arg = sendUsingMultiDeviceStub.getCall(0).args;
@ -342,12 +348,7 @@ describe('MessageQueue', () => {
.resolves(); .resolves();
const message = TestUtils.generateClosedGroupMessage(); const message = TestUtils.generateClosedGroupMessage();
const response = await messageQueueStub.sendToGroup(message); await messageQueueStub.sendToGroup(message);
expect(response).to.equal(
false,
'sendToGroup sent a message to an empty group'
);
expect(sendUsingMultiDeviceStub.callCount).to.equal(0); expect(sendUsingMultiDeviceStub.callCount).to.equal(0);
}); });
}); });
@ -365,9 +366,8 @@ describe('MessageQueue', () => {
it('can send to open group', async () => { it('can send to open group', async () => {
const message = TestUtils.generateOpenGroupMessage(); const message = TestUtils.generateOpenGroupMessage();
const success = await messageQueueStub.sendToGroup(message); await messageQueueStub.sendToGroup(message);
expect(sendToOpenGroupStub.callCount).to.equal(1); expect(sendToOpenGroupStub.callCount).to.equal(1);
expect(success).to.equal(true, 'Sending to open group failed');
}); });
it('should emit a success event when send was successful', async () => { it('should emit a success event when send was successful', async () => {

Loading…
Cancel
Save