Skip to content

Commit 94814df

Browse files
Update logs and tests
1 parent b8719b2 commit 94814df

File tree

3 files changed

+62
-56
lines changed

3 files changed

+62
-56
lines changed

src/logger/messages/warn.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const codesWarn: [number, string][] = codesError.concat([
1515
[c.SUBMITTERS_PUSH_RETRY, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Failed to push %s, keeping data to retry on next iteration. Reason: %s.'],
1616
// client status
1717
[c.CLIENT_NOT_READY_FROM_CACHE, '%s: the SDK is not ready to evaluate. Results may be incorrect%s. Make sure to wait for SDK readiness before using this method.'],
18-
[c.CLIENT_NO_LISTENER, 'No listeners for SDK Readiness detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet ready.'],
18+
[c.CLIENT_NO_LISTENER, 'No listeners for SDK_READY event detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet synchronized with the backend.'],
1919
// input validation
2020
[c.WARN_SETTING_NULL, '%s: Property "%s" is of invalid type. Setting value to null.'],
2121
[c.WARN_TRIMMING_PROPERTIES, '%s: more than 300 properties were provided. Some of them will be trimmed when processed.'],

src/readiness/__tests__/sdkReadinessManager.spec.ts

Lines changed: 59 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @ts-nocheck
22
import { loggerMock } from '../../logger/__tests__/sdkLogger.mock';
33
import SplitIO from '../../../types/splitio';
4-
import { SDK_READY, SDK_READY_FROM_CACHE, SDK_READY_TIMED_OUT, SDK_UPDATE, SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../constants';
4+
import { SDK_READY, SDK_READY_FROM_CACHE, SDK_READY_TIMED_OUT, SDK_UPDATE, SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../constants';
55
import { sdkReadinessManagerFactory } from '../sdkReadinessManager';
66
import { IReadinessManager } from '../types';
77
import { ERROR_CLIENT_LISTENER, CLIENT_READY_FROM_CACHE, CLIENT_READY, CLIENT_NO_LISTENER } from '../../logger/constants';
@@ -20,6 +20,12 @@ const EventEmitterMock = jest.fn(() => ({
2020

2121
// Makes readinessManager emit SDK_READY & update isReady flag
2222
function emitReadyEvent(readinessManager: IReadinessManager) {
23+
if (readinessManager.gate instanceof EventEmitter) {
24+
readinessManager.splits.emit(SDK_SPLITS_ARRIVED);
25+
readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED);
26+
return;
27+
}
28+
2329
readinessManager.splits.once.mock.calls[0][1]();
2430
readinessManager.splits.on.mock.calls[0][1]();
2531
readinessManager.segments.once.mock.calls[0][1]();
@@ -32,14 +38,19 @@ const timeoutErrorMessage = 'Split SDK emitted SDK_READY_TIMED_OUT event.';
3238

3339
// Makes readinessManager emit SDK_READY_TIMED_OUT & update hasTimedout flag
3440
function emitTimeoutEvent(readinessManager: IReadinessManager) {
41+
if (readinessManager.gate instanceof EventEmitter) {
42+
readinessManager.timeout();
43+
return;
44+
}
45+
3546
readinessManager.gate.once.mock.calls[1][1](timeoutErrorMessage);
3647
readinessManager.hasTimedout = () => true;
3748
if (readinessManager.gate.once.mock.calls[4]) readinessManager.gate.once.mock.calls[4][1](timeoutErrorMessage); // whenReady promise
3849
}
3950

4051
describe('SDK Readiness Manager - Event emitter', () => {
4152

42-
afterEach(() => { loggerMock.mockClear(); });
53+
beforeEach(() => { loggerMock.mockClear(); });
4354

4455
test('Providing the gate object to get the SDK status interface that manages events', () => {
4556
expect(typeof sdkReadinessManagerFactory).toBe('function'); // The module exposes a function.
@@ -203,82 +214,74 @@ describe('SDK Readiness Manager - Event emitter', () => {
203214
});
204215
});
205216

206-
describe('SDK Readiness Manager - whenReady promise', () => {
217+
describe('SDK Readiness Manager - Promises', () => {
207218

208-
test('.whenReady() promise behavior for clients', async () => {
209-
const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings);
219+
test('.whenReady() and .whenReadyFromCache() promises resolves when SDK_READY is emitted', async () => {
220+
const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitter, fullSettings);
221+
222+
// make the SDK ready from cache
223+
sdkReadinessManager.readinessManager.splits.emit(SDK_SPLITS_CACHE_LOADED);
224+
expect(await sdkReadinessManager.sdkStatus.whenReadyFromCache()).toBe(false);
225+
226+
// validate error log for SDK_READY_FROM_CACHE
227+
expect(loggerMock.error).not.toBeCalled();
228+
sdkReadinessManager.readinessManager.gate.on(SDK_READY_FROM_CACHE, () => {});
229+
expect(loggerMock.error).toBeCalledWith(ERROR_CLIENT_LISTENER, ['SDK_READY_FROM_CACHE']);
210230

231+
const readyFromCache = sdkReadinessManager.sdkStatus.whenReadyFromCache();
211232
const ready = sdkReadinessManager.sdkStatus.whenReady();
212-
expect(ready instanceof Promise).toBe(true); // It should return a promise.
213233

214234
// make the SDK ready
215235
emitReadyEvent(sdkReadinessManager.readinessManager);
236+
expect(await sdkReadinessManager.sdkStatus.whenReadyFromCache()).toBe(true);
216237

217238
let testPassedCount = 0;
218-
await ready.then(
219-
() => {
220-
expect('It should be a promise that will be resolved when the SDK is ready.');
221-
testPassedCount++;
222-
},
223-
() => { throw new Error('It should be resolved on ready event, not rejected.'); }
224-
);
239+
function incTestPassedCount() { testPassedCount++; }
240+
function throwTestFailed() { throw new Error('It should be resolved, not rejected.'); }
225241

226-
// any subsequent call to .whenReady() must be a resolved promise
227-
await sdkReadinessManager.sdkStatus.whenReady().then(
228-
() => {
229-
expect('A subsequent call should be a resolved promise.');
230-
testPassedCount++;
231-
},
232-
() => { throw new Error('It should be resolved on ready event, not rejected.'); }
233-
);
242+
await readyFromCache.then(incTestPassedCount, throwTestFailed);
243+
await ready.then(incTestPassedCount, throwTestFailed);
234244

235-
// control assertion. stubs already reset.
236-
expect(testPassedCount).toBe(2);
245+
// any subsequent call to .whenReady() and .whenReadyFromCache() must be a resolved promise
246+
await sdkReadinessManager.sdkStatus.whenReady().then(incTestPassedCount, throwTestFailed);
247+
await sdkReadinessManager.sdkStatus.whenReadyFromCache().then(incTestPassedCount, throwTestFailed);
237248

238-
const sdkReadinessManagerForTimedout = sdkReadinessManagerFactory(EventEmitterMock, fullSettings);
249+
expect(testPassedCount).toBe(4);
250+
});
239251

252+
test('.whenReady() and .whenReadyFromCache() promises reject when SDK_READY_TIMED_OUT is emitted before SDK_READY', async () => {
253+
const sdkReadinessManagerForTimedout = sdkReadinessManagerFactory(EventEmitter, fullSettings);
254+
255+
const readyFromCacheForTimeout = sdkReadinessManagerForTimedout.sdkStatus.whenReadyFromCache();
240256
const readyForTimeout = sdkReadinessManagerForTimedout.sdkStatus.whenReady();
241257

242258
emitTimeoutEvent(sdkReadinessManagerForTimedout.readinessManager); // make the SDK timeout
243259

244-
await readyForTimeout.then(
245-
() => { throw new Error('It should be a promise that was rejected on SDK_READY_TIMED_OUT, not resolved.'); },
246-
() => {
247-
expect('It should be a promise that will be rejected when the SDK is timed out.');
248-
testPassedCount++;
249-
}
250-
);
260+
let testPassedCount = 0;
261+
function incTestPassedCount() { testPassedCount++; }
262+
function throwTestFailed() { throw new Error('It should rejected, not resolved.'); }
251263

252-
// any subsequent call to .whenReady() must be a rejected promise until the SDK is ready
253-
await sdkReadinessManagerForTimedout.sdkStatus.whenReady().then(
254-
() => { throw new Error('It should be a promise that was rejected on SDK_READY_TIMED_OUT, not resolved.'); },
255-
() => {
256-
expect('A subsequent call should be a rejected promise.');
257-
testPassedCount++;
258-
}
259-
);
264+
await readyFromCacheForTimeout.then(throwTestFailed,incTestPassedCount);
265+
await readyForTimeout.then(throwTestFailed,incTestPassedCount);
266+
267+
// any subsequent call to .whenReady() and .whenReadyFromCache() must be a rejected promise until the SDK is ready
268+
await sdkReadinessManagerForTimedout.sdkStatus.whenReadyFromCache().then(throwTestFailed,incTestPassedCount);
269+
await sdkReadinessManagerForTimedout.sdkStatus.whenReady().then(throwTestFailed,incTestPassedCount);
260270

261271
// make the SDK ready
262272
emitReadyEvent(sdkReadinessManagerForTimedout.readinessManager);
263273

264274
// once SDK_READY, `.whenReady()` returns a resolved promise
265-
await sdkReadinessManagerForTimedout.sdkStatus.whenReady().then(
266-
() => {
267-
expect('It should be a resolved promise when the SDK is ready, even after an SDK timeout.');
268-
loggerMock.mockClear();
269-
testPassedCount++;
270-
expect(testPassedCount).toBe(5);
271-
},
272-
() => { throw new Error('It should be resolved on ready event, not rejected.'); }
273-
);
275+
await sdkReadinessManagerForTimedout.sdkStatus.whenReady().then(incTestPassedCount, throwTestFailed);
276+
await sdkReadinessManagerForTimedout.sdkStatus.whenReadyFromCache().then(incTestPassedCount, throwTestFailed);
277+
278+
expect(testPassedCount).toBe(6);
274279
});
275280

276-
test('whenReady promise count as a callback and resolves on SDK_READY', (done) => {
281+
test('whenReady promise counts as an SDK_READY listener', (done) => {
277282
let sdkReadinessManager = sdkReadinessManagerFactory(EventEmitter, fullSettings);
278283

279-
// Emit ready event
280-
sdkReadinessManager.readinessManager.splits.emit(SDK_SPLITS_ARRIVED);
281-
sdkReadinessManager.readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED);
284+
emitReadyEvent(sdkReadinessManager.readinessManager);
282285

283286
expect(loggerMock.warn).toBeCalledWith(CLIENT_NO_LISTENER); // We should get a warning if the SDK get's ready before calling the whenReady method or attaching a listener to the ready event
284287
loggerMock.warn.mockClear();
@@ -291,16 +294,17 @@ describe('SDK Readiness Manager - whenReady promise', () => {
291294
throw new Error('This should not be called as the promise is being resolved.');
292295
});
293296

294-
// Emit ready event
295-
sdkReadinessManager.readinessManager.splits.emit(SDK_SPLITS_ARRIVED);
296-
sdkReadinessManager.readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED);
297+
emitReadyEvent(sdkReadinessManager.readinessManager);
297298

298299
expect(loggerMock.warn).not.toBeCalled(); // But if we have a listener or call the whenReady method, we get no warnings.
299300
});
300301
});
301302

302303
// @TODO: remove in next major
303304
describe('SDK Readiness Manager - Ready promise', () => {
305+
306+
beforeEach(() => { loggerMock.mockClear(); });
307+
304308
test('ready promise count as a callback and resolves on SDK_READY', (done) => {
305309
const sdkReadinessManager = sdkReadinessManagerFactory(EventEmitterMock, fullSettings);
306310
const readyPromise = sdkReadinessManager.sdkStatus.ready();

src/readiness/sdkReadinessManager.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export function sdkReadinessManagerFactory(
3939
} else if (event === SDK_READY) {
4040
readyCbCount++;
4141
}
42+
} else if (event === SDK_READY_FROM_CACHE && readinessManager.isReadyFromCache()) {
43+
log.error(ERROR_CLIENT_LISTENER, ['SDK_READY_FROM_CACHE']);
4244
}
4345
});
4446

0 commit comments

Comments
 (0)