Skip to content

Commit

Permalink
Merge pull request #265 from splitio/sdks-7657-b
Browse files Browse the repository at this point in the history
[SDKS-7657] fix SDK_UPDATE issue
  • Loading branch information
emmaz90 authored Nov 2, 2023
2 parents 4f59b03 + 065c6e0 commit f3b4de8
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 8 deletions.
9 changes: 9 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
1.11.0 (November XX, 2023)
- Added support for Flag Sets on the SDK, which enables grouping feature flags and interacting with the group rather than individually (more details in our documentation):
- Added new variations of the get treatment methods to support evaluating flags in given flag set/s.
- getTreatmentsByFlagSet and getTreatmentsByFlagSets
- getTreatmentsWithConfigByFlagSets and getTreatmentsWithConfigByFlagSets
- Added a new optional Split Filter configuration option. This allows the SDK and Split services to only synchronize the flags in the specified flag sets, avoiding unused or unwanted flags from being synced on the SDK instance, bringing all the benefits from a reduced payload.
- Note: Only applicable when the SDK is in charge of the rollout data synchronization. When not applicable, the SDK will log a warning on init.
- Added `sets` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager to expose flag sets on flag views.

1.10.0 (October 20, 2023)
- Added `defaultTreatment` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager (Related to issue https://github.com/splitio/javascript-commons/issues/225).
- Updated log warning message to include the feature flag name when `getTreatment` method is called and the SDK client is not ready.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@splitsoftware/splitio-commons",
"version": "1.10.1-rc.0",
"version": "1.10.1-rc.3",
"description": "Split Javascript SDK common components",
"main": "cjs/index.js",
"module": "esm/index.js",
Expand Down
40 changes: 38 additions & 2 deletions src/sync/polling/updaters/__tests__/splitChangesUpdater.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ describe('splitChangesUpdater', () => {
const readinessManager = readinessManagerFactory(EventEmitter);
const splitsEmitSpy = jest.spyOn(readinessManager.splits, 'emit');

const splitFiltersValidation = { queryString: null, groupedFilters: { bySet: [], byName: [], byPrefix: [] }, validFilters: [] };
let splitFiltersValidation = { queryString: null, groupedFilters: { bySet: [], byName: [], byPrefix: [] }, validFilters: [] };

const splitChangesUpdater = splitChangesUpdaterFactory(loggerMock, splitChangesFetcher, splitsCache, segmentsCache, splitFiltersValidation, readinessManager.splits, 1000, 1);
let splitChangesUpdater = splitChangesUpdaterFactory(loggerMock, splitChangesFetcher, splitsCache, segmentsCache, splitFiltersValidation, readinessManager.splits, 1000, 1);

afterEach(() => {
jest.clearAllMocks();
Expand Down Expand Up @@ -213,4 +213,40 @@ describe('splitChangesUpdater', () => {
index++;
}
});

test('flag sets splits-arrived emition', async () => {
const payload = splitNotifications[3].decoded as Pick<ISplit, 'name' | 'changeNumber' | 'killed' | 'defaultTreatment' | 'trafficTypeName' | 'conditions' | 'status' | 'seed' | 'trafficAllocation' | 'trafficAllocationSeed' | 'configurations'>;
const setMocks = [
{ sets: [], shouldEmit: false }, /* should not emit if flag does not have any set */
{ sets: ['set_a'], shouldEmit: true }, /* should emit if flag is in configured sets */
{ sets: ['set_b'], shouldEmit: true }, /* should emit if flag was just removed from configured sets */
{ sets: ['set_b'], shouldEmit: false }, /* should NOT emit if flag is nor was just removed from configured sets */
{ sets: ['set_c'], shouldEmit: false }, /* should NOT emit if flag is nor was just removed from configured sets */
{ sets: ['set_a'], shouldEmit: true }, /* should emit if flag is back in configured sets */
];

splitChangesUpdater = splitChangesUpdaterFactory(loggerMock, splitChangesFetcher, new SplitsCacheInMemory(), segmentsCache, splitFiltersValidation, readinessManager.splits, 1000, 1, true);

let index = 0;
let calls = 0;
// emit always if not configured sets
for (const setMock of setMocks) {
await expect(splitChangesUpdater(undefined, undefined, { payload: {...payload, sets: setMock.sets, status: 'ACTIVE'}, changeNumber: index })).resolves.toBe(true);
expect(splitsEmitSpy.mock.calls[index][0]).toBe('state::splits-arrived');
index++;
}

// @ts-ignore
splitFiltersValidation = { queryString: null, groupedFilters: { bySet: ['set_a'], byName: [], byPrefix: [] }, validFilters: [] };
splitChangesUpdater = splitChangesUpdaterFactory(loggerMock, splitChangesFetcher, new SplitsCacheInMemory(), segmentsCache, splitFiltersValidation, readinessManager.splits, 1000, 1, true);
splitsEmitSpy.mockReset();
index = 0;
for (const setMock of setMocks) {
await expect(splitChangesUpdater(undefined, undefined, { payload: {...payload, sets: setMock.sets, status: 'ACTIVE'}, changeNumber: index })).resolves.toBe(true);
if (setMock.shouldEmit) calls++;
expect(splitsEmitSpy.mock.calls.length).toBe(calls);
index++;
}

});
});
15 changes: 12 additions & 3 deletions src/sync/polling/updaters/splitChangesUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ export function splitChangesUpdaterFactory(
return promise;
}

/** Returns true if at least one split was updated */
function isThereUpdate(flagsChange: [boolean | void, void | boolean[], void | boolean[], boolean | void] | [any, any, any]) {
const [, added, removed, ] = flagsChange;
// There is at least one added or modified feature flag
if (added && added.some((update: boolean) => update)) return true;
// There is at least one removed feature flag
if (removed && removed.some((update: boolean) => update)) return true;
return false;
}

/**
* SplitChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch splits or synchronize them with the storage.
* Returned promise will not be rejected.
Expand Down Expand Up @@ -163,11 +173,10 @@ export function splitChangesUpdaterFactory(
splits.addSplits(mutation.added),
splits.removeSplits(mutation.removed),
segments.registerSegments(mutation.segments)
]).then(() => {

]).then((flagsChange) => {
if (splitsEventEmitter) {
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && (isClientSide || checkAllSegmentsExist(segments))))
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate(flagsChange) && (isClientSide || checkAllSegmentsExist(segments))))
.catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
.then(emitSplitsArrivedEvent => {
// emit SDK events
Expand Down

0 comments on commit f3b4de8

Please sign in to comment.