From 3c7d05f070dc0a47b6a7819e98297acbffdecd2a Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 11 Jul 2024 15:49:25 -0300 Subject: [PATCH 1/2] Update Readiness Manager to handle largeSegments sync if largeSegmentsEnabled and waitForLargeSegments are true --- .../__tests__/readinessManager.spec.ts | 48 +++++++++++++------ .../__tests__/sdkReadinessManager.spec.ts | 23 ++++----- src/readiness/readinessManager.ts | 16 +++++-- src/readiness/sdkReadinessManager.ts | 14 +++--- src/readiness/types.ts | 5 +- src/sdkClient/sdkClientMethodCS.ts | 4 +- src/sdkClient/sdkClientMethodCSWithTT.ts | 4 +- src/sdkFactory/index.ts | 2 +- .../__tests__/splitChangesUpdater.spec.ts | 4 +- 9 files changed, 73 insertions(+), 47 deletions(-) diff --git a/src/readiness/__tests__/readinessManager.spec.ts b/src/readiness/__tests__/readinessManager.spec.ts index 6f2ade74..601f849f 100644 --- a/src/readiness/__tests__/readinessManager.spec.ts +++ b/src/readiness/__tests__/readinessManager.spec.ts @@ -2,8 +2,26 @@ import { readinessManagerFactory } from '../readinessManager'; import { EventEmitter } from '../../utils/MinEvents'; import { IReadinessManager } from '../types'; import { SDK_READY, SDK_UPDATE, SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_READY_FROM_CACHE, SDK_SPLITS_CACHE_LOADED, SDK_READY_TIMED_OUT } from '../constants'; +import { ISettings } from '../../types'; + +const settings = { + startup: { + readyTimeout: 0, + waitForLargeSegments: false + }, + sync: { + largeSegmentEnabled: false + } +} as unknown as ISettings; + +const settingsWithTimeout = { + ...settings, + startup: { + ...settings.startup, + readyTimeout: 50 + } +}; -const timeoutMs = 100; const statusFlagsCount = 5; function assertInitialStatus(readinessManager: IReadinessManager) { @@ -17,7 +35,7 @@ function assertInitialStatus(readinessManager: IReadinessManager) { test('READINESS MANAGER / Share splits but segments (without timeout enabled)', (done) => { expect.assertions(2 + statusFlagsCount * 2); - const readinessManager = readinessManagerFactory(EventEmitter); + const readinessManager = readinessManagerFactory(EventEmitter, settings); const readinessManager2 = readinessManager.shared(); assertInitialStatus(readinessManager); // all status flags must be false @@ -50,7 +68,7 @@ test('READINESS MANAGER / Share splits but segments (without timeout enabled)', }); test('READINESS MANAGER / Ready event should be fired once', () => { - const readinessManager = readinessManagerFactory(EventEmitter); + const readinessManager = readinessManagerFactory(EventEmitter, settings); let counter = 0; readinessManager.gate.on(SDK_READY, () => { @@ -69,7 +87,7 @@ test('READINESS MANAGER / Ready event should be fired once', () => { }); test('READINESS MANAGER / Ready from cache event should be fired once', (done) => { - const readinessManager = readinessManagerFactory(EventEmitter); + const readinessManager = readinessManagerFactory(EventEmitter, settings); let counter = 0; readinessManager.gate.on(SDK_READY_FROM_CACHE, () => { @@ -94,7 +112,7 @@ test('READINESS MANAGER / Ready from cache event should be fired once', (done) = }); test('READINESS MANAGER / Update event should be fired after the Ready event', () => { - const readinessManager = readinessManagerFactory(EventEmitter); + const readinessManager = readinessManagerFactory(EventEmitter, settings); let isReady = false; let counter = 0; @@ -121,7 +139,7 @@ test('READINESS MANAGER / Update event should be fired after the Ready event', ( test('READINESS MANAGER / Segment updates should not be propagated', (done) => { let updateCounter = 0; - const readinessManager = readinessManagerFactory(EventEmitter); + const readinessManager = readinessManagerFactory(EventEmitter, settings); const readinessManager2 = readinessManager.shared(); readinessManager2.gate.on(SDK_UPDATE, () => { @@ -149,7 +167,7 @@ describe('READINESS MANAGER / Timeout ready event', () => { beforeEach(() => { // Schedule timeout to be fired before SDK_READY - readinessManager = readinessManagerFactory(EventEmitter, 10); + readinessManager = readinessManagerFactory(EventEmitter, settingsWithTimeout); timeoutCounter = 0; readinessManager.gate.on(SDK_READY_TIMED_OUT, () => { @@ -160,7 +178,7 @@ describe('READINESS MANAGER / Timeout ready event', () => { setTimeout(() => { readinessManager.splits.emit(SDK_SPLITS_ARRIVED); readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED); - }, 20); + }, settingsWithTimeout.startup.readyTimeout + 20); }); test('should be fired once', (done) => { @@ -194,7 +212,7 @@ test('READINESS MANAGER / Cancel timeout if ready fired', (done) => { let sdkReadyCalled = false; let sdkReadyTimedoutCalled = false; - const readinessManager = readinessManagerFactory(EventEmitter, timeoutMs); + const readinessManager = readinessManagerFactory(EventEmitter, settingsWithTimeout); readinessManager.gate.on(SDK_READY_TIMED_OUT, () => { sdkReadyTimedoutCalled = true; }); readinessManager.gate.once(SDK_READY, () => { sdkReadyCalled = true; }); @@ -204,16 +222,16 @@ test('READINESS MANAGER / Cancel timeout if ready fired', (done) => { expect(sdkReadyTimedoutCalled).toBeFalsy(); expect(sdkReadyCalled).toBeTruthy(); done(); - }, timeoutMs * 3); + }, settingsWithTimeout.startup.readyTimeout * 3); setTimeout(() => { readinessManager.splits.emit(SDK_SPLITS_ARRIVED); readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED); - }, timeoutMs * 0.8); + }, settingsWithTimeout.startup.readyTimeout * 0.8); }); test('READINESS MANAGER / Destroy after it was ready but before timedout', () => { - const readinessManager = readinessManagerFactory(EventEmitter, timeoutMs); + const readinessManager = readinessManagerFactory(EventEmitter, settingsWithTimeout); let counter = 0; @@ -238,7 +256,7 @@ test('READINESS MANAGER / Destroy after it was ready but before timedout', () => }); test('READINESS MANAGER / Destroy before it was ready and timedout', (done) => { - const readinessManager = readinessManagerFactory(EventEmitter, timeoutMs); + const readinessManager = readinessManagerFactory(EventEmitter, settingsWithTimeout); readinessManager.gate.on(SDK_READY, () => { throw new Error('SDK_READY should have not been emitted'); @@ -250,7 +268,7 @@ test('READINESS MANAGER / Destroy before it was ready and timedout', (done) => { setTimeout(() => { readinessManager.destroy(); // Destroy the gate, removing all the listeners and clearing the ready timeout. - }, timeoutMs * 0.5); + }, settingsWithTimeout.startup.readyTimeout * 0.5); setTimeout(() => { readinessManager.splits.emit(SDK_SPLITS_ARRIVED); @@ -258,6 +276,6 @@ test('READINESS MANAGER / Destroy before it was ready and timedout', (done) => { expect('Calling destroy should have removed the readyTimeout and the test should end now.'); done(); - }, timeoutMs * 1.5); + }, settingsWithTimeout.startup.readyTimeout * 1.5); }); diff --git a/src/readiness/__tests__/sdkReadinessManager.spec.ts b/src/readiness/__tests__/sdkReadinessManager.spec.ts index 9c407052..3bb43192 100644 --- a/src/readiness/__tests__/sdkReadinessManager.spec.ts +++ b/src/readiness/__tests__/sdkReadinessManager.spec.ts @@ -5,6 +5,7 @@ import { SDK_READY, SDK_READY_FROM_CACHE, SDK_READY_TIMED_OUT, SDK_UPDATE } from import { sdkReadinessManagerFactory } from '../sdkReadinessManager'; import { IReadinessManager } from '../types'; import { ERROR_CLIENT_LISTENER, CLIENT_READY_FROM_CACHE, CLIENT_READY, CLIENT_NO_LISTENER } from '../../logger/constants'; +import { fullSettings } from '../../utils/settingsValidation/__tests__/settings.mocks'; const EventEmitterMock = jest.fn(() => ({ on: jest.fn(), @@ -40,7 +41,7 @@ describe('SDK Readiness Manager - Event emitter', () => { test('Providing the gate object to get the SDK status interface that manages events', () => { expect(typeof sdkReadinessManagerFactory).toBe('function'); // The module exposes a function. - const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); expect(typeof sdkReadinessManager).toBe('object'); // The function result contains the readiness manager and a sdkStatus object. const gateMock = sdkReadinessManager.readinessManager.gate; const sdkStatus = sdkReadinessManager.sdkStatus; @@ -76,7 +77,7 @@ describe('SDK Readiness Manager - Event emitter', () => { }); test('The event callbacks should work as expected - SDK_READY_FROM_CACHE', () => { - const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); const gateMock = sdkReadinessManager.readinessManager.gate; const readyFromCacheEventCB = gateMock.once.mock.calls[2][1]; @@ -86,7 +87,7 @@ describe('SDK Readiness Manager - Event emitter', () => { }); test('The event callbacks should work as expected - SDK_READY emits with no callbacks', () => { - const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); // Get the callbacks const addListenerCB = sdkReadinessManager.readinessManager.gate.on.mock.calls[1][1]; @@ -112,7 +113,7 @@ describe('SDK Readiness Manager - Event emitter', () => { }); test('The event callbacks should work as expected - SDK_READY emits with callbacks', () => { - const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); // Get the callbacks const addListenerCB = sdkReadinessManager.readinessManager.gate.on.mock.calls[1][1]; @@ -130,7 +131,7 @@ describe('SDK Readiness Manager - Event emitter', () => { }); test('The event callbacks should work as expected - If we end up removing the listeners for SDK_READY, it behaves as if it had none', () => { - const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); const gateMock = sdkReadinessManager.readinessManager.gate; // Get the callbacks @@ -150,7 +151,7 @@ describe('SDK Readiness Manager - Event emitter', () => { }); test('The event callbacks should work as expected - If we end up removing the listeners for SDK_READY, it behaves as if it had none', () => { - const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); const gateMock = sdkReadinessManager.readinessManager.gate; // Get the callbacks @@ -172,7 +173,7 @@ describe('SDK Readiness Manager - Event emitter', () => { test('The event callbacks should work as expected - SDK_READY emits with expected internal callbacks', () => { // the sdkReadinessManager expects more than one SDK_READY callback to not log the "No listeners" warning - const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); sdkReadinessManager.incInternalReadyCbCount(); const gateMock = sdkReadinessManager.readinessManager.gate; @@ -197,7 +198,7 @@ describe('SDK Readiness Manager - Event emitter', () => { describe('SDK Readiness Manager - Ready promise', () => { test('.ready() promise behaviour for clients', async () => { - const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); const ready = sdkReadinessManager.sdkStatus.ready(); expect(ready instanceof Promise).toBe(true); // It should return a promise. @@ -226,7 +227,7 @@ describe('SDK Readiness Manager - Ready promise', () => { // control assertion. stubs already reset. expect(testPassedCount).toBe(2); - const sdkReadinessManagerForTimedout = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManagerForTimedout = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); const readyForTimeout = sdkReadinessManagerForTimedout.sdkStatus.ready(); @@ -265,7 +266,7 @@ describe('SDK Readiness Manager - Ready promise', () => { }); test('Full blown ready promise count as a callback and resolves on SDK_READY', (done) => { - const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); const readyPromise = sdkReadinessManager.sdkStatus.ready(); // Get the callback @@ -287,7 +288,7 @@ describe('SDK Readiness Manager - Ready promise', () => { }); test('.ready() rejected promises have a default onRejected handler that just logs the error', (done) => { - const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); + const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings); let readyForTimeout = sdkReadinessManager.sdkStatus.ready(); emitTimeoutEvent(sdkReadinessManager.readinessManager); // make the SDK "timed out" diff --git a/src/readiness/readinessManager.ts b/src/readiness/readinessManager.ts index c5ac1c35..a4a5290d 100644 --- a/src/readiness/readinessManager.ts +++ b/src/readiness/readinessManager.ts @@ -1,5 +1,5 @@ import { objectAssign } from '../utils/lang/objectAssign'; -import { IEventEmitter } from '../types'; +import { IEventEmitter, ISettings } from '../types'; import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED, SDK_SEGMENTS_ARRIVED, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE, SDK_READY } from './constants'; import { IReadinessEventEmitter, IReadinessManager, ISegmentsEventEmitter, ISplitsEventEmitter } from './types'; @@ -33,10 +33,13 @@ function segmentsEventEmitterFactory(EventEmitter: new () => IEventEmitter): ISe */ export function readinessManagerFactory( EventEmitter: new () => IEventEmitter, - readyTimeout = 0, + settings: ISettings, splits: ISplitsEventEmitter = splitsEventEmitterFactory(EventEmitter)): IReadinessManager { + const { startup: { readyTimeout, waitForLargeSegments }, sync: { largeSegmentsEnabled } } = settings; + const segments: ISegmentsEventEmitter = segmentsEventEmitterFactory(EventEmitter); + const largeSegments = largeSegmentsEnabled && waitForLargeSegments ? segmentsEventEmitterFactory(EventEmitter) : undefined; const gate: IReadinessEventEmitter = new EventEmitter(); // emit SDK_READY_FROM_CACHE @@ -62,6 +65,7 @@ export function readinessManagerFactory( let isReady = false; splits.on(SDK_SPLITS_ARRIVED, checkIsReadyOrUpdate); segments.on(SDK_SEGMENTS_ARRIVED, checkIsReadyOrUpdate); + if (largeSegments) largeSegments.on(SDK_SEGMENTS_ARRIVED, checkIsReadyOrUpdate); let isDestroyed = false; @@ -87,7 +91,7 @@ export function readinessManagerFactory( setTimeout(() => { throw e; }, 0); } } else { - if (splits.splitsArrived && segments.segmentsArrived) { + if (splits.splitsArrived && segments.segmentsArrived && (!largeSegments || largeSegments.segmentsArrived)) { clearTimeout(readyTimeoutId); isReady = true; try { @@ -105,11 +109,12 @@ export function readinessManagerFactory( return { splits, segments, + largeSegments, gate, - shared(readyTimeout = 0) { + shared() { refCount++; - return readinessManagerFactory(EventEmitter, readyTimeout, splits); + return readinessManagerFactory(EventEmitter, settings, splits); }, // @TODO review/remove next methods when non-recoverable errors are reworked @@ -123,6 +128,7 @@ export function readinessManagerFactory( isDestroyed = true; segments.removeAllListeners(); + if (largeSegments) largeSegments.removeAllListeners(); gate.removeAllListeners(); clearTimeout(readyTimeoutId); diff --git a/src/readiness/sdkReadinessManager.ts b/src/readiness/sdkReadinessManager.ts index c137e040..be12a6e1 100644 --- a/src/readiness/sdkReadinessManager.ts +++ b/src/readiness/sdkReadinessManager.ts @@ -2,9 +2,8 @@ import { objectAssign } from '../utils/lang/objectAssign'; import { promiseWrapper } from '../utils/promise/wrapper'; import { readinessManagerFactory } from './readinessManager'; import { ISdkReadinessManager } from './types'; -import { IEventEmitter } from '../types'; +import { IEventEmitter, ISettings } from '../types'; import { SDK_READY, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE } from './constants'; -import { ILogger } from '../logger/types'; import { ERROR_CLIENT_LISTENER, CLIENT_READY_FROM_CACHE, CLIENT_READY, CLIENT_NO_LISTENER } from '../logger/constants'; const NEW_LISTENER_EVENT = 'newListener'; @@ -18,10 +17,11 @@ const REMOVE_LISTENER_EVENT = 'removeListener'; * @param readinessManager optional readinessManager to use. only used internally for `shared` method */ export function sdkReadinessManagerFactory( - log: ILogger, EventEmitter: new () => IEventEmitter, - readyTimeout = 0, - readinessManager = readinessManagerFactory(EventEmitter, readyTimeout)): ISdkReadinessManager { + settings: ISettings, + readinessManager = readinessManagerFactory(EventEmitter, settings)): ISdkReadinessManager { + + const log = settings.log; /** Ready callback warning */ let internalReadyCbCount = 0; @@ -72,8 +72,8 @@ export function sdkReadinessManagerFactory( return { readinessManager, - shared(readyTimeout = 0) { - return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager.shared(readyTimeout)); + shared() { + return sdkReadinessManagerFactory(EventEmitter, settings, readinessManager.shared()); }, incInternalReadyCbCount() { diff --git a/src/readiness/types.ts b/src/readiness/types.ts index d126b5ec..c5cd9b0f 100644 --- a/src/readiness/types.ts +++ b/src/readiness/types.ts @@ -45,6 +45,7 @@ export interface IReadinessManager { /** Event emitters */ splits: ISplitsEventEmitter, segments: ISegmentsEventEmitter, + largeSegments?: ISegmentsEventEmitter, // Undefined if largeSegmentsEnabled or waitForLargeSegments are false gate: IReadinessEventEmitter, /** Readiness status */ @@ -59,7 +60,7 @@ export interface IReadinessManager { destroy(): void, /** for client-side */ - shared(readyTimeout?: number): IReadinessManager, + shared(): IReadinessManager, } /** SDK readiness manager */ @@ -75,5 +76,5 @@ export interface ISdkReadinessManager { incInternalReadyCbCount(): void /** for client-side */ - shared(readyTimeout?: number): ISdkReadinessManager + shared(): ISdkReadinessManager } diff --git a/src/sdkClient/sdkClientMethodCS.ts b/src/sdkClient/sdkClientMethodCS.ts index 724a5871..50822592 100644 --- a/src/sdkClient/sdkClientMethodCS.ts +++ b/src/sdkClient/sdkClientMethodCS.ts @@ -21,7 +21,7 @@ const method = 'Client instantiation'; * Therefore, clients don't have a bound TT for the track method. */ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey) => SplitIO.ICsClient { - const { storage, syncManager, sdkReadinessManager, settings: { core: { key }, startup: { readyTimeout }, log } } = params; + const { storage, syncManager, sdkReadinessManager, settings: { core: { key }, log } } = params; const mainClientInstance = clientCSDecorator( log, @@ -53,7 +53,7 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl if (!clientInstances[instanceId]) { const matchingKey = getMatching(validKey); - const sharedSdkReadiness = sdkReadinessManager.shared(readyTimeout); + const sharedSdkReadiness = sdkReadinessManager.shared(); const sharedStorage = storage.shared && storage.shared(matchingKey, (err) => { if (err) { sharedSdkReadiness.readinessManager.timeout(); diff --git a/src/sdkClient/sdkClientMethodCSWithTT.ts b/src/sdkClient/sdkClientMethodCSWithTT.ts index 78957ba8..79731f31 100644 --- a/src/sdkClient/sdkClientMethodCSWithTT.ts +++ b/src/sdkClient/sdkClientMethodCSWithTT.ts @@ -23,7 +23,7 @@ const method = 'Client instantiation'; * (default client) or the client method (shared clients). */ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey, trafficType?: string) => SplitIO.ICsClient { - const { storage, syncManager, sdkReadinessManager, settings: { core: { key, trafficType }, startup: { readyTimeout }, log } } = params; + const { storage, syncManager, sdkReadinessManager, settings: { core: { key, trafficType }, log } } = params; const mainClientInstance = clientCSDecorator( log, @@ -63,7 +63,7 @@ export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: Spl if (!clientInstances[instanceId]) { const matchingKey = getMatching(validKey); - const sharedSdkReadiness = sdkReadinessManager.shared(readyTimeout); + const sharedSdkReadiness = sdkReadinessManager.shared(); const sharedStorage = storage.shared && storage.shared(matchingKey, (err) => { if (err) { sharedSdkReadiness.readinessManager.timeout(); diff --git a/src/sdkFactory/index.ts b/src/sdkFactory/index.ts index cd15e9ef..31a9ddc5 100644 --- a/src/sdkFactory/index.ts +++ b/src/sdkFactory/index.ts @@ -32,7 +32,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO. // We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle. validateAndTrackApiKey(log, settings.core.authorizationKey); - const sdkReadinessManager = sdkReadinessManagerFactory(log, platform.EventEmitter, settings.startup.readyTimeout); + const sdkReadinessManager = sdkReadinessManagerFactory(platform.EventEmitter, settings); const readiness = sdkReadinessManager.readinessManager; const storage = storageFactory({ diff --git a/src/sync/polling/updaters/__tests__/splitChangesUpdater.spec.ts b/src/sync/polling/updaters/__tests__/splitChangesUpdater.spec.ts index faf31e44..b4dca3fe 100644 --- a/src/sync/polling/updaters/__tests__/splitChangesUpdater.spec.ts +++ b/src/sync/polling/updaters/__tests__/splitChangesUpdater.spec.ts @@ -7,7 +7,7 @@ import { splitChangesFetcherFactory } from '../../fetchers/splitChangesFetcher'; import { splitChangesUpdaterFactory, parseSegments, computeSplitsMutation } from '../splitChangesUpdater'; import splitChangesMock1 from '../../../../__tests__/mocks/splitchanges.since.-1.json'; import fetchMock from '../../../../__tests__/testUtils/fetchMock'; -import { settingsSplitApi } from '../../../../utils/settingsValidation/__tests__/settings.mocks'; +import { fullSettings, settingsSplitApi } from '../../../../utils/settingsValidation/__tests__/settings.mocks'; import { EventEmitter } from '../../../../utils/MinEvents'; import { loggerMock } from '../../../../logger/__tests__/sdkLogger.mock'; import { telemetryTrackerFactory } from '../../../../trackers/telemetryTracker'; @@ -165,7 +165,7 @@ describe('splitChangesUpdater', () => { const segmentsCache = new SegmentsCacheInMemory(); const registerSegments = jest.spyOn(segmentsCache, 'registerSegments'); - const readinessManager = readinessManagerFactory(EventEmitter); + const readinessManager = readinessManagerFactory(EventEmitter, fullSettings); const splitsEmitSpy = jest.spyOn(readinessManager.splits, 'emit'); let splitFiltersValidation = { queryString: null, groupedFilters: { bySet: [], byName: [], byPrefix: [] }, validFilters: [] }; From fac27f93b4b2b7a5a4016bdc2752cea6b0ef3223 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Thu, 11 Jul 2024 16:29:57 -0300 Subject: [PATCH 2/2] Add unit tests --- .../__tests__/readinessManager.spec.ts | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/readiness/__tests__/readinessManager.spec.ts b/src/readiness/__tests__/readinessManager.spec.ts index 601f849f..fafa4019 100644 --- a/src/readiness/__tests__/readinessManager.spec.ts +++ b/src/readiness/__tests__/readinessManager.spec.ts @@ -279,3 +279,44 @@ test('READINESS MANAGER / Destroy before it was ready and timedout', (done) => { }, settingsWithTimeout.startup.readyTimeout * 1.5); }); + +test('READINESS MANAGER / with large segments', () => { + const readinessManager = readinessManagerFactory(EventEmitter, { + startup: { readyTimeout: 0, waitForLargeSegments: false }, + sync: { largeSegmentsEnabled: true } + } as unknown as ISettings); + + expect(readinessManager.largeSegments).toBeUndefined(); + + const readinessManagerWithLargeSegments = readinessManagerFactory(EventEmitter, { + startup: { readyTimeout: 0, waitForLargeSegments: true }, + sync: { largeSegmentsEnabled: true } + } as unknown as ISettings); + + expect(readinessManagerWithLargeSegments.largeSegments).toBeDefined(); + + [readinessManager, readinessManagerWithLargeSegments].forEach(rm => { + let counter = 0; + + rm.gate.on(SDK_READY, () => { + expect(rm.isReady()).toBe(true); + counter++; + }); + + rm.splits.emit(SDK_SPLITS_ARRIVED); + rm.segments.emit(SDK_SEGMENTS_ARRIVED); + if (rm.largeSegments) { + expect(counter).toBe(0); // should not be called yet + rm.largeSegments.emit(SDK_SEGMENTS_ARRIVED); + } + expect(counter).toBe(1); // should be called + + rm.splits.emit(SDK_SPLITS_ARRIVED); + rm.segments.emit(SDK_SEGMENTS_ARRIVED); + rm.splits.emit(SDK_SPLITS_ARRIVED); + rm.segments.emit(SDK_SEGMENTS_ARRIVED); + if (rm.largeSegments) rm.largeSegments.emit(SDK_SEGMENTS_ARRIVED); + + expect(counter).toBe(1); // should be called once + }); +});