test: add tests for swarmPolling of new groups 03

pull/2873/head
Audric Ackermann 2 years ago
parent e69c5c4b35
commit cc7e6f03db

@ -366,31 +366,15 @@ export class SwarmPolling {
type,
});
const shouldDiscardMessages = await this.shouldLeaveNotPolledGroup({ type, pubkey });
if (shouldDiscardMessages) {
return;
}
perfStart(`handleSeenMessages-${pubkey}`);
const newMessages = await this.handleSeenMessages(uniqOtherMsgs);
perfEnd(`handleSeenMessages-${pubkey}`, 'handleSeenMessages');
const allLegacyGroupsInWrapper = await UserGroupsWrapperActions.getAllLegacyGroups();
const allGroupsInWrapper = await UserGroupsWrapperActions.getAllGroups();
// don't handle incoming messages from group when the group is not tracked.
// this can happen when a group is removed from the wrapper while we were polling
if (
type === ConversationTypeEnum.GROUP &&
pubkey.startsWith('05') &&
!allLegacyGroupsInWrapper.some(m => m.pubkeyHex === pubkey) // just check if a legacy group with that pubkey exists
) {
// not tracked anymore in the wrapper. Discard messages and stop polling
await this.notPollingForGroupAsNotInWrapper(pubkey, 'not in wrapper after poll');
return;
}
if (PubKey.isClosedGroupV2(pubkey) && !allGroupsInWrapper.some(m => m.pubkeyHex === pubkey)) {
// not tracked anymore in the wrapper. Discard messages and stop polling
await this.notPollingForGroupAsNotInWrapper(pubkey, 'not in wrapper after poll');
return;
}
// trigger the handling of all the other messages, not shared config related
newMessages.forEach(m => {
const content = extractWebSocketContent(m.data, m.hash);
@ -408,6 +392,34 @@ export class SwarmPolling {
});
}
private async shouldLeaveNotPolledGroup({
pubkey,
type,
}: {
type: ConversationTypeEnum;
pubkey: string;
}) {
const allLegacyGroupsInWrapper = await UserGroupsWrapperActions.getAllLegacyGroups();
const allGroupsInWrapper = await UserGroupsWrapperActions.getAllGroups();
// don't handle incoming messages from group when the group is not tracked.
// this can happen when a group is removed from the wrapper while we were polling
const newGroupButNotInWrapper =
PubKey.isClosedGroupV2(pubkey) && !allGroupsInWrapper.some(m => m.pubkeyHex === pubkey);
const legacyGroupButNoInWrapper =
type === ConversationTypeEnum.GROUP &&
pubkey.startsWith('05') &&
!allLegacyGroupsInWrapper.some(m => m.pubkeyHex === pubkey);
if (newGroupButNotInWrapper || legacyGroupButNoInWrapper) {
// not tracked anymore in the wrapper. Discard messages and stop polling
await this.notPollingForGroupAsNotInWrapper(pubkey, 'not in wrapper after poll');
return true;
}
return false;
}
private async getHashesToBump(
type: ConversationTypeEnum,
pubkey: string

@ -24,6 +24,8 @@ const pollOnceForGroupLegacyArgs = (groupLegacy: string) => [
[groupLegacy, ConversationTypeEnum.GROUP],
];
const pollOnceForGroupArgs = (group: GroupPubkeyType) => [[group, ConversationTypeEnum.GROUPV3]];
function stubWithLegacyGroups(pubkeys: Array<string>) {
const groups = pubkeys.map(m => ({ pubkeyHex: m }) as LegacyGroupInfo);
TestUtils.stubUserGroupWrapper('getAllLegacyGroups', groups);
@ -341,5 +343,222 @@ describe('SwarmPolling:pollForAllKeys', () => {
});
});
it.skip('do the same for neww groups');
describe('03 group', () => {
it('does run for group pubkey on start no matter the recent timestamp', async () => {
const groupPk = TestUtils.generateFakeClosedGroupV3PkStr();
const convo = ConvoHub.use().getOrCreate(groupPk, ConversationTypeEnum.GROUPV3);
stubWithLegacyGroups([]);
stubWithGroups([groupPk]);
convo.set('active_at', Date.now());
const groupConvoPubkey = PubKey.cast(groupPk);
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(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq(pollOnceForGroupArgs(groupPk));
});
it('does only poll from -10 for closed groups', async () => {
const groupPk = TestUtils.generateFakeClosedGroupV3PkStr();
const convo = ConvoHub.use().getOrCreate(groupPk, ConversationTypeEnum.GROUPV3);
stubWithLegacyGroups([]);
stubWithGroups([groupPk]);
convo.set('active_at', 1);
swarmPolling.addGroupId(PubKey.cast(groupPk));
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(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq(pollOnceForGroupArgs(groupPk));
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 groupPk = TestUtils.generateFakeClosedGroupV3PkStr();
const convo = ConvoHub.use().getOrCreate(groupPk, ConversationTypeEnum.GROUPV3);
stubWithLegacyGroups([]);
stubWithGroups([groupPk]);
convo.set('active_at', 1); // really old, but active
swarmPolling.addGroupId(groupPk);
// this calls the stub 2 times, one for our direct pubkey and one for the group
await swarmPolling.start(true);
expect(pollOnceForKeySpy.callCount).to.eq(2);
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq(pollOnceForGroupArgs(groupPk));
// 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.thirdCall.args).to.deep.eq(pollOnceForUsArgs(ourPubkey.key));
});
it('does run twice if activeAt less than one hour ', async () => {
const groupPk = TestUtils.generateFakeClosedGroupV3PkStr();
const convo = ConvoHub.use().getOrCreate(groupPk, ConversationTypeEnum.GROUPV3);
stubWithLegacyGroups([]);
stubWithGroups([groupPk]);
convo.set('active_at', Date.now());
swarmPolling.addGroupId(groupPk);
await swarmPolling.start(true);
expect(pollOnceForKeySpy.callCount).to.eq(2);
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq(pollOnceForGroupArgs(groupPk));
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(2);
expect(pollOnceForKeySpy.firstCall.args).to.deep.eq(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq(pollOnceForGroupArgs(groupPk));
});
it('does run twice if activeAt is inactive and we tick longer than 2 minutes', async () => {
const groupPk = TestUtils.generateFakeClosedGroupV3PkStr();
const convo = ConvoHub.use().getOrCreate(groupPk, ConversationTypeEnum.GROUPV3);
stubWithLegacyGroups([]);
stubWithGroups([groupPk]);
pollOnceForKeySpy.resetHistory();
convo.set('active_at', Date.now());
swarmPolling.addGroupId(groupPk);
// 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(groupPk, 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
*/
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(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq(pollOnceForGroupArgs(groupPk));
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.getCalls()[3].args).to.deep.eq(pollOnceForGroupArgs(groupPk));
});
it('does run once only if group is inactive and we tick less than 2 minutes ', async () => {
const groupPk = TestUtils.generateFakeClosedGroupV3PkStr();
const convo = ConvoHub.use().getOrCreate(groupPk, ConversationTypeEnum.GROUPV3);
stubWithLegacyGroups([]);
stubWithGroups([groupPk]);
convo.set('active_at', Date.now());
swarmPolling.addGroupId(groupPk);
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);
await sleepFor(10);
// 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(pollOnceForGroupArgs(groupPk)); // this one comes from the swarmPolling.start
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq(pollOnceForUsArgs(ourPubkey.key));
});
describe('multiple runs', () => {
let convo: ConversationModel;
let groupConvoPubkey: PubKey;
beforeEach(async () => {
convo = ConvoHub.use().getOrCreate(
TestUtils.generateFakeClosedGroupV3PkStr(),
ConversationTypeEnum.GROUPV3
);
stubWithLegacyGroups([]);
stubWithGroups([convo.id]);
convo.set('active_at', Date.now());
groupConvoPubkey = PubKey.cast(convo.id as string);
swarmPolling.addGroupId(groupConvoPubkey);
await swarmPolling.start(true);
});
afterEach(() => {
Sinon.restore();
ConvoHub.use().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
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(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq(
pollOnceForGroupArgs(groupConvoPubkey.key as GroupPubkeyType)
);
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.getCalls()[3].args).to.deep.eq(
pollOnceForGroupArgs(groupConvoPubkey.key as GroupPubkeyType)
);
});
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; // 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(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.secondCall.args).to.deep.eq(
pollOnceForGroupArgs(groupConvoPubkey.key as GroupPubkeyType)
);
expect(pollOnceForKeySpy.thirdCall.args).to.deep.eq(pollOnceForUsArgs(ourPubkey.key));
expect(pollOnceForKeySpy.getCalls()[3].args).to.deep.eq(
pollOnceForGroupArgs(groupConvoPubkey.key as GroupPubkeyType)
);
});
});
});
});

Loading…
Cancel
Save