diff --git a/ts/components/leftpane/LeftPaneMessageSection.tsx b/ts/components/leftpane/LeftPaneMessageSection.tsx index e439957ac..b46507888 100644 --- a/ts/components/leftpane/LeftPaneMessageSection.tsx +++ b/ts/components/leftpane/LeftPaneMessageSection.tsx @@ -84,7 +84,7 @@ export class LeftPaneMessageSection extends React.Component { throw new Error('renderRow: conversations selector returned element containing falsy value.'); } - return ; + return ; // TODO there should not be a need for the ...conversation here? }; public renderList(): JSX.Element { diff --git a/ts/components/leftpane/overlay/OverlayMessageRequest.tsx b/ts/components/leftpane/overlay/OverlayMessageRequest.tsx index cc63d7cff..9f1360b25 100644 --- a/ts/components/leftpane/overlay/OverlayMessageRequest.tsx +++ b/ts/components/leftpane/overlay/OverlayMessageRequest.tsx @@ -34,7 +34,7 @@ const MessageRequestList = () => { return ( {conversationRequests.map(conversation => { - return ; + return ; // TODO there should not be a need for the ...conversation here? })} ); diff --git a/ts/data/configDump/configDumpType.ts b/ts/data/configDump/configDumpType.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/ts/receiver/configMessage.ts b/ts/receiver/configMessage.ts index 0d1b52ad4..9bb7b3797 100644 --- a/ts/receiver/configMessage.ts +++ b/ts/receiver/configMessage.ts @@ -1000,9 +1000,7 @@ async function handleConfigurationMessageLegacy( } await handleOurProfileUpdateLegacy(envelope.timestamp, configurationMessage); - await handleGroupsAndContactsFromConfigMessageLegacy(envelope, configurationMessage); - await removeFromCache(envelope); } diff --git a/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts b/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts index 5a6e90c7b..aee542ede 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts @@ -119,7 +119,7 @@ async function handlePollInfoResponse( read, write, upload, - active_users: active_users, + active_users, details: pick( details, 'admins', diff --git a/ts/session/apis/snode_api/namespaces.ts b/ts/session/apis/snode_api/namespaces.ts index a1558953d..23d60450c 100644 --- a/ts/session/apis/snode_api/namespaces.ts +++ b/ts/session/apis/snode_api/namespaces.ts @@ -16,7 +16,7 @@ export enum SnodeNamespaces { */ UserContacts = 3, /** - * This is the namespace used to sync our contacts + * This is the namespace used to sync our volatile info (currently read status only) */ ConvoInfoVolatile = 4, @@ -94,9 +94,9 @@ function namespacePriority(namespace: SnodeNamespaces): number { default: try { - assertUnreachable(namespace, `isUserConfigNamespace case not handled: ${namespace}`); + assertUnreachable(namespace, `namespacePriority case not handled: ${namespace}`); } catch (e) { - window.log.warn(`isUserConfigNamespace case not handled: ${namespace}: ${e.message}`); + window.log.warn(`namespacePriority case not handled: ${namespace}: ${e.message}`); return 1; } } diff --git a/ts/session/apis/snode_api/swarmPolling.ts b/ts/session/apis/snode_api/swarmPolling.ts index 6b497652b..e1b1ebea8 100644 --- a/ts/session/apis/snode_api/swarmPolling.ts +++ b/ts/session/apis/snode_api/swarmPolling.ts @@ -172,7 +172,6 @@ export class SwarmPolling { getConversationController() .get(group.pubkey.key) ?.idForLogging() || group.pubkey.key; - if (diff >= convoPollingTimeout) { window?.log?.debug( `Polling for ${loggingId}; timeout: ${convoPollingTimeout}; diff: ${diff} ` diff --git a/ts/session/messages/outgoing/controlMessage/group/v3/GroupAdminGroupMessage.ts b/ts/session/messages/outgoing/controlMessage/group/v3/GroupAdminGroupMessage.ts deleted file mode 100644 index 4688b1229..000000000 --- a/ts/session/messages/outgoing/controlMessage/group/v3/GroupAdminGroupMessage.ts +++ /dev/null @@ -1,55 +0,0 @@ -// import { SignalService } from '../../../../../../protobuf'; -// import { isArray } from 'lodash'; -// import { GroupMessage, GroupMessageParams } from './GroupMessage'; -// // import { PubKey } from '../../../../../types'; -// // import { from_hex } from 'libsodium-wrappers-sumo'; - -// interface GroupAdminMessageParams extends GroupMessageParams { -// /* -// * A proof that we are an admin (a proof that we have access to the private key of the closed group). -// * this field is needed for all types of admin messages so that every member can make -// */ -// groupSignature: Uint8Array; -// } - -// interface GroupAdminMessageParams extends GroupMessageParams { -// /** -// * hex string of the members to delete the group from. -// * a single '*' is allowed too and means 'every members' -// * -// */ -// members: Array; -// } - -// export class GroupAdminGroupMessage extends GroupMessage { -// // private readonly members: Array; - -// constructor(params: GroupAdminMessageParams) { -// super(params); - -// if (!params.members || !isArray(params.members) || !params.members.length) { -// throw new Error('members parameter must be set'); -// } - -// // if (params.members.length === 1 && params.members[0] === '*') { -// // this.members = params.members; -// // } else { -// // const allAreValid = params.members.every(PubKey.isValidGroupPubkey); -// // if (!allAreValid) { -// // throw new Error('One of the members is not a `isValidGroupPubkey`'); -// // } - -// // this.members = params.members; -// // } -// throw new Error('TODO and add tests'); -// } - -// public dataProto(): SignalService.DataMessage { -// const dataMessage = new SignalService.DataMessage(); -// dataMessage.groupMessage = super.groupMessage(); -// dataMessage.groupMessage.adminMessage = new SignalService.GroupAdminMessage(); -// // dataMessage.groupMessage.members = this.members.map(from_hex); - -// return dataMessage; -// } -// } diff --git a/ts/session/messages/outgoing/controlMessage/group/v3/GroupInviteMessage.ts b/ts/session/messages/outgoing/controlMessage/group/v3/GroupInviteMessage.ts deleted file mode 100644 index d922745b8..000000000 --- a/ts/session/messages/outgoing/controlMessage/group/v3/GroupInviteMessage.ts +++ /dev/null @@ -1,48 +0,0 @@ -// import { SignalService } from '../../../../../../protobuf'; -// import { isEmpty, isString } from 'lodash'; -// import { GroupMessage, GroupMessageParams } from './GroupMessage'; -// import { PubKey } from '../../../../../types'; -// import { from_hex } from 'libsodium-wrappers-sumo'; - -// export interface GroupInviteMessageParams extends GroupMessageParams { -// name: string; -// /** -// * hex string of that member private key -// */ -// memberPrivateKey: string; -// } - -// export class GroupInviteMessage extends GroupMessage { -// private readonly name: string; -// private readonly memberPrivateKey: string; - -// constructor(params: GroupInviteMessageParams) { -// super(params); - -// if (!params.name || isEmpty(params.name) || !isString(params.name)) { -// throw new Error('name parameter must be valid'); -// } - -// if ( -// !params.memberPrivateKey || -// isEmpty(params.memberPrivateKey) || -// !isString(params.memberPrivateKey) || -// !PubKey.isHexOnly(params.memberPrivateKey) -// ) { -// throw new Error('memberPrivateKey parameter must be valid'); -// } - -// this.name = params.name; -// this.memberPrivateKey = params.memberPrivateKey; -// } - -// public dataProto(): SignalService.DataMessage { -// const dataMessage = new SignalService.DataMessage(); -// dataMessage.groupMessage = super.groupMessage(); -// dataMessage.groupMessage.inviteMessage = new SignalService.GroupInviteMessage(); -// dataMessage.groupMessage.inviteMessage.name = this.name; -// dataMessage.groupMessage.inviteMessage.memberPrivateKey = from_hex(this.memberPrivateKey); - -// return dataMessage; -// } -// } diff --git a/ts/session/messages/outgoing/controlMessage/group/v3/GroupMemberLeftMessage.ts b/ts/session/messages/outgoing/controlMessage/group/v3/GroupMemberLeftMessage.ts deleted file mode 100644 index a85fd659d..000000000 --- a/ts/session/messages/outgoing/controlMessage/group/v3/GroupMemberLeftMessage.ts +++ /dev/null @@ -1,18 +0,0 @@ -// import { SignalService } from '../../../../../../protobuf'; -// import { GroupMessage, GroupMessageParams } from './GroupMessage'; - -// interface GroupMemberLeftMessageParams extends GroupMessageParams {} - -// export class GroupMemberLeftMessage extends GroupMessage { -// constructor(params: GroupMemberLeftMessageParams) { -// super(params); -// } - -// public dataProto(): SignalService.DataMessage { -// const dataMessage = new SignalService.DataMessage(); -// dataMessage.groupMessage = super.groupMessage(); -// dataMessage.groupMessage.memberLeftMessage = new SignalService.GroupMemberLeftMessage(); - -// return dataMessage; -// } -// } diff --git a/ts/session/messages/outgoing/controlMessage/group/v3/GroupMessage.ts b/ts/session/messages/outgoing/controlMessage/group/v3/GroupMessage.ts deleted file mode 100644 index b2fc845c4..000000000 --- a/ts/session/messages/outgoing/controlMessage/group/v3/GroupMessage.ts +++ /dev/null @@ -1,18 +0,0 @@ -// import { SignalService } from '../../../../../../protobuf'; -// import { DataMessage } from '../../../DataMessage'; -// import { MessageParams } from '../../../Message'; - -// export interface GroupMessageParams extends MessageParams {} - -// export abstract class GroupMessage extends DataMessage { -// constructor(params: GroupMessageParams) { -// super({ -// timestamp: params.timestamp, -// identifier: params.identifier, -// }); -// } - -// protected groupMessage() { -// return new SignalService.GroupMessage(); -// } -// } diff --git a/ts/session/messages/outgoing/controlMessage/group/v3/GroupPromoteMessage.ts b/ts/session/messages/outgoing/controlMessage/group/v3/GroupPromoteMessage.ts deleted file mode 100644 index 292ff1312..000000000 --- a/ts/session/messages/outgoing/controlMessage/group/v3/GroupPromoteMessage.ts +++ /dev/null @@ -1,34 +0,0 @@ -// import { SignalService } from '../../../../../../protobuf'; -// import { isEmpty } from 'lodash'; -// import { GroupMessage, GroupMessageParams } from './GroupMessage'; -// import { from_hex } from 'libsodium-wrappers-sumo'; - -// export interface GroupPromoteMessageParams extends GroupMessageParams { -// /** -// * hex string of the group private key -// */ -// privateKey: string; -// } - -// export class GroupPromoteMessage extends GroupMessage { -// private readonly privateKey: string; - -// constructor(params: GroupPromoteMessageParams) { -// super(params); - -// if (!params.privateKey || isEmpty(params.privateKey)) { -// throw new Error('privateKey parameter must be set'); -// } - -// this.privateKey = params.privateKey; -// } - -// public dataProto(): SignalService.DataMessage { -// const dataMessage = new SignalService.DataMessage(); -// dataMessage.groupMessage = super.groupMessage(); -// dataMessage.groupMessage.promoteMessage = new SignalService.GroupPromoteMessage(); -// dataMessage.groupMessage.promoteMessage.privateKey = from_hex(this.privateKey); - -// return dataMessage; -// } -// } diff --git a/ts/session/utils/job_runners/jobs/JobRunnerType.ts b/ts/session/utils/job_runners/jobs/JobRunnerType.ts index c88f9a4ba..d24a2dc78 100644 --- a/ts/session/utils/job_runners/jobs/JobRunnerType.ts +++ b/ts/session/utils/job_runners/jobs/JobRunnerType.ts @@ -1,6 +1,5 @@ export type JobRunnerType = | 'ConfigurationSyncJob' - | 'ConfigurationSyncDumpJob' | 'FakeSleepForJob' | 'FakeSleepForMultiJob' | 'AvatarDownloadJob'; diff --git a/ts/test/automation/disappearing_messages.spec.ts b/ts/test/automation/disappearing_messages.spec.ts index b19c33d21..1e88e4d37 100644 --- a/ts/test/automation/disappearing_messages.spec.ts +++ b/ts/test/automation/disappearing_messages.spec.ts @@ -7,7 +7,7 @@ import { clickOnMatchingText, clickOnTestIdWithText, waitForMatchingText, - waitForTestIdWithText + waitForTestIdWithText, } from './utilities/utils'; // tslint:disable: no-console @@ -20,9 +20,9 @@ sessionTestTwoWindows('Disappearing messages', async ([windowA, windowB]) => { // Create User const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]); // Create Contact - await createContact(windowA, windowB, userA, userB) + await createContact(windowA, windowB, userA, userB); // Click on user's avatar to open conversation options - await clickOnTestIdWithText(windowA, 'conversation-options-avatar') + await clickOnTestIdWithText(windowA, 'conversation-options-avatar'); // Select disappearing messages drop down await clickOnMatchingText(windowA, 'Disappearing messages'); // Select 5 seconds @@ -74,7 +74,7 @@ sessionTestTwoWindows('Disappearing messages', async ([windowA, windowB]) => { `${userA.userName} set the disappearing message timer to 5 seconds` ); // Wait 5 seconds - await sleepFor(5000) + await sleepFor(5000); await waitForMatchingText(windowB, `${userA.userName} has turned off disappearing messages.`); // verify message is deleted in windowB const errorDesc2 = 'Should not be found'; diff --git a/ts/test/automation/linked_device_user.spec.ts b/ts/test/automation/linked_device_user.spec.ts index 12ebe2b28..6b1690202 100644 --- a/ts/test/automation/linked_device_user.spec.ts +++ b/ts/test/automation/linked_device_user.spec.ts @@ -14,7 +14,7 @@ import { typeIntoInput, waitForMatchingText, waitForTestIdWithText, - waitForTextMessage + waitForTextMessage, } from './utilities/utils'; const windows: Array = []; diff --git a/ts/test/automation/setup/beforeEach.ts b/ts/test/automation/setup/beforeEach.ts index b0f7f421f..f47f97418 100644 --- a/ts/test/automation/setup/beforeEach.ts +++ b/ts/test/automation/setup/beforeEach.ts @@ -27,14 +27,14 @@ function cleanUpOtherTest() { const parentFolderOfAllDataPath = isMacOS() ? '~/Library/Application Support/' : isLinux() - ? homedir() + '/.config/' + ? `${homedir()}/.config/` : null; if (!parentFolderOfAllDataPath) { throw new Error('Only macOS is currrently supported '); } if (!parentFolderOfAllDataPath || parentFolderOfAllDataPath.length < 9) { - throw new Error('parentFolderOfAllDataPath not found or invalid:' + parentFolderOfAllDataPath); + throw new Error(`parentFolderOfAllDataPath not found or invalid: ${parentFolderOfAllDataPath}`); } console.info('cleaning other tests leftovers...', parentFolderOfAllDataPath); diff --git a/ts/test/automation/setup/sessionTest.ts b/ts/test/automation/setup/sessionTest.ts index afba32320..4b92a80c8 100644 --- a/ts/test/automation/setup/sessionTest.ts +++ b/ts/test/automation/setup/sessionTest.ts @@ -17,7 +17,7 @@ type _TupleOf = R['length'] extends N type CountWindows = 1 | 2 | 3 | 4 | 5; -async function sessionTest>( +function sessionTest>( testName: string, testCallback: (windows: N) => Promise, count: T @@ -43,35 +43,35 @@ async function sessionTest>( }); } -export async function sessionTestOneWindow( +export function sessionTestOneWindow( testName: string, testCallback: (windows: Tuple) => Promise ) { return sessionTest(testName, testCallback, 1); } -export async function sessionTestTwoWindows( +export function sessionTestTwoWindows( testName: string, testCallback: ([windowA, windowB]: [Page, Page]) => Promise ) { return sessionTest(testName, testCallback, 2); } -export async function sessionTestThreeWindows( +export function sessionTestThreeWindows( testName: string, testCallback: ([windowA, windowB, windowC]: [Page, Page, Page]) => Promise ) { return sessionTest(testName, testCallback, 3); } -export async function sessionTestFourWindows( +export function sessionTestFourWindows( testName: string, testCallback: ([windowA, windowB, windowC, windowD]: [Page, Page, Page, Page]) => Promise ) { return sessionTest(testName, testCallback, 4); } -export async function sessionTestFiveWindows( +export function sessionTestFiveWindows( testName: string, testCallback: ([windowA, windowB, windowC, windowD]: [Page, Page, Page, Page, Page]) => Promise< void diff --git a/ts/test/automation/tslint.json b/ts/test/automation/tslint.json new file mode 100644 index 000000000..ff7a903b3 --- /dev/null +++ b/ts/test/automation/tslint.json @@ -0,0 +1,10 @@ +{ + "defaultSeverity": "error", + "extends": ["../tslint.json"], + "rules": { + "no-empty": false, + "array-type": false, + "no-console": false, + "no-void-expression": false + } +} diff --git a/ts/test/session/unit/receiver/opengroup/deduplicate_test.ts b/ts/test/session/unit/receiver/opengroup/deduplicate_test.ts index 44977ddc5..ac7bd2ecd 100644 --- a/ts/test/session/unit/receiver/opengroup/deduplicate_test.ts +++ b/ts/test/session/unit/receiver/opengroup/deduplicate_test.ts @@ -94,11 +94,4 @@ describe('filterDuplicatesFromDbAndIncomingV4', () => { expect(filtered[0]).to.be.deep.eq(msg1); }); }); - - describe('filters duplicated message from database', () => { - //sadly better-sqlite3 does not allow us to easily create an in memory db for now (issues with sqlite binary) - // so testing this part is not easy as all the logic is made in sqlite - // tslint:disable-next-line: no-empty - it.skip('in memory database', () => {}); - }); }); diff --git a/ts/test/session/unit/receiving/ConfigurationMessage_test.ts b/ts/test/session/unit/receiving/ConfigurationMessage_test.ts index b462971fc..7a8e9f62f 100644 --- a/ts/test/session/unit/receiving/ConfigurationMessage_test.ts +++ b/ts/test/session/unit/receiving/ConfigurationMessage_test.ts @@ -1,7 +1,7 @@ // tslint:disable: no-implicit-dependencies -import { SignalService } from '../../../../protobuf'; import chai from 'chai'; +import { SignalService } from '../../../../protobuf'; import { ConfigurationMessage } from '../../../../session/messages/outgoing/controlMessage/ConfigurationMessage'; import { UserUtils } from '../../../../session/utils'; @@ -13,13 +13,15 @@ import { EnvelopePlus } from '../../../../receiver/types'; import chaiAsPromised from 'chai-as-promised'; import { ConfigMessageHandler } from '../../../../receiver/configMessage'; +import { ConfigurationSync } from '../../../../session/utils/job_runners/jobs/ConfigurationSyncJob'; +import { ReleasedFeatures } from '../../../../util/releaseFeature'; import { stubData } from '../../../test-utils/utils'; chai.use(chaiAsPromised as any); chai.should(); const { expect } = chai; -describe('ConfigurationMessage_receiving', () => { +describe('handleConfigurationMessageLegacy_receiving', () => { let createOrUpdateStub: Sinon.SinonStub; let getItemByIdStub: Sinon.SinonStub; let sender: string; @@ -39,6 +41,8 @@ describe('ConfigurationMessage_receiving', () => { displayName: 'displayName', contacts: [], }); + Sinon.stub(ConfigurationSync, 'queueNewJobIfNeeded').resolves(); + TestUtils.stubWindow('setSettingValue', () => undefined); }); afterEach(() => { @@ -46,18 +50,26 @@ describe('ConfigurationMessage_receiving', () => { }); it('should not be processed if we do not have a pubkey', async () => { + TestUtils.stubWindowLog(); Sinon.stub(UserUtils, 'getOurPubKeyStrFromCache').resolves(undefined); + envelope = TestUtils.generateEnvelopePlus(sender); const proto = config.contentProto(); createOrUpdateStub = stubData('createOrUpdateItem').resolves(); getItemByIdStub = stubData('getItemById').resolves(); + const checkIsUserConfigFeatureReleasedStub = Sinon.stub( + ReleasedFeatures, + 'checkIsUserConfigFeatureReleased' + ).resolves(false); await ConfigMessageHandler.handleConfigurationMessageLegacy( envelope, proto.configurationMessage as SignalService.ConfigurationMessage ); + expect(createOrUpdateStub.callCount).to.equal(0); expect(getItemByIdStub.callCount).to.equal(0); + expect(checkIsUserConfigFeatureReleasedStub.callCount).to.be.eq(1); // should only have the one as part of the global legacy check, but none for the smaller handlers }); describe('with ourNumber set', () => { @@ -71,7 +83,7 @@ describe('ConfigurationMessage_receiving', () => { const proto = config.contentProto(); // sender !== ourNumber envelope = TestUtils.generateEnvelopePlus(sender); - + Sinon.stub(ReleasedFeatures, 'checkIsUserConfigFeatureReleased').resolves(false); createOrUpdateStub = stubData('createOrUpdateItem').resolves(); getItemByIdStub = stubData('getItemById').resolves(); await ConfigMessageHandler.handleConfigurationMessageLegacy( @@ -81,15 +93,5 @@ describe('ConfigurationMessage_receiving', () => { expect(createOrUpdateStub.callCount).to.equal(0); expect(getItemByIdStub.callCount).to.equal(0); }); - - // it('should be processed if the message is coming from our number', async () => { - // const proto = config.contentProto(); - // envelope = TestUtils.generateEnvelopePlus(ourNumber); - - // createOrUpdateStub = sandbox.stub(data, 'createOrUpdateItem').resolves(); - // getItemByIdStub = sandbox.stub(data, 'getItemById').resolves(); - // await handleConfigurationMessageLegacy(envelope, proto.configurationMessage as SignalService.ConfigurationMessage); - // expect(getItemByIdStub.callCount).to.equal(1); - // }); }); }); diff --git a/ts/test/session/unit/swarm_polling/SwarmPolling_test.ts b/ts/test/session/unit/swarm_polling/SwarmPolling_test.ts index de03273fa..f1be4f069 100644 --- a/ts/test/session/unit/swarm_polling/SwarmPolling_test.ts +++ b/ts/test/session/unit/swarm_polling/SwarmPolling_test.ts @@ -15,7 +15,9 @@ import { SWARM_POLLING_TIMEOUT } from '../../../../session/constants'; import { getConversationController } from '../../../../session/conversations'; import { PubKey } from '../../../../session/types'; import { UserUtils } from '../../../../session/utils'; +import { ConfigurationSync } from '../../../../session/utils/job_runners/jobs/ConfigurationSyncJob'; import { sleepFor } from '../../../../session/utils/Promise'; +import { UserGroupsWrapperActions } from '../../../../webworker/workers/browser/libsession_worker_interface'; import { TestUtils } from '../../../test-utils'; import { generateFakeSnodes, stubData } from '../../../test-utils/utils'; // tslint:disable: chai-vague-errors @@ -41,6 +43,8 @@ describe('SwarmPolling', () => { beforeEach(async () => { getConversationController().reset(); TestUtils.stubWindowFeatureFlags(); + Sinon.stub(ConfigurationSync, 'queueNewJobIfNeeded').resolves(); + // Utils Stubs Sinon.stub(UserUtils, 'getOurPubKeyStrFromCache').returns(ourNumber); @@ -75,6 +79,9 @@ describe('SwarmPolling', () => { }); describe('getPollingTimeout', () => { + beforeEach(() => { + TestUtils.stubLibSessionWorker(undefined); + }); it('returns INACTIVE for non existing convo', () => { const fakeConvo = TestUtils.generateFakePubKey(); @@ -200,7 +207,7 @@ describe('SwarmPolling', () => { await swarmPolling.start(true); expect(pollOnceForKeySpy.callCount).to.eq(1); - expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]); + expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); }); it('does run for our pubkey even if activeAt is recent ', async () => { @@ -212,27 +219,16 @@ describe('SwarmPolling', () => { await swarmPolling.start(true); expect(pollOnceForKeySpy.callCount).to.eq(1); - expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]); - }); - - it('does run for our pubkey even if activeAt is recent ', async () => { - const convo = getConversationController().getOrCreate( - ourNumber, - ConversationTypeEnum.PRIVATE - ); - convo.set('active_at', Date.now()); - await swarmPolling.start(true); - - expect(pollOnceForKeySpy.callCount).to.eq(1); - expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]); + expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); }); describe('legacy group', () => { - it('does run for group pubkey on start no matter the recent timestamp ', async () => { + it('does run for group pubkey on start no matter the recent timestamp', async () => { const convo = getConversationController().getOrCreate( TestUtils.generateFakePubKeyStr(), ConversationTypeEnum.GROUP ); + TestUtils.stubLibSessionWorker(undefined); convo.set('active_at', Date.now()); const groupConvoPubkey = PubKey.cast(convo.id as string); swarmPolling.addGroupId(groupConvoPubkey); @@ -240,23 +236,7 @@ describe('SwarmPolling', () => { // 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.generateFakePubKeyStr(), - ConversationTypeEnum.GROUP - ); - 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.firstCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]); }); @@ -265,6 +245,7 @@ describe('SwarmPolling', () => { TestUtils.generateFakePubKeyStr(), ConversationTypeEnum.GROUP ); + TestUtils.stubLibSessionWorker(undefined); getItemByIdStub.restore(); getItemByIdStub = TestUtils.stubData('getItemById'); getItemByIdStub @@ -281,7 +262,7 @@ describe('SwarmPolling', () => { // 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.firstCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]); getItemByIdStub.restore(); getItemByIdStub = TestUtils.stubData('getItemById'); @@ -294,6 +275,7 @@ describe('SwarmPolling', () => { TestUtils.generateFakePubKeyStr(), ConversationTypeEnum.GROUP ); + TestUtils.stubLibSessionWorker(undefined); convo.set('active_at', 1); // really old, but active const groupConvoPubkey = PubKey.cast(convo.id as string); @@ -306,9 +288,9 @@ describe('SwarmPolling', () => { await swarmPolling.pollForAllKeys(); expect(pollOnceForKeySpy.callCount).to.eq(3); - expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]); + expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]); - expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0]]); + expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); }); it('does run twice if activeAt less than one hour ', async () => { @@ -317,27 +299,31 @@ describe('SwarmPolling', () => { ConversationTypeEnum.GROUP ); + // fake that the group is part of the wrapper otherwise we stop tracking it after the first polling event + Sinon.stub(UserGroupsWrapperActions, 'getLegacyGroup').resolves({} as any); + convo.set('active_at', Date.now()); const groupConvoPubkey = PubKey.cast(convo.id as string); swarmPolling.addGroupId(groupConvoPubkey); await swarmPolling.start(true); expect(pollOnceForKeySpy.callCount).to.eq(2); - expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]); + expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]); + pollOnceForKeySpy.resetHistory(); 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 id) * - 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 */ + await sleepFor(10); - expect(pollOnceForKeySpy.callCount).to.eq(4); - expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0]]); + expect(pollOnceForKeySpy.callCount).to.eq(2); + expect(pollOnceForKeySpy.firstCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); 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 () => { @@ -345,7 +331,8 @@ describe('SwarmPolling', () => { TestUtils.generateFakePubKeyStr(), ConversationTypeEnum.GROUP ); - + // fake that the group is part of the wrapper otherwise we stop tracking it after the first polling event + Sinon.stub(UserGroupsWrapperActions, 'getLegacyGroup').resolves({} as any); pollOnceForKeySpy.resetHistory(); convo.set('active_at', Date.now()); const groupConvoPubkey = PubKey.cast(convo.id as string); @@ -365,9 +352,9 @@ describe('SwarmPolling', () => { 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.firstCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]); - expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0]]); + expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); expect(pollOnceForKeySpy.getCalls()[3].args).to.deep.eq([groupConvoPubkey, true, [-10]]); }); @@ -377,7 +364,7 @@ describe('SwarmPolling', () => { ConversationTypeEnum.GROUP ); pollOnceForKeySpy.resetHistory(); - + TestUtils.stubLibSessionWorker(undefined); convo.set('active_at', Date.now()); const groupConvoPubkey = PubKey.cast(convo.id as string); swarmPolling.addGroupId(groupConvoPubkey); @@ -392,7 +379,7 @@ describe('SwarmPolling', () => { // 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]]); + expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); }); describe('multiple runs', () => { @@ -404,6 +391,7 @@ describe('SwarmPolling', () => { TestUtils.generateFakePubKeyStr(), ConversationTypeEnum.GROUP ); + TestUtils.stubLibSessionWorker({}); convo.set('active_at', Date.now()); groupConvoPubkey = PubKey.cast(convo.id as string); @@ -411,6 +399,13 @@ describe('SwarmPolling', () => { await swarmPolling.start(true); }); + afterEach(() => { + Sinon.restore(); + getConversationController().reset(); + clock.restore(); + resetHardForkCachedValues(); + }); + it('does run twice if activeAt is less than 2 days', async () => { pollOnceForKeySpy.resetHistory(); // less than 2 days old, this is an active group @@ -426,29 +421,33 @@ describe('SwarmPolling', () => { // 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.firstCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]); - expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0]]); + expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); 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 () => { + it('does run twice if activeAt is more than 2 days old and we tick more than one minute', async () => { pollOnceForKeySpy.resetHistory(); + TestUtils.stubWindowLog(); convo.set('active_at', Date.now() - 2 * 25 * 3600 * 1000); // medium active + // fake that the group is part of the wrapper otherwise we stop tracking it after the first polling event - const timeToTick = 65 * 1000; + const timeToTick = 65 * 1000; // more than one minute swarmPolling.forcePolledTimestamp(convo.id, timeToTick); - clock.tick(timeToTick); // should tick twice more (one more our direct pubkey and one for the group) + // fake that the group is part of the wrapper otherwise we stop tracking it after the first polling event + 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.firstCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); expect(pollOnceForKeySpy.secondCall.args).to.deep.eq([groupConvoPubkey, true, [-10]]); - expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0]]); + expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq([ourPubkey, false, [0, 2, 3, 5, 4]]); expect(pollOnceForKeySpy.getCalls()[3].args).to.deep.eq([groupConvoPubkey, true, [-10]]); }); }); diff --git a/ts/test/test-utils/utils/stubbing.ts b/ts/test/test-utils/utils/stubbing.ts index 362060e15..8ff01faf8 100644 --- a/ts/test/test-utils/utils/stubbing.ts +++ b/ts/test/test-utils/utils/stubbing.ts @@ -5,6 +5,7 @@ import { OpenGroupData } from '../../../data/opengroups'; import { ConfigDumpData } from '../../../data/configDump/configDump'; import * as utilWorker from '../../../webworker/workers/browser/util_worker_interface'; +import * as libsessionWorker from '../../../webworker/workers/browser/libsession_worker_interface'; const globalAny: any = global; @@ -38,6 +39,11 @@ export function stubUtilWorker(fnName: string, returnedValue: any): sinon.SinonS .withArgs(fnName as any) .resolves(returnedValue); } + +export function stubLibSessionWorker(value: any) { + Sinon.stub(libsessionWorker, 'callLibSessionWorker').resolves(value); +} + export function stubCreateObjectUrl() { // tslint:disable-next-line: no-empty no-function-expression (global as any).URL = function() {}; diff --git a/ts/types/Util.ts b/ts/types/Util.ts index 5e494da0d..ccea6b792 100644 --- a/ts/types/Util.ts +++ b/ts/types/Util.ts @@ -7,5 +7,3 @@ export type RenderTextCallbackType = (options: { }) => JSX.Element; export type LocalizerType = (key: LocalizerKeys, values?: Array) => string; - -export type FixedLengthArray = Array & { length: Length }; diff --git a/ts/webworker/workers/browser/libsession_worker_interface.ts b/ts/webworker/workers/browser/libsession_worker_interface.ts index 030515e35..0d746ea08 100644 --- a/ts/webworker/workers/browser/libsession_worker_interface.ts +++ b/ts/webworker/workers/browser/libsession_worker_interface.ts @@ -314,6 +314,8 @@ export const ConvoInfoVolatileWrapperActions: ConvoInfoVolatileWrapperActionsCal ]) as Promise>, }; -const callLibSessionWorker = async (callToMake: LibSessionWorkerFunctions): Promise => { +export const callLibSessionWorker = async ( + callToMake: LibSessionWorkerFunctions +): Promise => { return internalCallLibSessionWorker(callToMake); };