From 2f8598c88c622f09d90ae75600df415dd587d498 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Wed, 15 Jun 2022 13:23:54 -0300 Subject: [PATCH 1/3] Add singleSync tests for shared client. Avoid pushManager instantiation if singleSync is enabled --- src/sync/__tests__/syncManagerOnline.spec.ts | 134 ++++++++++++++++--- src/sync/syncManagerOnline.ts | 8 +- 2 files changed, 120 insertions(+), 22 deletions(-) diff --git a/src/sync/__tests__/syncManagerOnline.spec.ts b/src/sync/__tests__/syncManagerOnline.spec.ts index 93678113..dd531b8f 100644 --- a/src/sync/__tests__/syncManagerOnline.spec.ts +++ b/src/sync/__tests__/syncManagerOnline.spec.ts @@ -4,6 +4,7 @@ import { syncManagerOnlineFactory } from '../syncManagerOnline'; import { pushManagerFactory } from '../streaming/pushManager'; import { IPushManager } from '../streaming/types'; import { EventEmitter } from '../../utils/MinEvents'; +import { IReadinessManager } from '../../readiness/types'; jest.mock('../submitters/submitterManager', () => { return { @@ -22,6 +23,45 @@ const paramsMock = { start: jest.fn() }; +const ALWAYS_ON_SPLIT = '{"trafficTypeName":"user","name":"always-on","trafficAllocation":100,"trafficAllocationSeed":1012950810,"seed":-725161385,"status":"ACTIVE","killed":false,"defaultTreatment":"off","changeNumber":1494364996459,"algo":2,"conditions":[{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":null},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":null,"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}'; +const ALWAYS_OFF_SPLIT = '{"trafficTypeName":"user","name":"always-off","trafficAllocation":100,"trafficAllocationSeed":-331690370,"seed":403891040,"status":"ACTIVE","killed":false,"defaultTreatment":"on","changeNumber":1494365020316,"algo":2,"conditions":[{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":null},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":null,"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment all"}]}'; + +const STORED_SPLITS: Record = {}; +STORED_SPLITS['always-on'] = ALWAYS_ON_SPLIT; +STORED_SPLITS['always-off'] = ALWAYS_OFF_SPLIT; + +// Mocked storageManager +const storageManagerMock = { + splits: { + getSplit: (name: string) => STORED_SPLITS[name], + usesSegments: () => false + } +}; + +// @ts-expect-error +// Mocked readinessManager +let readinessManagerMock = { + isReady: jest.fn(() => true) // Fake the signal for the non ready SDK +} as IReadinessManager; + + +// Mocked pollingManager +const pollingManagerMock = { + syncAll: jest.fn(), + start: jest.fn(), + stop: jest.fn(), + isRunning: jest.fn(), + add: jest.fn(()=>{return {isrunning: () => true};}), + get: jest.fn() +}; + +// Mocked pushManager +const pushManagerMock = pushManagerFactory({ // @ts-ignore + ...paramsMock, splitApi: { fetchAuth: jest.fn() } +}, {}) as IPushManager; + +pushManagerMock.start = jest.fn(); + test('syncManagerOnline should start or not the submitter depending on user consent status', () => { const settings = { ...fullSettings }; @@ -57,41 +97,99 @@ test('syncManagerOnline should start or not the submitter depending on user cons test('syncManagerOnline should syncAll a single time in singleSync mode', () => { const settings = { ...fullSettings }; + // Enable single sync settings.sync.singleSync = true; - const pollingManager = { - syncAll: jest.fn(), - start: jest.fn(), - stop: jest.fn(), - isRunning: jest.fn() - }; + // @ts-ignore + const pollingSyncManager = syncManagerOnlineFactory(() => pollingManagerMock)({ settings }); - const fetchAuthMock = jest.fn(); + expect(pollingSyncManager.pushManager).toBeUndefined(); - // @ts-ignore - const pollingSyncManager = syncManagerOnlineFactory(() => pollingManager)({ settings }); + // Test pollingManager for Main client + pollingSyncManager.start(); + + expect(pollingManagerMock.start).not.toBeCalled(); + expect(pollingManagerMock.syncAll).toBeCalledTimes(1); + + pollingSyncManager.stop(); + pollingSyncManager.start(); + expect(pollingManagerMock.start).not.toBeCalled(); + expect(pollingManagerMock.syncAll).toBeCalledTimes(1); + + pollingSyncManager.stop(); pollingSyncManager.start(); - expect(pollingManager.start).not.toBeCalled(); - expect(pollingManager.syncAll).toBeCalledTimes(1); + expect(pollingManagerMock.start).not.toBeCalled(); + expect(pollingManagerMock.syncAll).toBeCalledTimes(1); pollingSyncManager.stop(); - const pushManager = pushManagerFactory({ // @ts-ignore - ...paramsMock, splitApi: { fetchAuth: fetchAuthMock } - }, {}) as IPushManager; + // @ts-ignore + // Test pollingManager for shared client + const pollingSyncManagerShared = pollingSyncManager.shared('sharedKey', readinessManagerMock, storageManagerMock); + + if (!pollingSyncManagerShared) throw new Error('pollingSyncManagerShared should exist'); + + pollingSyncManagerShared.start(); - pushManager.start = jest.fn(); + expect(pollingManagerMock.start).not.toBeCalled(); + + pollingSyncManagerShared.stop(); + pollingSyncManagerShared.start(); + + expect(pollingManagerMock.start).not.toBeCalled(); + + pollingSyncManagerShared.stop(); // @ts-ignore - const pushingSyncManager = syncManagerOnlineFactory(() => pollingManager, () => pushManager)({ settings }); + // Test pushManager for main client + const pushingSyncManager = syncManagerOnlineFactory(() => pollingManagerMock, () => pushManagerMock)({ settings }); pushingSyncManager.start(); - expect(pushManager.start).not.toBeCalled(); - expect(pollingManager.start).not.toBeCalled(); + expect(pushManagerMock.start).not.toBeCalled(); + expect(pollingManagerMock.start).not.toBeCalled(); pushingSyncManager.stop(); + pushingSyncManager.start(); + + expect(pushManagerMock.start).not.toBeCalled(); + expect(pollingManagerMock.start).not.toBeCalled(); + + pushingSyncManager.stop(); + + // @ts-ignore + // Test pollingManager for shared client + const pushingSyncManagerShared = pushingSyncManager.shared('pushingSharedKey', readinessManagerMock, storageManagerMock); + + if (!pushingSyncManagerShared) throw new Error('pushingSyncManagerShared should exist'); + + pushingSyncManagerShared.start(); + + expect(pushManagerMock.start).not.toBeCalled(); + expect(pollingManagerMock.start).not.toBeCalled(); + + pushingSyncManagerShared.stop(); + pushingSyncManagerShared.start(); + + expect(pushManagerMock.start).not.toBeCalled(); + expect(pollingManagerMock.start).not.toBeCalled(); + + pushingSyncManagerShared.stop(); + + settings.sync.singleSync = false; + // @ts-ignore + // pushManager instantiation control test + const testSyncManager = syncManagerOnlineFactory(() => pollingManagerMock, () => pushManagerMock)({ settings }); + + expect(testSyncManager.pushManager).not.toBeUndefined(); + + // Test pollingManager for Main client + testSyncManager.start(); + + expect(pushManagerMock.start).toBeCalled(); + + testSyncManager.stop(); }); diff --git a/src/sync/syncManagerOnline.ts b/src/sync/syncManagerOnline.ts index 73f5658a..f51bcce3 100644 --- a/src/sync/syncManagerOnline.ts +++ b/src/sync/syncManagerOnline.ts @@ -28,13 +28,13 @@ export function syncManagerOnlineFactory( */ return function (params: ISdkFactoryContextSync): ISyncManagerCS { - const { settings, settings: { log, streamingEnabled }, telemetryTracker } = params; + const { settings, settings: { log, streamingEnabled, sync: { singleSync } }, telemetryTracker } = params; /** Polling Manager */ const pollingManager = pollingManagerFactory && pollingManagerFactory(params); /** Push Manager */ - const pushManager = streamingEnabled && pollingManager && pushManagerFactory ? + const pushManager = !singleSync && streamingEnabled && pollingManager && pushManagerFactory ? pushManagerFactory(params, pollingManager) : undefined; @@ -91,7 +91,7 @@ export function syncManagerOnlineFactory( if (pollingManager) { // If singleSync is enabled pushManager and pollingManager should not start - if (settings.sync.singleSync === true) { + if (singleSync === true) { if (startFirstTime) { pollingManager.syncAll(); startFirstTime = false; @@ -147,7 +147,7 @@ export function syncManagerOnlineFactory( return { isRunning: mySegmentsSyncTask.isRunning, start() { - if (settings.sync.singleSync === true) { + if (singleSync === true) { if (!readinessManager.isReady()) mySegmentsSyncTask.execute(); } else { if (pushManager) { From d07638431aeb5a4e14f2b3579c4a32ee9ec33bb2 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Wed, 15 Jun 2022 14:54:03 -0300 Subject: [PATCH 2/3] Use one syncManager instance for tests --- src/sync/__tests__/syncManagerOnline.spec.ts | 41 +++++++------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/src/sync/__tests__/syncManagerOnline.spec.ts b/src/sync/__tests__/syncManagerOnline.spec.ts index dd531b8f..434ce24c 100644 --- a/src/sync/__tests__/syncManagerOnline.spec.ts +++ b/src/sync/__tests__/syncManagerOnline.spec.ts @@ -23,17 +23,9 @@ const paramsMock = { start: jest.fn() }; -const ALWAYS_ON_SPLIT = '{"trafficTypeName":"user","name":"always-on","trafficAllocation":100,"trafficAllocationSeed":1012950810,"seed":-725161385,"status":"ACTIVE","killed":false,"defaultTreatment":"off","changeNumber":1494364996459,"algo":2,"conditions":[{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":null},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":null,"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}'; -const ALWAYS_OFF_SPLIT = '{"trafficTypeName":"user","name":"always-off","trafficAllocation":100,"trafficAllocationSeed":-331690370,"seed":403891040,"status":"ACTIVE","killed":false,"defaultTreatment":"on","changeNumber":1494365020316,"algo":2,"conditions":[{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":null},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":null,"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment all"}]}'; - -const STORED_SPLITS: Record = {}; -STORED_SPLITS['always-on'] = ALWAYS_ON_SPLIT; -STORED_SPLITS['always-off'] = ALWAYS_OFF_SPLIT; - // Mocked storageManager const storageManagerMock = { splits: { - getSplit: (name: string) => STORED_SPLITS[name], usesSegments: () => false } }; @@ -101,33 +93,34 @@ test('syncManagerOnline should syncAll a single time in singleSync mode', () => settings.sync.singleSync = true; // @ts-ignore - const pollingSyncManager = syncManagerOnlineFactory(() => pollingManagerMock)({ settings }); + // Test pushManager for main client + const syncManager = syncManagerOnlineFactory(() => pollingManagerMock, () => pushManagerMock)({ settings }); - expect(pollingSyncManager.pushManager).toBeUndefined(); + expect(syncManager.pushManager).toBeUndefined(); // Test pollingManager for Main client - pollingSyncManager.start(); + syncManager.start(); expect(pollingManagerMock.start).not.toBeCalled(); expect(pollingManagerMock.syncAll).toBeCalledTimes(1); - pollingSyncManager.stop(); - pollingSyncManager.start(); + syncManager.stop(); + syncManager.start(); expect(pollingManagerMock.start).not.toBeCalled(); expect(pollingManagerMock.syncAll).toBeCalledTimes(1); - pollingSyncManager.stop(); - pollingSyncManager.start(); + syncManager.stop(); + syncManager.start(); expect(pollingManagerMock.start).not.toBeCalled(); expect(pollingManagerMock.syncAll).toBeCalledTimes(1); - pollingSyncManager.stop(); + syncManager.stop(); // @ts-ignore // Test pollingManager for shared client - const pollingSyncManagerShared = pollingSyncManager.shared('sharedKey', readinessManagerMock, storageManagerMock); + const pollingSyncManagerShared = syncManager.shared('sharedKey', readinessManagerMock, storageManagerMock); if (!pollingSyncManagerShared) throw new Error('pollingSyncManagerShared should exist'); @@ -142,26 +135,22 @@ test('syncManagerOnline should syncAll a single time in singleSync mode', () => pollingSyncManagerShared.stop(); - // @ts-ignore - // Test pushManager for main client - const pushingSyncManager = syncManagerOnlineFactory(() => pollingManagerMock, () => pushManagerMock)({ settings }); - - pushingSyncManager.start(); + syncManager.start(); expect(pushManagerMock.start).not.toBeCalled(); expect(pollingManagerMock.start).not.toBeCalled(); - pushingSyncManager.stop(); - pushingSyncManager.start(); + syncManager.stop(); + syncManager.start(); expect(pushManagerMock.start).not.toBeCalled(); expect(pollingManagerMock.start).not.toBeCalled(); - pushingSyncManager.stop(); + syncManager.stop(); // @ts-ignore // Test pollingManager for shared client - const pushingSyncManagerShared = pushingSyncManager.shared('pushingSharedKey', readinessManagerMock, storageManagerMock); + const pushingSyncManagerShared = syncManager.shared('pushingSharedKey', readinessManagerMock, storageManagerMock); if (!pushingSyncManagerShared) throw new Error('pushingSyncManagerShared should exist'); From 08f55f7ae6743bd6841692602397b8e0c28940a0 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Wed, 15 Jun 2022 16:44:08 -0300 Subject: [PATCH 3/3] Use pushManagerFactoryMock and pushManagerMock --- src/sync/__tests__/syncManagerOnline.spec.ts | 38 ++++++-------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/src/sync/__tests__/syncManagerOnline.spec.ts b/src/sync/__tests__/syncManagerOnline.spec.ts index 434ce24c..d60156ab 100644 --- a/src/sync/__tests__/syncManagerOnline.spec.ts +++ b/src/sync/__tests__/syncManagerOnline.spec.ts @@ -1,9 +1,6 @@ import { fullSettings } from '../../utils/settingsValidation/__tests__/settings.mocks'; import { syncTaskFactory } from './syncTask.mock'; import { syncManagerOnlineFactory } from '../syncManagerOnline'; -import { pushManagerFactory } from '../streaming/pushManager'; -import { IPushManager } from '../streaming/types'; -import { EventEmitter } from '../../utils/MinEvents'; import { IReadinessManager } from '../../readiness/types'; jest.mock('../submitters/submitterManager', () => { @@ -12,17 +9,6 @@ jest.mock('../submitters/submitterManager', () => { }; }); -const paramsMock = { - platform: { - getEventSource: jest.fn(() => { return () => { }; }), - EventEmitter - }, - settings: fullSettings, - storage: {}, - readiness: {}, - start: jest.fn() -}; - // Mocked storageManager const storageManagerMock = { splits: { @@ -47,12 +33,14 @@ const pollingManagerMock = { get: jest.fn() }; -// Mocked pushManager -const pushManagerMock = pushManagerFactory({ // @ts-ignore - ...paramsMock, splitApi: { fetchAuth: jest.fn() } -}, {}) as IPushManager; +const pushManagerMock = { + start: jest.fn(), + on: jest.fn(), + stop: jest.fn() +}; -pushManagerMock.start = jest.fn(); +// Mocked pushManager +const pushManagerFactoryMock = jest.fn(() => pushManagerMock); test('syncManagerOnline should start or not the submitter depending on user consent status', () => { const settings = { ...fullSettings }; @@ -94,9 +82,9 @@ test('syncManagerOnline should syncAll a single time in singleSync mode', () => // @ts-ignore // Test pushManager for main client - const syncManager = syncManagerOnlineFactory(() => pollingManagerMock, () => pushManagerMock)({ settings }); + const syncManager = syncManagerOnlineFactory(() => pollingManagerMock, pushManagerFactoryMock)({ settings }); - expect(syncManager.pushManager).toBeUndefined(); + expect(pushManagerFactoryMock).not.toBeCalled(); // Test pollingManager for Main client syncManager.start(); @@ -137,13 +125,11 @@ test('syncManagerOnline should syncAll a single time in singleSync mode', () => syncManager.start(); - expect(pushManagerMock.start).not.toBeCalled(); expect(pollingManagerMock.start).not.toBeCalled(); syncManager.stop(); syncManager.start(); - expect(pushManagerMock.start).not.toBeCalled(); expect(pollingManagerMock.start).not.toBeCalled(); syncManager.stop(); @@ -156,13 +142,11 @@ test('syncManagerOnline should syncAll a single time in singleSync mode', () => pushingSyncManagerShared.start(); - expect(pushManagerMock.start).not.toBeCalled(); expect(pollingManagerMock.start).not.toBeCalled(); pushingSyncManagerShared.stop(); pushingSyncManagerShared.start(); - expect(pushManagerMock.start).not.toBeCalled(); expect(pollingManagerMock.start).not.toBeCalled(); pushingSyncManagerShared.stop(); @@ -170,9 +154,9 @@ test('syncManagerOnline should syncAll a single time in singleSync mode', () => settings.sync.singleSync = false; // @ts-ignore // pushManager instantiation control test - const testSyncManager = syncManagerOnlineFactory(() => pollingManagerMock, () => pushManagerMock)({ settings }); + const testSyncManager = syncManagerOnlineFactory(() => pollingManagerMock, pushManagerFactoryMock)({ settings }); - expect(testSyncManager.pushManager).not.toBeUndefined(); + expect(pushManagerFactoryMock).toBeCalled(); // Test pollingManager for Main client testSyncManager.start();