Skip to content

Commit 8e0a1e3

Browse files
Adding some corner cases to unit tests
1 parent 2d49c01 commit 8e0a1e3

File tree

2 files changed

+47
-19
lines changed

2 files changed

+47
-19
lines changed

src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import { MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../constants';
1313
*/
1414
export function MySegmentsUpdateWorker(log: ILogger, storage: Pick<IStorageSync, 'segments' | 'largeSegments'>, mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker): IUpdateWorker<[mySegmentsData?: Pick<MySegmentsData, 'type' | 'cn'>, payload?: Pick<MySegmentsData, 'added' | 'removed'>, delay?: number]> {
1515

16+
let _delay: undefined | number;
17+
let _delayTimeoutID: any;
18+
1619
function createUpdateWorker(mySegmentsCache: ISegmentsCacheSync) {
1720

1821
let maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
@@ -21,8 +24,6 @@ export function MySegmentsUpdateWorker(log: ILogger, storage: Pick<IStorageSync,
2124
let isHandlingEvent: boolean;
2225
let cdnBypass: boolean;
2326
let _segmentsData: MySegmentsData | undefined; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
24-
let _delay: undefined | number;
25-
let _delayTimeoutID: any;
2627
const backoff = new Backoff(__handleMySegmentsUpdateCall);
2728

2829
function __handleMySegmentsUpdateCall() {
@@ -92,10 +93,11 @@ export function MySegmentsUpdateWorker(log: ILogger, storage: Pick<IStorageSync,
9293
*/
9394
put(mySegmentsData: Pick<MySegmentsData, 'type' | 'cn'>, payload?: Pick<MySegmentsData, 'added' | 'removed'>, delay?: number) {
9495
const { type, cn } = mySegmentsData;
95-
// Ignore event if it is outdated or if there is a pending fetch request (_delay is set)
96-
if (cn <= Math.max(currentChangeNumber, mySegmentsCache.getChangeNumber()) || cn <= maxChangeNumber || _delay) return;
97-
96+
// Discard event if it is outdated or there is a pending fetch request (_delay is set), but update target change number
97+
if (cn <= Math.max(currentChangeNumber, mySegmentsCache.getChangeNumber()) || cn <= maxChangeNumber) return;
9898
maxChangeNumber = cn;
99+
if (_delay) return;
100+
99101
handleNewEvent = true;
100102
cdnBypass = false;
101103
_segmentsData = payload && { type, cn, added: payload.added, removed: payload.removed };

src/sync/streaming/UpdateWorkers/__tests__/MySegmentsUpdateWorker.spec.ts

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
import { MySegmentsUpdateWorker } from '../MySegmentsUpdateWorker';
2-
import { MySegmentsCacheInMemory } from '../../../../storages/inMemory/MySegmentsCacheInMemory';
32
import { loggerMock } from '../../../../logger/__tests__/sdkLogger.mock';
43
import { syncTaskFactory } from '../../../syncTask';
54
import { Backoff } from '../../../../utils/Backoff';
65
import { telemetryTrackerFactory } from '../../../../trackers/telemetryTracker';
76
import { MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../../constants';
87

9-
function createStorage() {
8+
function storageMock() {
109
return {
11-
segments: new MySegmentsCacheInMemory(),
12-
largeSegments: new MySegmentsCacheInMemory(),
10+
segments: {
11+
_changeNumber: -1,
12+
getChangeNumber() {
13+
return this._changeNumber;
14+
}
15+
},
16+
largeSegments: {
17+
_changeNumber: -1,
18+
getChangeNumber() {
19+
return this._changeNumber;
20+
}
21+
},
1322
};
1423
}
1524

@@ -55,7 +64,7 @@ describe('MySegmentsUpdateWorker', () => {
5564
// setup
5665
const mySegmentsSyncTask = mySegmentsSyncTaskMock();
5766
Backoff.__TEST__BASE_MILLIS = 1; // retry immediately
58-
const mySegmentUpdateWorker = MySegmentsUpdateWorker(loggerMock, createStorage(), mySegmentsSyncTask as any, telemetryTracker);
67+
const mySegmentUpdateWorker = MySegmentsUpdateWorker(loggerMock, storageMock() as any, mySegmentsSyncTask as any, telemetryTracker);
5968

6069
// assert calling `mySegmentsSyncTask.execute` if `isExecuting` is false
6170
expect(mySegmentsSyncTask.isExecuting()).toBe(false);
@@ -123,7 +132,7 @@ describe('MySegmentsUpdateWorker', () => {
123132
// setup
124133
Backoff.__TEST__BASE_MILLIS = 50;
125134
const mySegmentsSyncTask = mySegmentsSyncTaskMock([false, false, false]); // fetch fail
126-
const mySegmentUpdateWorker = MySegmentsUpdateWorker(loggerMock, createStorage(), mySegmentsSyncTask as any, telemetryTracker);
135+
const mySegmentUpdateWorker = MySegmentsUpdateWorker(loggerMock, storageMock() as any, mySegmentsSyncTask as any, telemetryTracker);
127136

128137
// while fetch fails, should retry with backoff
129138
mySegmentUpdateWorker.put({ type: MEMBERSHIPS_MS_UPDATE, cn: 100 });
@@ -138,7 +147,7 @@ describe('MySegmentsUpdateWorker', () => {
138147
test('stop', async () => {
139148
// setup
140149
const mySegmentsSyncTask = mySegmentsSyncTaskMock([false]);
141-
const mySegmentUpdateWorker = MySegmentsUpdateWorker(loggerMock, createStorage(), mySegmentsSyncTask as any, telemetryTracker);
150+
const mySegmentUpdateWorker = MySegmentsUpdateWorker(loggerMock, storageMock() as any, mySegmentsSyncTask as any, telemetryTracker);
142151

143152
mySegmentUpdateWorker.put({ type: MEMBERSHIPS_LS_UPDATE, cn: 100 });
144153
mySegmentUpdateWorker.stop();
@@ -153,36 +162,53 @@ describe('MySegmentsUpdateWorker', () => {
153162
expect(mySegmentsSyncTask.execute).toBeCalledTimes(1);
154163
});
155164

156-
test('put with delay', async () => {
165+
test('put, with delay and storage change number', async () => {
157166
// setup
167+
Backoff.__TEST__BASE_MILLIS = 1; // retry immediately
158168
const mySegmentsSyncTask = mySegmentsSyncTaskMock();
159-
const mySegmentUpdateWorker = MySegmentsUpdateWorker(loggerMock, createStorage(), mySegmentsSyncTask as any, telemetryTracker);
169+
const storage = storageMock();
170+
const mySegmentUpdateWorker = MySegmentsUpdateWorker(loggerMock, storage as any, mySegmentsSyncTask as any, telemetryTracker);
160171

161-
// If a delayed fetch request is queued while another fetch request is waiting, it is discarded
172+
// notification with delay
162173
mySegmentUpdateWorker.put({ type: MEMBERSHIPS_LS_UPDATE, cn: 100 }, undefined, 50);
163-
mySegmentUpdateWorker.put({ type: MEMBERSHIPS_LS_UPDATE, cn: 150 }, undefined, 100);
174+
175+
// If a notification is queued while a fetch request is waiting, the notification is discarded but its change number is used to update the target change number
176+
mySegmentUpdateWorker.put({ type: MEMBERSHIPS_MS_UPDATE, cn: 150 }, undefined, 100); // target for segments storage is 150
177+
mySegmentUpdateWorker.put({ type: MEMBERSHIPS_LS_UPDATE, cn: 120 }); // target for large segments storage is 120
164178

165179
await new Promise(res => setTimeout(res, 60));
166180
expect(mySegmentsSyncTask.execute).toBeCalledTimes(1);
167181
expect(mySegmentsSyncTask.execute).toHaveBeenLastCalledWith(undefined, true, undefined);
182+
storage.largeSegments._changeNumber = 100; // change number update but not the expected one
168183
mySegmentsSyncTask.__resolveMySegmentsUpdaterCall(); // fetch success
169184

170185
await new Promise(res => setTimeout(res, 60));
171-
expect(mySegmentsSyncTask.execute).toBeCalledTimes(1);
186+
expect(mySegmentsSyncTask.execute).toBeCalledTimes(2); // fetch retry due to target change number mismatch
187+
188+
storage.largeSegments._changeNumber = 120;
189+
mySegmentsSyncTask.__resolveMySegmentsUpdaterCall();
190+
await new Promise(res => setTimeout(res, 60));
191+
expect(mySegmentsSyncTask.execute).toBeCalledTimes(2); // no more fetches since target change number is reached
172192

173193
// If an event with segmentData (i.e., an instant update) is queued while a delayed fetch request is waiting, the instant update is discarded
174194
mySegmentUpdateWorker.put({ type: MEMBERSHIPS_LS_UPDATE, cn: 200 }, undefined, 50);
175195
await new Promise(res => setTimeout(res, 10));
176196
mySegmentUpdateWorker.put({ type: MEMBERSHIPS_LS_UPDATE, cn: 230 }, { added: ['some_segment'], removed: [] });
177197

178198
await new Promise(res => setTimeout(res, 60));
179-
expect(mySegmentsSyncTask.execute).toBeCalledTimes(2);
199+
expect(mySegmentsSyncTask.execute).toBeCalledTimes(3);
180200
expect(mySegmentsSyncTask.execute).toHaveBeenLastCalledWith(undefined, true, undefined);
181201
mySegmentsSyncTask.__resolveMySegmentsUpdaterCall(); // fetch success
182202
await new Promise(res => setTimeout(res));
183203

184204
mySegmentUpdateWorker.put({ type: MEMBERSHIPS_LS_UPDATE, cn: 250 }, { added: ['some_segment'], removed: [] });
185-
expect(mySegmentsSyncTask.execute).toBeCalledTimes(3);
205+
expect(mySegmentsSyncTask.execute).toBeCalledTimes(4);
186206
expect(mySegmentsSyncTask.execute).toHaveBeenLastCalledWith({ type: MEMBERSHIPS_LS_UPDATE, cn: 250, added: ['some_segment'], removed: [] }, true, undefined);
207+
208+
// Stop should clear the delayed fetch request
209+
mySegmentUpdateWorker.put({ type: MEMBERSHIPS_MS_UPDATE, cn: 300 }, undefined, 10);
210+
mySegmentUpdateWorker.stop();
211+
await new Promise(res => setTimeout(res, 20));
212+
expect(mySegmentsSyncTask.execute).toBeCalledTimes(4);
187213
});
188214
});

0 commit comments

Comments
 (0)