chore: fix unit tests

pull/2620/head
Audric Ackermann 2 years ago
parent 55a2767fce
commit dc329668fa

@ -44,7 +44,8 @@
"format-full": "prettier --list-different --write \"*.{css,js,json,scss,ts,tsx}\" \"./**/*.{css,js,json,scss,ts,tsx}\"",
"integration-test": "npx playwright test",
"integration-test-snapshots": "npx playwright test -g 'profile picture' --update-snapshots",
"test": "mocha -r jsdom-global/register --recursive --exit --timeout 10000 \"./ts/test/**/*_test.js\"",
"rebuild-libsession-for-unit-tests": "cd node_modules/session_util_wrapper/ && yarn configure && yarn build && cd ../../ ",
"test": "yarn rebuild-libsession-for-unit-tests && mocha -r jsdom-global/register --recursive --exit --timeout 10000 \"./ts/test/**/*_test.js\"",
"coverage": "nyc --reporter=html mocha -r jsdom-global/register --recursive --exit --timeout 10000 \"./ts/test/**/*_test.js\"",
"build-release": "run-script-os",
"build-release-non-linux": "yarn build-everything && cross-env SIGNAL_ENV=production electron-builder --config.extraMetadata.environment=production --publish=never --config.directories.output=release",
@ -274,11 +275,7 @@
"StartupWMClass": "Session"
},
"asarUnpack": "node_modules/spellchecker/vendor/hunspell_dictionaries",
"target": [
"deb",
"rpm",
"freebsd"
],
"target": ["deb", "rpm", "freebsd"],
"icon": "build/icon-linux.icns"
},
"asarUnpack": [

@ -269,7 +269,7 @@ export class SwarmPolling {
const messages = uniqBy(allNamespacesWithoutUserConfigIfNeeded, x => x.hash);
// if all snodes returned an error (null), no need to update the lastPolledTimestamp
if (isGroup && allNamespacesWithoutUserConfigIfNeeded?.length) {
if (isGroup) {
window?.log?.info(
`Polled for group(${ed25519Str(pubkey.key)}):, got ${messages.length} messages back.`
);

@ -238,12 +238,17 @@ export class ConversationController {
// remove from the wrapper the entries before we remove the roomInfos, as we won't have the required community pubkey afterwards
try {
await SessionUtilUserGroups.removeCommunityFromWrapper(conversation.id, conversation.id);
} catch (e) {
window?.log?.info('SessionUtilUserGroups.removeCommunityFromWrapper failed:', e);
}
try {
await SessionUtilConvoInfoVolatile.removeCommunityFromWrapper(
conversation.id,
conversation.id
);
} catch (e) {
window?.log?.info('SessionUtilUserGroups.removeCommunityFromWrapper failed:', e);
window?.log?.info('SessionUtilConvoInfoVolatile.removeCommunityFromWrapper failed:', e);
}
const roomInfos = OpenGroupData.getV2OpenGroupRoom(conversation.id);

@ -34,7 +34,6 @@ function jobToLogId<T extends TypeOfPersistedData>(jobRunner: JobRunnerType, job
*
* SyncConfigurationJob is a job which can only be planned once until it is a success. So in the queue on jobs, there can only be one SyncConfigurationJob at all times.
*
*
*/
export class PersistedJobRunner<T extends TypeOfPersistedData> {
private isInit = false;
@ -133,6 +132,10 @@ export class PersistedJobRunner<T extends TypeOfPersistedData> {
this.currentJob = null;
}
public getCurrentJobIdentifier(): string | null {
return this.currentJob?.persistedData?.identifier || null;
}
/**
* if we are running a job, this call will await until the job is done and stop the queue
*/

@ -30,6 +30,7 @@ import { PubKey } from '../../types';
import { ConfigurationDumpSync } from '../job_runners/jobs/ConfigurationSyncDumpJob';
import { ConfigurationSync } from '../job_runners/jobs/ConfigurationSyncJob';
import { fromBase64ToArray, fromHexToArray } from '../String';
import { getCompleteUrlFromRoom } from '../../apis/open_group_api/utils/OpenGroupUtils';
const ITEM_ID_LAST_SYNC_TIMESTAMP = 'lastSyncedTimestamp';
@ -141,8 +142,9 @@ const getActiveOpenGroupV2CompleteUrls = async (
const urls = await Promise.all(
openGroupsV2ConvoIds.map(async opengroupConvoId => {
const roomInfos = OpenGroupData.getV2OpenGroupRoom(opengroupConvoId);
if (roomInfos) {
return opengroupConvoId;
return getCompleteUrlFromRoom(roomInfos);
}
return null;
})

@ -1,6 +1,5 @@
import { expect } from 'chai';
import { from_hex, from_string } from 'libsodium-wrappers-sumo';
import Sinon from 'sinon';
import { ConversationModel } from '../../../../models/conversation';
import {
@ -22,290 +21,6 @@ describe('libsession_contacts', () => {
// We have to disable it by filename as nodejs tries to load the module during the import step above, and fails as it is not compiled for nodejs but for electron.
it('libsession_contacts1', () => {
const edSecretKey = from_hex(
'0123456789abcdef0123456789abcdef000000000000000000000000000000004cb76fdc6d32278e3f83dbf608360ecc6b65727934b85d2fb86862ff98c46ab7'
);
const SessionUtilWrapper = require('session_util_wrapper');
// Initialize a brand new, empty config because we have no dump data to deal with.
const contacts = new SessionUtilWrapper.ContactsConfigWrapperInsideWorker(edSecretKey, null);
// We don't need to push anything, since this is an empty config
expect(contacts.needsPush()).to.be.eql(false);
expect(contacts.needsDump()).to.be.eql(false);
const real_id = '050000000000000000000000000000000000000000000000000000000000000000';
// Since it's empty there shouldn't be a get result.
expect(contacts.get(real_id)).to.be.null;
const created = contacts.getOrCreate(real_id);
expect(created).to.be.not.null;
expect(created.id).to.be.eq(real_id);
expect(created.name).to.be.null;
expect(created.nickname).to.be.null;
expect(created.approved).to.be.eq(false);
expect(created.approvedMe).to.be.eq(false);
expect(created.blocked).to.be.eq(false);
expect(created.id).to.be.eq(real_id);
expect(created.profilePicture?.url).to.be.eq(undefined);
expect(created.profilePicture?.key).to.be.eq(undefined);
expect(contacts.needsPush()).to.be.eql(false);
expect(contacts.needsDump()).to.be.eql(false);
expect(contacts.push().seqno === 0);
created.name = 'Joe';
created.nickname = 'Joey';
created.approved = true;
created.approvedMe = true;
contacts.set(created);
const updated = contacts.get(real_id);
expect(updated).to.not.be.null;
expect(updated).to.not.be.undefined;
expect(updated?.id).to.be.eq(real_id);
expect(updated?.name).to.be.eq('Joe');
expect(updated?.nickname).to.be.eq('Joey');
expect(updated?.approved).to.be.true;
expect(updated?.approvedMe).to.be.true;
expect(updated?.blocked).to.be.false;
expect(updated?.profilePicture).to.be.undefined;
const plop = new Uint8Array(32).fill(6);
created.profilePicture = { key: plop, url: 'fakeUrl' };
contacts.set(created);
const updated2 = contacts.get(real_id);
expect(updated2?.profilePicture?.url).to.be.deep.eq('fakeUrl');
expect(updated2?.profilePicture?.key).to.be.deep.eq(plop);
expect(contacts.needsPush()).to.be.eql(true);
expect(contacts.needsDump()).to.be.eql(true);
let push1 = contacts.push();
expect(push1.seqno).to.be.eq(1);
// Pretend we uploaded it
contacts.confirmPushed(push1.seqno);
expect(contacts.needsPush()).to.be.eql(false);
expect(contacts.needsDump()).to.be.eql(true);
const dump = contacts.dump();
const contacts2 = new SessionUtilWrapper.ContactsConfigWrapperInsideWorker(edSecretKey, dump);
expect(contacts2.needsPush()).to.be.eql(false);
expect(contacts2.needsDump()).to.be.eql(false);
expect(contacts2.push().seqno).to.be.eq(1);
// Because we just called dump() above, to load up
// contacts2.
expect(contacts2.needsDump()).to.be.eql(false);
const x = contacts2.get(real_id);
expect(x?.id).to.be.eq(real_id);
expect(x?.name).to.be.eq('Joe');
expect(x?.nickname).to.be.eq('Joey');
expect(x?.approved).to.be.true;
expect(x?.approvedMe).to.be.true;
expect(x?.blocked).to.be.false;
const anotherId = '051111111111111111111111111111111111111111111111111111111111111111';
contacts2.getOrCreate(anotherId);
contacts2.set({
id: anotherId,
});
// We're not setting any fields, but we should still keep a record of the session id
expect(contacts2.needsPush()).to.be.true;
let push2 = contacts2.push();
push1.seqno = push2.seqno;
push1.data = push2.data;
expect(push1.seqno).to.be.equal(2);
contacts.merge([push1.data]);
contacts2.confirmPushed(push1.seqno);
expect(contacts.needsPush()).to.be.false;
expect(contacts.push().seqno).to.be.eq(push1.seqno);
// Iterate through and make sure we got everything we expected
const allContacts = contacts.getAll();
const session_ids = allContacts.map((m: any) => m.id);
const nicknames = allContacts.map((m: any) => m.nickname || '(N/A)');
expect(session_ids.length).to.be.eq(2);
expect(session_ids).to.be.deep.eq([real_id, anotherId]);
expect(nicknames).to.be.deep.eq(['Joey', '(N/A)']);
// Conflict! Oh no!
// On client 1 delete a contact:
contacts.erase(real_id);
const shouldBeErased = contacts.get(real_id);
expect(shouldBeErased).to.be.null;
// Client 2 adds a new friend:
const third_id = '052222222222222222222222222222222222222222222222222222222222222222';
contacts2.setNickname(third_id, 'Nickname 3');
contacts2.setApproved(third_id, true);
contacts2.setBlocked(third_id, true);
contacts2.setProfilePicture(
third_id,
'http://example.com/huge.bmp',
from_string('qwert\0yuio1234567890123456789012')
);
expect(contacts.needsPush()).to.be.true;
expect(contacts2.needsPush()).to.be.true;
push1 = contacts.push();
push2 = contacts2.push();
expect(push1.seqno).to.be.eq(push2.seqno);
expect(push1.data).to.not.be.deep.eq(push2.data);
contacts.confirmPushed(push1.seqno);
contacts2.confirmPushed(push2.seqno);
contacts.merge([push2.data]);
expect(contacts.needsPush()).to.be.true;
contacts2.merge([push1.data]);
expect(contacts2.needsPush()).to.be.true;
push1 = contacts.push();
expect(push1.seqno).to.be.eq(push2.seqno + 1);
push2 = contacts2.push();
expect(push1.seqno).to.be.deep.eq(push2.seqno);
expect(push1.data).to.be.deep.eq(push2.data);
contacts.confirmPushed(push1.seqno);
contacts2.confirmPushed(push2.seqno);
expect(contacts.needsPush()).to.be.false;
expect(contacts2.needsPush()).to.be.false;
const allContacts2 = contacts.getAll();
const sessionIds2 = allContacts2.map((m: any) => m.id);
const nicknames2 = allContacts2.map((m: any) => m.nickname || '(N/A)');
expect(sessionIds2.length).to.be.eq(2);
expect(nicknames2.length).to.be.eq(2);
expect(sessionIds2).to.be.deep.eq([anotherId, third_id]);
expect(nicknames2).to.be.deep.eq(['(N/A)', 'Nickname 3']);
});
it('libsession_contacts2_c', () => {
const edSecretKey = from_hex(
'0123456789abcdef0123456789abcdef000000000000000000000000000000004cb76fdc6d32278e3f83dbf608360ecc6b65727934b85d2fb86862ff98c46ab7'
);
const SessionUtilWrapper = require('session_util_wrapper');
// Initialize a brand new, empty config because we have no dump data to deal with.
const contacts = new SessionUtilWrapper.ContactsConfigWrapperInsideWorker(edSecretKey, null);
const realId = '050000000000000000000000000000000000000000000000000000000000000000';
expect(contacts.get(realId)).to.be.null;
const c = contacts.getOrCreate(realId);
expect(c.id).to.be.eq(realId);
expect(c.name).to.be.null;
expect(c.nickname).to.be.null;
expect(c.approved).to.be.false;
expect(c.approvedMe).to.be.false;
expect(c.blocked).to.be.false;
expect(c.profilePicture?.key).to.be.undefined;
expect(c.profilePicture?.url).to.be.undefined;
c.name = 'Joe';
c.nickname = 'Joey';
c.approved = true;
c.approvedMe = true;
contacts.set(c);
const c2 = contacts.getOrCreate(realId);
expect(c2.name).to.be.eq('Joe');
expect(c2.nickname).to.be.eq('Joey');
expect(c2.approved).to.be.true;
expect(c2.approvedMe).to.be.true;
expect(c2.blocked).to.be.false;
expect(c2.profilePicture?.key).to.be.undefined;
expect(c2.profilePicture?.url).to.be.undefined;
expect(contacts.needsDump()).to.be.true;
expect(contacts.needsPush()).to.be.true;
const push1 = contacts.push();
expect(push1.seqno).to.be.equal(1);
const contacts2 = new SessionUtilWrapper.ContactsConfigWrapperInsideWorker(edSecretKey, null);
let accepted = contacts2.merge([push1.data]);
expect(accepted).to.be.equal(1);
contacts.confirmPushed(push1.seqno);
let c3 = contacts2.getOrCreate(realId);
expect(c3.name).to.be.eq('Joe');
expect(c3.nickname).to.be.eq('Joey');
expect(c3.approved).to.be.true;
expect(c3.approvedMe).to.be.true;
expect(c3.blocked).to.be.false;
expect(c3.profilePicture?.key).to.be.undefined;
expect(c3.profilePicture?.url).to.be.undefined;
const another_id = '051111111111111111111111111111111111111111111111111111111111111111';
c3 = contacts.getOrCreate(another_id);
expect(c3.name).to.be.null;
expect(c3.nickname).to.be.null;
expect(c3.approved).to.be.false;
expect(c3.approvedMe).to.be.false;
expect(c3.blocked).to.be.false;
expect(c3.profilePicture?.key).to.be.undefined;
expect(c3.profilePicture?.url).to.be.undefined;
contacts2.set(c3);
const push2 = contacts2.push();
accepted = contacts.merge([push2.data]);
expect(accepted).to.be.equal(1);
const allContacts2 = contacts.getAll();
const session_ids2 = allContacts2.map((m: any) => m.id);
const nicknames2 = allContacts2.map((m: any) => m.nickname || '(N/A)');
expect(session_ids2.length).to.be.eq(2);
expect(nicknames2.length).to.be.eq(2);
expect(session_ids2).to.be.deep.eq([realId, another_id]);
expect(nicknames2).to.be.deep.eq(['Joey', '(N/A)']);
// Changing things while iterating:
// no need to support this in JS for now.
const allContacts3 = contacts.getAll();
let deletions = 0;
let non_deletions = 0;
allContacts3.forEach((contact: any) => {
if (contact.id !== realId) {
contacts.erase(contact.id);
deletions++;
} else {
non_deletions++;
}
});
expect(deletions).to.be.eq(1);
expect(non_deletions).to.be.eq(1);
expect(contacts.get(realId)).to.exist;
expect(contacts.get(another_id)).to.be.null;
});
describe('filter contacts for wrapper', () => {
const ourNumber = '051234567890acbdef';
const validArgs = {

@ -1,217 +1,24 @@
import { expect } from 'chai';
import { stringToUint8Array } from '../../../../session/utils/String';
import { from_hex, from_string, to_hex } from 'libsodium-wrappers-sumo';
import { concatUInt8Array } from '../../../../session/crypto';
// tslint:disable: chai-vague-errors no-unused-expression no-http-string no-octal-literal whitespace no-require-imports variable-name
const fakeKey32 = from_string('secret78901234567890123456789012');
import { SessionUtilUserProfile } from '../../../../session/utils/libsession/libsession_utils_user_profile';
import Sinon from 'sinon';
import { UserUtils } from '../../../../session/utils';
import { TestUtils } from '../../../test-utils';
describe('libsession_wrapper', () => {
it('libsession_user', () => {
// Note: To run this test, you need to compile the libsession wrapper for node (and not for electron).
// To do this, you can cd to the node_module/libsession_wrapper folder and do
// yarn configure && yarn build
// once that is done, you can rename this file and remove the _skip suffix so that test is run.
// We have to disable it by filename as nodejs tries to load the module during the import step above, and fails as it is not compiled for nodejs but for electron.
const edSecretKey = from_hex(
'0123456789abcdef0123456789abcdef000000000000000000000000000000004cb76fdc6d32278e3f83dbf608360ecc6b65727934b85d2fb86862ff98c46ab7'
);
const SessionUtilWrapper = require('session_util_wrapper');
// Initialize a brand new, empty config because we have no dump data to deal with.
const conf = new SessionUtilWrapper.UserConfigWrapperInsideWorker(edSecretKey, null);
// We don't need to push anything, since this is an empty config
expect(conf.needsPush()).to.be.eql(false);
expect(conf.needsDump()).to.be.eql(false);
// Since it's empty there shouldn't be a name.
expect(conf.getName()).to.be.null;
let pushResult = conf.push();
expect(pushResult.seqno).to.be.eq(0);
expect(pushResult.data.length).to.be.eq(256);
expect(conf.storageNamespace()).to.be.eq(2);
expect(to_hex(pushResult.data)).to.be.deep.eq(
'9ffb5347e061ac40d937ae4f1a890031475bdc11653f94c8ae1d516ffda71d9ee9cdaf9fbaeb15d835cdc7b3b6ecc120361f004ff172dd5e757c80ede10e88945536e6841255a7bca73664ab8a0607fcfe2579c05bb3d9d4b34ac1de2921e703783ce39e317a512cb9d4e3b59176cbde47b5ba24a03065bf8fefe3e8ca2609e0ad10c7c9c3f81dc6d3a399bda0c190e8a228d0acb22863ab84c2d0c411be74dac4de1f8bc18539635db01ea1ef7f28e505703d67786cb419690edd4bd8c92926fc1d6449eaccc31d7d9639e1b36222e5672b87d1e34b7860308c3f40b3997f39fecf6ceb889323826fa69e001816307799fc9fed302a90faa1e43f7cd7367c3c'
);
// This should also be unset:
const picResult = conf.getProfilePicture();
expect(picResult.url).to.be.null;
expect(picResult.key).to.be.null;
// Now let's go set a profile name and picture:
conf.setProfilePicture('http://example.org/omg-pic-123.bmp', new Uint8Array(fakeKey32));
expect(conf.getProfilePicture().key).to.be.deep.eq(new Uint8Array(fakeKey32));
conf.setName('Kallie');
// Retrieve them just to make sure they set properly:
const name = conf.getName();
expect(name).to.be.not.null;
expect(name).to.be.eq('Kallie');
const picture = conf.getProfilePicture();
expect(picture.url).to.be.eq('http://example.org/omg-pic-123.bmp');
expect(picture.key).to.be.deep.eq(new Uint8Array(fakeKey32));
// Since we've made changes, we should need to push new config to the swarm, *and* should need
// to dump the updated state:
expect(conf.needsDump()).to.be.true;
expect(conf.needsPush()).to.be.true;
// incremented since we made changes (this only increments once between
// dumps; even though we changed two fields here).
pushResult = conf.push();
expect(pushResult.seqno).to.be.eq(1);
const expHash0 = from_hex('ea173b57beca8af18c3519a7bbf69c3e7a05d1c049fa9558341d8ebb48b0c965');
const expPush1Start =
'd1:#i1e1:&d1:n6:Kallie1:p34:http://example.org/omg-pic-123.bmp1:q32:secret78901234567890123456789012e1:<lli0e32:';
const expPush1End = 'deee1:=d1:n0:1:p0:1:q0:ee';
// The data to be actually pushed, expanded like this to make it somewhat human-readable:
const expPush1Decrypted = concatUInt8Array(
stringToUint8Array(expPush1Start),
expHash0,
stringToUint8Array(expPush1End)
);
const expPush1Encrypted = from_hex(
'877c8e0f5d33f5fffa5a4e162785a9a89918e95de1c4b925201f1f5c29d9ee4f8c36e2b278fce1e6b9d999689dd86ff8e79e0a04004fa54d24da89bc2604cb1df8c1356da8f14710543ecec44f2d57fc56ea8b7e73d119c69d755f4d513d5d069f02396b8ec0cbed894169836f57ca4b782ce705895c593b4230d50c175d44a08045388d3f4160bacb617b9ae8de3ebc8d9024245cd09ce102627cab2acf1b9126159211359606611ca5814de320d1a7099a65c99b0eebbefb92a115f5efa6b9132809300ac010c6857cfbd62af71b0fa97eccec75cb95e67edf40b35fdb9cad125a6976693ab085c6bba96a2e51826e81e16b9ec1232af5680f2ced55310486'
);
expect(to_hex(pushResult.data)).to.be.deep.eq(to_hex(expPush1Encrypted));
// We haven't dumped, so still need to dump:
expect(conf.needsDump()).to.be.true;
// We did call push, but we haven't confirmed it as stored yet, so this will still return true:
expect(conf.needsPush()).to.be.true;
const dumped = conf.dump();
// (in a real client we'd now store this to disk)
expect(conf.needsDump()).to.be.false;
const expectedDump = concatUInt8Array(
stringToUint8Array('d' + '1:!' + 'i2e' + '1:$' + `${expPush1Decrypted.length}` + ':'),
expPush1Decrypted,
stringToUint8Array('e')
);
expect(to_hex(dumped)).to.be.deep.eq(to_hex(expectedDump));
// So now imagine we got back confirmation from the swarm that the push has been stored:
conf.confirmPushed(pushResult.seqno);
expect(conf.needsPush()).to.be.false;
expect(conf.needsDump()).to.be.true;
conf.dump();
expect(conf.needsDump()).to.be.false;
// Now we're going to set up a second, competing config object (in the real world this would be
// another Session client somewhere).
// Start with an empty config, as abo.setve:
const conf2 = new SessionUtilWrapper.UserConfigWrapperInsideWorker(edSecretKey, null);
expect(conf2.needsDump()).to.be.false;
// Now imagine we just pulled down the encrypted string from the swarm; we merge it into conf2:
const accepted = conf2.merge([expPush1Encrypted]);
expect(accepted).to.be.eq(1);
// Our state has changed, so we need to dump:
expect(conf2.needsDump()).to.be.true;
conf2.dump();
// (store in db)
expect(conf2.needsDump()).to.be.false;
// We *don't* need to push: even though we updated, all we did is update to the merged data (and
// didn't have any sort of merge conflict needed):
expect(conf2.needsPush()).to.be.false;
// Now let's create a conflicting update:
// Change the name on both clients:
conf.setName('Nibbler');
conf2.setName('Raz');
// And, on conf2, we're also going to change the profile pic:
conf2.setProfilePicture(
'http://new.example.com/pic',
stringToUint8Array('qwert\0yuio1234567890123456789012')
);
// Both have changes, so push need a push
expect(conf.needsPush()).to.be.true;
expect(conf2.needsPush()).to.be.true;
pushResult = conf.push();
expect(pushResult.seqno).to.be.eq(2); // incremented, since we made a field change
let pushResult2 = conf2.push();
expect(pushResult2.seqno).to.be.eq(2); // incremented, since we made a field change
// (store in db)
conf.dump();
conf2.dump();
// Since we set different things, we're going to get back different serialized data to be
// pushed:
expect(to_hex(pushResult.data)).to.not.be.deep.eq(to_hex(pushResult2.data));
// Now imagine that each client pushed its `seqno=2` config to the swarm, but then each client
// also fetches new messages and pulls down the other client's `seqno=2` value.
// Feed the new config into each other. (This array could hold multiple configs if we pulled
// down more than one).
conf2.merge([pushResult.data]);
conf.merge([pushResult2.data]);
// Now after the merge we *will* want to push from both client, since both will have generated a
// merge conflict update (with seqno = 3).
expect(conf.needsPush()).to.be.true;
expect(conf2.needsPush()).to.be.true;
pushResult = conf.push();
pushResult2 = conf2.push();
expect(pushResult.seqno).to.be.eq(3);
expect(pushResult2.seqno).to.be.eq(3);
// They should have resolved the conflict to the same thing:
expect(conf.getName()).to.be.eq('Nibbler');
expect(conf2.getName()).to.be.eq('Nibbler');
// (Note that they could have also both resolved to "Raz" here, but the hash of the serialized
// message just happens to have a higher hash -- and thus gets priority -- for this particular
// test).
// Since only one of them set a profile pic there should be no conflict there:
const pic = conf.getProfilePicture();
const pic2 = conf2.getProfilePicture();
expect(pic.url).to.be.eq('http://new.example.com/pic');
expect(pic2.url).to.be.eq('http://new.example.com/pic');
expect(pic.key).to.be.deep.eq(stringToUint8Array('qwert\0yuio1234567890123456789012'));
expect(pic2.key).to.be.deep.eq(stringToUint8Array('qwert\0yuio1234567890123456789012'));
conf.confirmPushed(pushResult.seqno);
conf2.confirmPushed(pushResult2.seqno);
afterEach(() => {
Sinon.restore();
});
conf.dump();
conf2.dump();
// (store in db)
it('isUserProfileToStoreInWrapper returns true if thats our convo', () => {
const us = TestUtils.generateFakePubKeyStr();
Sinon.stub(UserUtils, 'getOurPubKeyStrFromCache').returns(us);
expect(SessionUtilUserProfile.isUserProfileToStoreInWrapper(us)).to.be.true;
});
expect(conf.needsPush()).to.be.false;
expect(conf.needsDump()).to.be.false;
expect(conf2.needsPush()).to.be.false;
expect(conf2.needsDump()).to.be.false;
it('isUserProfileToStoreInWrapper returns false if thats NOT our convo', () => {
const us = TestUtils.generateFakePubKeyStr();
const notUs = TestUtils.generateFakePubKeyStr();
Sinon.stub(UserUtils, 'getOurPubKeyStrFromCache').returns(us);
expect(SessionUtilUserProfile.isUserProfileToStoreInWrapper(notUs)).to.be.false;
});
});

@ -78,29 +78,6 @@ describe('formatRowOfConversation', () => {
});
});
describe('mentionedUs', () => {
it('initialize mentionedUs if they are not given', () => {
expect(formatRowOfConversation({}, 'test', 0, false)).to.have.deep.property(
'mentionedUs',
false
);
});
it('do not override mentionedUs if they are set in the row as integer: true', () => {
expect(formatRowOfConversation({ mentionedUs: 1 }, 'test', 0, false)).to.have.deep.property(
'mentionedUs',
true
);
});
it('do not override mentionedUs if they are set in the row as integer: false', () => {
expect(formatRowOfConversation({ mentionedUs: 0 }, 'test', 0, false)).to.have.deep.property(
'mentionedUs',
false
);
});
});
describe('isKickedFromGroup', () => {
it('initialize isKickedFromGroup if they are not given', () => {
expect(formatRowOfConversation({}, 'test', 0, false)).to.have.deep.property(

@ -19,15 +19,22 @@ import { MessageUtils, UserUtils } from '../../../../session/utils';
import { TestUtils } from '../../../test-utils';
import { stubCreateObjectUrl, stubData, stubUtilWorker } from '../../../test-utils/utils';
import { TEST_identityKeyPair } from '../crypto/MessageEncrypter_test';
import { fromBase64ToArrayBuffer } from '../../../../session/utils/String';
describe('MessageSender', () => {
afterEach(() => {
sinon.restore();
});
beforeEach(() => {
beforeEach(async () => {
TestUtils.stubWindowLog();
TestUtils.stubWindowFeatureFlags();
getConversationController().reset();
TestUtils.stubData('getItemById').resolves();
stubData('getAllConversations').resolves([]);
stubData('saveConversation').resolves();
await getConversationController().load();
});
// tslint:disable-next-line: max-func-body-length
@ -114,9 +121,13 @@ describe('MessageSender', () => {
await MessageSender.send(rawMessage, 3, 10);
const args = sessionMessageAPISendStub.getCall(0).args;
expect(args[0]).to.equal(device.key);
expect(args[1]).to.equal(device.key);
const firstArg = args[0];
expect(firstArg.length).to.equal(1);
// expect(args[3]).to.equal(visibleMessage.timestamp); the timestamp is overwritten on sending by the network clock offset
expect(args[2]).to.equal(visibleMessage.ttl());
expect(firstArg[0].ttl).to.equal(visibleMessage.ttl());
expect(firstArg[0].pubkey).to.equal(device.key);
expect(firstArg[0].namespace).to.equal(SnodeNamespaces.UserMessages);
});
it('should correctly build the envelope and override the timestamp', async () => {
@ -135,8 +146,10 @@ describe('MessageSender', () => {
Sinon.stub(GetNetworkTime, 'getLatestTimestampOffset').returns(offset);
await MessageSender.send(rawMessage, 3, 10);
const data = sessionMessageAPISendStub.getCall(0).args[1];
const webSocketMessage = SignalService.WebSocketMessage.decode(data);
const firstArg = sessionMessageAPISendStub.getCall(0).args[0];
const { data64 } = firstArg[0];
const data = fromBase64ToArrayBuffer(data64);
const webSocketMessage = SignalService.WebSocketMessage.decode(new Uint8Array(data));
expect(webSocketMessage.request?.body).to.not.equal(
undefined,
'Request body should not be undefined'
@ -187,8 +200,10 @@ describe('MessageSender', () => {
);
await MessageSender.send(rawMessage, 3, 10);
const data = sessionMessageAPISendStub.getCall(0).args[1];
const webSocketMessage = SignalService.WebSocketMessage.decode(data);
const firstArg = sessionMessageAPISendStub.getCall(0).args[0];
const { data64 } = firstArg[0];
const data = fromBase64ToArrayBuffer(data64);
const webSocketMessage = SignalService.WebSocketMessage.decode(new Uint8Array(data));
expect(webSocketMessage.request?.body).to.not.equal(
undefined,
'Request body should not be undefined'

@ -11,6 +11,8 @@ import {
import { getOpenGroupV2ConversationId } from '../../../../session/apis/open_group_api/utils/OpenGroupUtils';
import { getConversationController } from '../../../../session/conversations';
import { stubData, stubOpenGroupData, stubWindowLog } from '../../../test-utils/utils';
import { UserUtils } from '../../../../session/utils';
import { TestUtils } from '../../../test-utils';
describe('APIUtils', () => {
beforeEach(() => {
@ -115,8 +117,8 @@ describe('APIUtils', () => {
it('returns false if there no rooms matching that serverURL with http prefix', () => {
expect(hasExistingOpenGroup('http://1.1.1.1', 'roomId')).to.be.false;
expect(hasExistingOpenGroup('http://1.1.1.1:4433', 'roomId')).to.be.false;
expect(hasExistingOpenGroup('http://plop.com:4433', 'roomId')).to.be.false;
expect(hasExistingOpenGroup('https://plop.com', 'roomId')).to.be.false;
expect(hasExistingOpenGroup('http://whatever.com:4433', 'roomId')).to.be.false;
expect(hasExistingOpenGroup('https://whatever.com', 'roomId')).to.be.false;
});
});
});
@ -135,6 +137,10 @@ describe('APIUtils', () => {
getV2OpenGroupRoomsByServerUrl = stubOpenGroupData('getV2OpenGroupRoomsByServerUrl');
getConversationController().reset();
Sinon.stub(UserUtils, 'getOurPubKeyStrFromCache').returns(
TestUtils.generateFakePubKeyStr()
);
await getConversationController().load();
const convoOurIp = await getConversationController().getOrCreateAndWait(

@ -33,7 +33,7 @@ describe('FetchCapabilities', () => {
});
it('return null if given object without cap field ', () => {
expect(parseCapabilities({ plop: [] })).to.be.deep.eq(null);
expect(parseCapabilities({ invalid: [] })).to.be.deep.eq(null);
});
it('return valid if given one cap ', () => {

@ -23,6 +23,7 @@ import { getConversationController } from '../../../../session/conversations';
import { LibSodiumWrappers } from '../../../../session/crypto';
import { UserUtils } from '../../../../session/utils';
import { expectAsyncToThrow, stubData, stubWindowLog } from '../../../test-utils/utils';
import { TestUtils } from '../../../test-utils';
// tslint:disable: chai-vague-errors
@ -72,7 +73,7 @@ describe('knownBlindedKeys', () => {
});
it('loadFromDb with invalid json', async () => {
getItemById.resolves({ id: '', value: 'plop invalid json' });
getItemById.resolves({ id: '', value: 'invalid json content' });
await loadKnownBlindedKeys();
expect(TEST_getCachedBlindedKeys()).to.deep.eq([]);
});
@ -481,14 +482,17 @@ describe('knownBlindedKeys', () => {
describe('when not in cache', () => {
beforeEach(async () => {
getConversationController().reset();
getItemById.resolves();
stubData('getAllConversations').resolves([]);
stubData('saveConversation').resolves();
Sinon.stub(UserUtils, 'getOurPubKeyStrFromCache').returns(
TestUtils.generateFakePubKeyStr()
);
await getConversationController().load();
});
it('does iterate over all the conversations and find the first one matching (fails)', async () => {
getItemById.resolves();
await loadKnownBlindedKeys();
const shouldBeWrittenToDb = {
blindedId: knownBlindingMatch.blindedId,
@ -510,7 +514,6 @@ describe('knownBlindedKeys', () => {
});
it('does iterate over all the conversations and find the first one matching (passes)', async () => {
getItemById.resolves();
await loadKnownBlindedKeys();
// adding a private conversation with a known match of the blinded pubkey we have
await getConversationController().getOrCreateAndWait(
@ -543,7 +546,6 @@ describe('knownBlindedKeys', () => {
});
it('does iterate over all the conversations but is not approved so must fail', async () => {
getItemById.resolves();
await loadKnownBlindedKeys();
// adding a private conversation with a known match of the blinded pubkey we have
const convo = await getConversationController().getOrCreateAndWait(
@ -562,7 +564,6 @@ describe('knownBlindedKeys', () => {
});
it('does iterate over all the conversations but is not private so must fail: group', async () => {
getItemById.resolves();
await loadKnownBlindedKeys();
// adding a private conversation with a known match of the blinded pubkey we have
const convo = await getConversationController().getOrCreateAndWait(

@ -295,7 +295,7 @@ describe('SwarmPolling', () => {
ConversationTypeEnum.GROUP
);
convo.set('active_at', 1); // really old
convo.set('active_at', 1); // really old, but active
const groupConvoPubkey = PubKey.cast(convo.id as string);
swarmPolling.addGroupId(groupConvoPubkey);
@ -451,230 +451,5 @@ describe('SwarmPolling', () => {
});
});
});
describe('group v3', () => {
it('does run for group pubkey on start no matter the recent timestamp ', async () => {
const convo = getConversationController().getOrCreate(
TestUtils.generateFakeClosedGroupV3PkStr(),
ConversationTypeEnum.GROUPV3
);
convo.set('active_at', Date.now());
const groupConvoPubkey = PubKey.cast(convo.id as string);
swarmPolling.addGroupId(groupConvoPubkey);
await swarmPolling.start(true);
// our pubkey will be polled for, hence the 2
expect(pollOnceForKeySpy.callCount).to.eq(2);
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]);
});
it('does run for groupv3 pubkey on start no matter the recent timestamp ', async () => {
const convo = getConversationController().getOrCreate(
TestUtils.generateFakeClosedGroupV3PkStr(),
ConversationTypeEnum.GROUPV3
);
convo.set('active_at', Date.now());
const groupConvoPubkey = PubKey.cast(convo.id as string);
swarmPolling.addGroupId(groupConvoPubkey);
await swarmPolling.start(true);
// our pubkey will be polled for, hence the 2
expect(pollOnceForKeySpy.callCount).to.eq(2);
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]);
});
it('does only poll from -10 for closed groups if HF >= 19.1 ', async () => {
const convo = getConversationController().getOrCreate(
TestUtils.generateFakeClosedGroupV3PkStr(),
ConversationTypeEnum.GROUPV3
);
getItemByIdStub.restore();
getItemByIdStub = TestUtils.stubData('getItemById');
getItemByIdStub
.withArgs('hasSeenHardfork190')
.resolves({ id: 'hasSeenHardfork190', value: true })
.withArgs('hasSeenHardfork191')
.resolves({ id: 'hasSeenHardfork191', value: true });
convo.set('active_at', 1);
const groupConvoPubkey = PubKey.cast(convo.id as string);
swarmPolling.addGroupId(groupConvoPubkey);
await swarmPolling.start(true);
// our pubkey will be polled for, hence the 2
expect(pollOnceForKeySpy.callCount).to.eq(2);
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]);
getItemByIdStub.restore();
getItemByIdStub = TestUtils.stubData('getItemById');
getItemByIdStub.resolves();
});
it('does run for group pubkey on start but not another time if activeAt is old ', async () => {
const convo = getConversationController().getOrCreate(
TestUtils.generateFakeClosedGroupV3PkStr(),
ConversationTypeEnum.GROUPV3
);
convo.set('active_at', 1); // really old
const groupConvoPubkey = PubKey.cast(convo.id as string);
swarmPolling.addGroupId(groupConvoPubkey);
// this calls the stub 2 times, one for our direct pubkey and one for the group
await swarmPolling.start(true);
// this should only call the stub one more time: for our direct pubkey but not for the group pubkey
await swarmPolling.pollForAllKeys();
expect(pollOnceForKeySpy.callCount).to.eq(3);
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]);
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0]]);
});
it('does run twice if activeAt less than one hour ', async () => {
const convo = getConversationController().getOrCreate(
TestUtils.generateFakeClosedGroupV3PkStr(),
ConversationTypeEnum.GROUPV3
);
convo.set('active_at', Date.now());
const groupConvoPubkey = PubKey.cast(convo.id as string);
swarmPolling.addGroupId(groupConvoPubkey);
await swarmPolling.start(true);
clock.tick(9000);
// no need to do that as the tick will trigger a call in all cases after 5 secs await swarmPolling.pollForAllKeys();
/** this is not easy to explain, but
* - during the swarmPolling.start, we get two calls to pollOnceForKeySpy (one for our id and one for group od)
* - the clock ticks 9sec, and another call of pollOnceForKeySpy get started, but as we do not await them, this test fails.
* the only fix is to restore the clock and force the a small sleep to let the thing run in bg
*/
clock.restore();
await sleepFor(10);
expect(pollOnceForKeySpy.callCount).to.eq(4);
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]);
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.getCall(3).args).to.deep.eq([groupConvoPubkey, true, [-10]]);
});
it('does run twice if activeAt is inactive and we tick longer than 2 minutes', async () => {
const convo = getConversationController().getOrCreate(
TestUtils.generateFakeClosedGroupV3PkStr(),
ConversationTypeEnum.GROUPV3
);
pollOnceForKeySpy.resetHistory();
convo.set('active_at', Date.now());
const groupConvoPubkey = PubKey.cast(convo.id as string);
swarmPolling.addGroupId(groupConvoPubkey);
// this call the stub two times already, one for our direct pubkey and one for the group
await swarmPolling.start(true);
const timeToTick = 3 * 60 * 1000;
swarmPolling.forcePolledTimestamp(groupConvoPubkey, Date.now() - timeToTick);
// more than week old, so inactive group but we have to tick after more than 2 min
convo.set('active_at', Date.now() - 7 * 25 * 3600 * 1000);
clock.tick(timeToTick);
/** this is not easy to explain, but
* - during the swarmPolling.start, we get two calls to pollOnceForKeySpy (one for our id and one for group od)
* - the clock ticks 9sec, and another call of pollOnceForKeySpy get started, but as we do not await them, this test fails.
* the only fix is to restore the clock and force the a small sleep to let the thing run in bg
*/
clock.restore();
await sleepFor(10);
// we should have two more calls here, so 4 total.
expect(pollOnceForKeySpy.callCount).to.eq(4);
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]);
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.getCalls()[3].args).to.deep.eq([groupConvoPubkey, true, [-10]]);
});
it('does run once only if group is inactive and we tick less than 2 minutes ', async () => {
const convo = getConversationController().getOrCreate(
TestUtils.generateFakeClosedGroupV3PkStr(),
ConversationTypeEnum.GROUPV3
);
pollOnceForKeySpy.resetHistory();
convo.set('active_at', Date.now());
const groupConvoPubkey = PubKey.cast(convo.id as string);
swarmPolling.addGroupId(groupConvoPubkey);
await swarmPolling.start(true);
// more than a week old, we should not tick after just 5 seconds
convo.set('active_at', Date.now() - 7 * 24 * 3600 * 1000 - 3600 * 1000);
clock.tick(1 * 60 * 1000);
// we should have only one more call here, the one for our direct pubkey fetch
expect(pollOnceForKeySpy.callCount).to.eq(3);
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]); // this one comes from the swarmPolling.start
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0]]);
});
describe('multiple runs', () => {
let convo: ConversationModel;
let groupConvoPubkey: PubKey;
beforeEach(async () => {
convo = getConversationController().getOrCreate(
TestUtils.generateFakeClosedGroupV3PkStr(),
ConversationTypeEnum.GROUPV3
);
convo.set('active_at', Date.now());
groupConvoPubkey = PubKey.cast(convo.id as string);
swarmPolling.addGroupId(groupConvoPubkey);
await swarmPolling.start(true);
});
it('does run twice if activeAt is less than 2 days', async () => {
pollOnceForKeySpy.resetHistory();
// less than 2 days old, this is an active group
convo.set('active_at', Date.now() - 2 * 24 * 3600 * 1000 - 3600 * 1000);
const timeToTick = 6 * 1000;
swarmPolling.forcePolledTimestamp(convo.id, timeToTick);
// we tick more than 5 sec
clock.tick(timeToTick);
await swarmPolling.pollForAllKeys();
// we have 4 calls total. 2 for our direct promises run each 5 seconds, and 2 for the group pubkey active (so run every 5 sec too)
expect(pollOnceForKeySpy.callCount).to.eq(4);
// first two calls are our pubkey
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]);
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.getCalls()[3].args).to.deep.eq([groupConvoPubkey, true, [-10]]);
});
it('does run twice if activeAt is more than 2 days old and we tick more than one minute ', async () => {
pollOnceForKeySpy.resetHistory();
convo.set('active_at', Date.now() - 2 * 25 * 3600 * 1000); // medium active
const timeToTick = 65 * 1000;
swarmPolling.forcePolledTimestamp(convo.id, timeToTick);
clock.tick(timeToTick); // should tick twice more (one more our direct pubkey and one for the group)
await swarmPolling.pollForAllKeys();
expect(pollOnceForKeySpy.callCount).to.eq(4);
// first two calls are our pubkey
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]);
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0]]);
expect(pollOnceForKeySpy.getCalls()[3].args).to.deep.eq([groupConvoPubkey, true, [-10]]);
});
});
});
});
});

@ -251,6 +251,9 @@ describe('Message Utils', () => {
stubData('getAllConversations').resolves([]);
stubData('saveConversation').resolves();
stubOpenGroupData('getAllV2OpenGroupRooms').resolves();
TestUtils.stubData('getItemById').callsFake(async () => {
return { value: '[]' };
});
getConversationController().reset();
await getConversationController().load();
@ -271,8 +274,9 @@ describe('Message Utils', () => {
ConversationTypeEnum.PRIVATE
);
const convoId3 = getOpenGroupV2ConversationId('chat-dev2.lokinet.org', 'fish');
const convoId4 = getOpenGroupV2ConversationId('chat-dev3.lokinet.org', 'fish2');
const convoId3 = getOpenGroupV2ConversationId('http://chat-dev2.lokinet.org', 'fish');
const convoId4 = getOpenGroupV2ConversationId('http://chat-dev3.lokinet.org', 'fish2');
const convoId5 = getOpenGroupV2ConversationId('http://chat-dev3.lokinet.org', 'fish3');
const convo3 = await getConversationController().getOrCreateAndWait(
convoId3,
@ -284,7 +288,7 @@ describe('Message Utils', () => {
.returns(null)
.withArgs(convoId3)
.returns({
serverUrl: 'chat-dev2.lokinet.org',
serverUrl: 'http://chat-dev2.lokinet.org',
roomId: 'fish',
serverPublicKey: 'serverPublicKey',
} as OpenGroupV2Room);
@ -297,7 +301,7 @@ describe('Message Utils', () => {
await OpenGroupData.opengroupRoomsLoad();
const convo5 = await getConversationController().getOrCreateAndWait(
convoId4,
convoId5,
ConversationTypeEnum.GROUP
);
convo5.set({ active_at: 0 });
@ -308,11 +312,12 @@ describe('Message Utils', () => {
);
const convos = getConversationController().getConversations();
//convoID3 is active but 4 and 5 are not
const configMessage = await getCurrentConfigurationMessage(convos);
expect(configMessage.activeOpenGroups.length).to.equal(1);
expect(configMessage.activeOpenGroups[0]).to.equal(
// tslint:disable-next-line: no-http-string
'chat-dev2.lokinet.org/fish?public_key=serverPublicKey'
'http://chat-dev2.lokinet.org/fish?public_key=serverPublicKey'
);
});
});

@ -14,21 +14,21 @@ chai.use(chaiAsPromised as any);
describe('OpenGroupUtils', () => {
describe('prefixify', () => {
it('should just return if http:// is as prefix', () => {
expect(prefixify('http://plop.com')).to.be.equal('http://plop.com');
expect(prefixify('http://whatever.com')).to.be.equal('http://whatever.com');
});
it('should just return if https:// is as prefix', () => {
expect(prefixify('https://plop.com')).to.be.equal('https://plop.com');
expect(prefixify('https://whatever.com')).to.be.equal('https://whatever.com');
});
it('should just return if http:// is as prefix ', () => {
expect(prefixify('http://plop.com')).to.be.equal('http://plop.com');
expect(prefixify('http://whatever.com')).to.be.equal('http://whatever.com');
});
it('should just return if https:// is as prefix', () => {
expect(prefixify('https://plop.com')).to.be.equal('https://plop.com');
expect(prefixify('https://whatever.com')).to.be.equal('https://whatever.com');
});
it('should prefix with http if ssl is false and no prefix', () => {
expect(prefixify('plop.com')).to.be.equal('http://plop.com');
expect(prefixify('whatever.com')).to.be.equal('http://whatever.com');
});
});
@ -37,7 +37,7 @@ describe('OpenGroupUtils', () => {
it('throws if roomId is too long 64 ', () => {
expect(() => {
getOpenGroupV2ConversationId(
'http://plop.com',
'http://whatever.com',
'012345678901234567890#1234567!89012345678901234567890123456789fg01234'
);
}).to.throw('getOpenGroupV2ConversationId: Invalid roomId');
@ -45,37 +45,37 @@ describe('OpenGroupUtils', () => {
it('throws if roomId is too short ', () => {
expect(() => {
getOpenGroupV2ConversationId('http://plop.com', '');
getOpenGroupV2ConversationId('http://whatever.com', '');
}).to.throw('getOpenGroupV2ConversationId: Invalid roomId');
});
it('throws if roomId is has forbidden chars ', () => {
expect(() => {
getOpenGroupV2ConversationId('http://plop.com', '1&%^%');
getOpenGroupV2ConversationId('http://whatever.com', '1&%^%');
}).to.throw('getOpenGroupV2ConversationId: Invalid roomId');
});
});
it('doesnt throw if roomId and serverUrl are valid ', () => {
expect(() => {
getOpenGroupV2ConversationId('http://127.0.0.1/', 'plop1234');
getOpenGroupV2ConversationId('http://127.0.0.1/', 'whatever1234');
}).to.not.throw();
});
it('doesnt throw if roomId and serverUrl are valid with port', () => {
expect(() => {
getOpenGroupV2ConversationId('http://127.0.0.1:22/', 'plop1234');
getOpenGroupV2ConversationId('http://127.0.0.1:22/', 'whatever1234');
}).to.not.throw();
});
it('doesnt throw if roomId and serverUrl are valid with port', () => {
expect(() => {
getOpenGroupV2ConversationId('https://opengroup.com/', 'plop1234');
getOpenGroupV2ConversationId('https://opengroup.com/', 'whatever1234');
}).to.not.throw();
});
it('throw if serverUrl is no url', () => {
expect(() => {
getOpenGroupV2ConversationId('opengroup', 'plop1234');
getOpenGroupV2ConversationId('opengroup', 'whatever1234');
}).to.throw();
});
});
@ -84,17 +84,17 @@ describe('OpenGroupUtils', () => {
it('doesnt throw if roomId and serverUrl are valid with port', () => {
expect(
getCompleteUrlFromRoom({
roomId: 'plop1234',
roomId: 'whatever1234',
serverPublicKey: '05123456789',
serverUrl: 'https://example.org',
})
).to.be.eq('https://example.org/plop1234?public_key=05123456789');
).to.be.eq('https://example.org/whatever1234?public_key=05123456789');
});
it('throws if pubkey is empty', () => {
expect(() =>
getCompleteUrlFromRoom({
roomId: 'plop1234',
roomId: 'whatever1234',
serverPublicKey: '',
serverUrl: 'https://example.org',
})
@ -104,7 +104,7 @@ describe('OpenGroupUtils', () => {
it('throws if serverUrl is empty', () => {
expect(() =>
getCompleteUrlFromRoom({
roomId: 'plop1234',
roomId: 'whatever1234',
serverPublicKey: '05123456789',
serverUrl: '',
})
@ -123,7 +123,7 @@ describe('OpenGroupUtils', () => {
it('throws if pubkey is null', () => {
expect(() =>
getCompleteUrlFromRoom({
roomId: 'plop1234',
roomId: 'whatever1234',
serverPublicKey: null as any,
serverUrl: 'https://example.org',
})
@ -133,7 +133,7 @@ describe('OpenGroupUtils', () => {
it('throws if serverUrl is null', () => {
expect(() =>
getCompleteUrlFromRoom({
roomId: 'plop1234',
roomId: 'whatever1234',
serverPublicKey: '05123456789',
serverUrl: null as any,
})

@ -10,6 +10,7 @@ import {
} from '../../../../../session/utils/job_runners/PersistedJob';
import { sleepFor } from '../../../../../session/utils/Promise';
import { stubData } from '../../../../test-utils/utils';
import { TestUtils } from '../../../../test-utils';
function getFakeSleepForJob(timestamp: number): FakeSleepForJob {
const job = new FakeSleepForJob({
@ -185,28 +186,48 @@ describe('JobRunner', () => {
it('two jobs are running sequentially', async () => {
await runnerMulti.loadJobsFromDb();
const job = getFakeSleepForMultiJob({ timestamp: 100 });
TestUtils.stubWindowLog();
const job = getFakeSleepForMultiJob({ timestamp: 5 });
const job2 = getFakeSleepForMultiJob({ timestamp: 200 });
runnerMulti.startProcessing();
clock.tick(110);
clock.tick(100);
// job should be started right away
let result = await runnerMulti.addJob(job);
expect(result).to.eq('job_started');
result = await runnerMulti.addJob(job2);
expect(result).to.eq('job_deferred');
expect(runnerMulti.getJobList()).to.deep.eq([job.serializeJob(), job2.serializeJob()]);
expect(runnerMulti.getJobList()).to.deep.eq([job.serializeJob(), job2.serializeJob()]);
expect(runnerMulti.getCurrentJobIdentifier()).to.be.equal(job.persistedData.identifier);
console.warn(
'runnerMulti.getJobList() initial',
runnerMulti.getJobList().map(m => m.identifier),
Date.now()
);
console.warn('=========== awaiting first job ==========');
// each job takes 5s to finish, so let's tick once the first one should be done
clock.tick(5010);
await runnerMulti.waitCurrentJob();
clock.tick(5010);
await runnerMulti.waitCurrentJob();
clock.tick(5000);
expect(runnerMulti.getCurrentJobIdentifier()).to.be.equal(job.persistedData.identifier);
let awaited = await runnerMulti.waitCurrentJob();
expect(awaited).to.eq('await');
await sleepFor(10);
expect(runnerMulti.getJobList()).to.deep.eq([job2.serializeJob()]);
console.warn('=========== awaited first job ==========');
expect(runnerMulti.getCurrentJobIdentifier()).to.be.equal(job2.persistedData.identifier);
console.warn('=========== awaiting second job ==========');
clock.tick(5000);
await runnerMulti.waitCurrentJob();
awaited = await runnerMulti.waitCurrentJob();
expect(awaited).to.eq('await');
await sleepFor(10); // those sleep for is just to let the runner the time to finish writing the tests to the DB and exit the handling of the previous test
console.warn('=========== awaited second job ==========');
expect(runnerMulti.getCurrentJobIdentifier()).to.eq(null);
expect(runnerMulti.getJobList()).to.deep.eq([]);
});
@ -219,24 +240,32 @@ describe('JobRunner', () => {
clock.tick(110);
// job should be started right away
let result = await runnerMulti.addJob(job);
expect(result).to.eq('job_started');
expect(runnerMulti.getJobList()).to.deep.eq([job.serializeJob()]);
expect(runnerMulti.getCurrentJobIdentifier()).to.be.equal(job.persistedData.identifier);
expect(result).to.eq('job_started');
clock.tick(5010);
await runnerMulti.waitCurrentJob();
clock.tick(5010);
clock.tick(5000);
console.warn('=========== awaiting first job ==========');
await runnerMulti.waitCurrentJob();
// just give some time for the runnerMulti to pick up a new job
await sleepFor(100);
await sleepFor(10);
expect(runnerMulti.getJobList()).to.deep.eq([]);
expect(runnerMulti.getCurrentJobIdentifier()).to.be.equal(null);
console.warn('=========== awaited first job ==========');
// the first job should already be finished now
result = await runnerMulti.addJob(job2);
expect(result).to.eq('job_started');
expect(runnerMulti.getJobList()).to.deep.eq([job2.serializeJob()]);
console.warn('=========== awaiting second job ==========');
// each job takes 5s to finish, so let's tick once the first one should be done
clock.tick(5010);
await runnerMulti.waitCurrentJob();
await sleepFor(10);
console.warn('=========== awaited second job ==========');
expect(runnerMulti.getJobList()).to.deep.eq([]);
});

Loading…
Cancel
Save