Add tests

This commit is contained in:
Mikunj 2020-06-01 15:04:09 +10:00
parent b644e2a05f
commit 736cbc06da
6 changed files with 123 additions and 37 deletions

View file

@ -1,7 +1,8 @@
/* global window, setTimeout, clearTimeout, IDBKeyRange, dcodeIO */
const electron = require('electron');
const { ipcRenderer } = electron;
// TODO: this results in poor readability, would be
// much better to explicitly call with `_`.
const {
@ -21,12 +22,6 @@ const _ = require('lodash');
const { base64ToArrayBuffer, arrayBufferToBase64 } = require('./crypto');
const MessageType = require('./types/message');
const { ipcRenderer } = electron;
// We listen to a lot of events on ipcRenderer, often on the same channel. This prevents
// any warnings that might be sent to the console in that case.
ipcRenderer.setMaxListeners(0);
const DATABASE_UPDATE_TIMEOUT = 2 * 60 * 1000; // two minutes
const SQL_CHANNEL_KEY = 'sql-channel';
@ -44,6 +39,7 @@ let _shutdownPromise = null;
const channels = {};
module.exports = {
init,
_jobs,
_cleanData,
@ -212,6 +208,42 @@ module.exports = {
createOrUpdateSenderKeys,
};
function init() {
// We listen to a lot of events on ipcRenderer, often on the same channel. This prevents
// any warnings that might be sent to the console in that case.
ipcRenderer.setMaxListeners(0);
forEach(module.exports, fn => {
if (isFunction(fn) && fn.name !== 'init') {
makeChannel(fn.name);
}
});
ipcRenderer.on(
`${SQL_CHANNEL_KEY}-done`,
(event, jobId, errorForDisplay, result) => {
const job = _getJob(jobId);
if (!job) {
throw new Error(
`Received SQL channel reply to job ${jobId}, but did not have it in our registry!`
);
}
const { resolve, reject, fnName } = job;
if (errorForDisplay) {
return reject(
new Error(
`Error received from SQL channel job ${jobId} (${fnName}): ${errorForDisplay}`
)
);
}
return resolve(result);
}
);
}
// When IPC arguments are prepared for the cross-process send, they are JSON.stringified.
// We can't send ArrayBuffers or BigNumbers (what we get from proto library for dates).
function _cleanData(data) {
@ -352,30 +384,6 @@ function _getJob(id) {
return _jobs[id];
}
ipcRenderer.on(
`${SQL_CHANNEL_KEY}-done`,
(event, jobId, errorForDisplay, result) => {
const job = _getJob(jobId);
if (!job) {
throw new Error(
`Received SQL channel reply to job ${jobId}, but did not have it in our registry!`
);
}
const { resolve, reject, fnName } = job;
if (errorForDisplay) {
return reject(
new Error(
`Error received from SQL channel job ${jobId} (${fnName}): ${errorForDisplay}`
)
);
}
return resolve(result);
}
);
function makeChannel(fnName) {
channels[fnName] = (...args) => {
const jobId = _makeJob(fnName);
@ -398,12 +406,6 @@ function makeChannel(fnName) {
};
}
forEach(module.exports, fn => {
if (isFunction(fn)) {
makeChannel(fn.name);
}
});
function keysToArrayBuffer(keys, data) {
const updated = cloneDeep(data);
for (let i = 0, max = keys.length; i < max; i += 1) {

View file

@ -263,6 +263,8 @@ function initializeMigrations({
exports.setup = (options = {}) => {
const { Attachments, userDataPath, getRegionCode, logger } = options;
Data.init();
const Migrations = initializeMigrations({
userDataPath,
getRegionCode,

View file

@ -0,0 +1,47 @@
import { expect } from 'chai';
import * as crypto from 'crypto';
import * as sinon from 'sinon';
import * as window from '../../../window';
import { MessageEncrypter } from '../../../session/crypto';
import { EncryptionType } from '../../../session/types/EncryptionType';
describe('MessageEncrypter', () => {
const sandbox = sinon.sandbox.create();
beforeEach(() => {
sandbox.stub(window);
});
afterEach(() => {
sandbox.restore();
});
describe('EncryptionType', () => {
describe('MediumGroup', () => {
it('should throw an error', async () => {
const data = crypto.randomBytes(10);
const promise = MessageEncrypter.encrypt('1', data, EncryptionType.MediumGroup);
await expect(promise).to.be.rejectedWith('Encryption is not yet supported');
});
});
/*
describe('SessionReset', () => {
it('should call FallbackSessionCipher', async () => {
});
it('should pass the padded message body to encrypt', async () => {
});
});
describe('Signal', () => {
it('should call SessionCipher', async () => {
});
it('should pass the padded message body to encrypt', async () => {
});
});
*/
});
});

View file

@ -0,0 +1,27 @@
import { SignalProtocolAddress } from "../../../../libtextsecure/libsignal-protocol";
export class SignalProtocolAddressStub extends SignalProtocolAddress {
private readonly hexEncodedPublicKey: string;
private readonly deviceId: number;
constructor(hexEncodedPublicKey: string, deviceId: number) {
super(hexEncodedPublicKey, deviceId);
this.hexEncodedPublicKey = hexEncodedPublicKey;
this.deviceId = deviceId;
}
// tslint:disable-next-line: function-name
public static fromString(encodedAddress: string): SignalProtocolAddressStub {
const values = encodedAddress.split('.');
return new SignalProtocolAddressStub(values[0], Number(values[1]));
}
public getName(): string { return this.hexEncodedPublicKey; }
public getDeviceId(): number { return this.deviceId; }
public equals(other: SignalProtocolAddress): boolean {
return other.getName() === this.hexEncodedPublicKey;
}
public toString(): string { return this.hexEncodedPublicKey; }
}

View file

@ -0,0 +1 @@
export * from './SignalAddressProtocolStub';

View file

@ -74,6 +74,13 @@ interface WindowInterface extends Window {
resetDatabase: any;
}
// In the case for tests
// tslint:disable-next-line: no-typeof-undefined
if (typeof(window) === 'undefined') {
const globalAny: any = global;
globalAny.window = {};
}
declare const window: WindowInterface;
// TODO: Is there an easier way to dynamically export these?