Skip to content

Commit

Permalink
Added getState method to NodeJS factory instances
Browse files Browse the repository at this point in the history
EmilianoSanchez committed Oct 2, 2024
1 parent d58d8e3 commit 170c81c
Showing 11 changed files with 110 additions and 38 deletions.
18 changes: 9 additions & 9 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@splitsoftware/splitio",
"version": "10.28.1-rc.2",
"version": "10.28.1-rc.3",
"description": "Split SDK",
"files": [
"README.md",
@@ -40,7 +40,7 @@
"node": ">=6"
},
"dependencies": {
"@splitsoftware/splitio-commons": "1.17.1-rc.1",
"@splitsoftware/splitio-commons": "1.17.1-rc.2",
"@types/google.analytics": "0.0.40",
"@types/ioredis": "^4.28.0",
"bloom-filters": "^3.0.0",
58 changes: 58 additions & 0 deletions src/__tests__/browserSuites/ready-from-cache.spec.js
Original file line number Diff line number Diff line change
@@ -478,6 +478,64 @@ export default function (fetchMock, assert) {
});
});

assert.test(t => { // Testing when we start with preloaded data and MEMORY storage type (is ready from cache immediately)
const testUrls = {
sdk: 'https://sdk.baseurl/readyFromCacheWithPreloadedData',
events: 'https://events.baseurl/readyFromCacheWithPreloadedData'
};

t.plan(5);

fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=25', { status: 200, body: { ...splitChangesMock1, since: 25 } });
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: membershipsNicolas });
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas2%40split.io', { status: 200, body: { 'ms': {} } });

fetchMock.postOnce(testUrls.events + '/testImpressions/bulk', 200);
fetchMock.postOnce(testUrls.events + '/testImpressions/count', 200);

const splitio = SplitFactory({
...baseConfig,
storage: {
type: 'MEMORY',
},
urls: testUrls,
preloadedData: {
since: 25,
splitsData: [JSON.parse(alwaysOnSplitInverted)]
}
});

const client = splitio.client();
const client2 = splitio.client('[email protected]');

t.equal(client.__getStatus().isReadyFromCache, true, 'Client is ready from cache');

t.equal(client.getTreatment('always_on'), 'off', 'It should evaluate treatments with data from cache instead of control due to Input Validation');
t.equal(client2.getTreatment('always_on'), 'off', 'It should evaluate treatments with data from cache instead of control due to Input Validation');

client.on(client.Event.SDK_READY_TIMED_OUT, () => {
t.fail('It should not timeout in this scenario.');
t.end();
});

client.on(client.Event.SDK_READY_FROM_CACHE, () => {
t.fail('SDK is ready from cache immediately. SDK_READY_FROM_CACHE not emitted.');
t.end();
});

client.on(client.Event.SDK_READY, () => {
t.equal(client.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
});
client2.on(client2.Event.SDK_READY, () => {
t.equal(client2.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');

splitio.destroy().then(() => {
t.end();
});
});
});

/** Fetch specific splits **/

assert.test(t => { // Testing when we start with cached data but without storage hash (JS SDK <=v10.24.0 and Browser SDK <=v0.12.0), and a valid split filter config
2 changes: 1 addition & 1 deletion src/__tests__/browserSuites/ready-promise.spec.js
Original file line number Diff line number Diff line change
@@ -561,7 +561,7 @@ export default function readyPromiseAssertions(fetchMock, assert) {
});
}, 0);
});
}, fromSecondsToMillis(0.2));
}, fromSecondsToMillis(0.25));

}, 'Validate that warning messages are properly sent');

13 changes: 13 additions & 0 deletions src/__tests__/nodeSuites/evaluations.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { SplitFactory } from '../../';
import splitChangesMock1 from '../mocks/splitchanges.since.-1.json';

const SDK_INSTANCES_TO_TEST = 4;

@@ -265,6 +266,18 @@ export default async function (config, key, assert) {
getTreatmentsTests(client, i);
getTreatmentsWithConfigTests(client, i);

// getState method
const serverSideState = splitio.getState();
assert.equal(serverSideState.since, 1457552620999);
assert.equal(serverSideState.splitsData.length, splitChangesMock1.splits.length);
assert.deepEqual(serverSideState.segmentsData, { employees: [], splitters: [], developers: [] });
assert.deepEqual(serverSideState.mySegmentsData, undefined);
const clientSideState = splitio.getState(['user1']);
assert.equal(clientSideState.since, 1457552620999);
assert.equal(clientSideState.splitsData.length, splitChangesMock1.splits.length);
assert.deepEqual(clientSideState.segmentsData, undefined);
assert.deepEqual(clientSideState.mySegmentsData, { user1: [] });

await client.destroy();

tested++;
2 changes: 0 additions & 2 deletions src/__tests__/offline/browser.spec.js
Original file line number Diff line number Diff line change
@@ -112,8 +112,6 @@ tape('Browser offline mode', function (assert) {
});

const sdkReadyFromCache = (client) => () => {
assert.equal(factory.settings.storage.type, 'MEMORY', 'In localhost mode, storage must fallback to memory storage');

const clientStatus = client.__getStatus();
assert.equal(clientStatus.isReadyFromCache, true, 'If ready from cache, READY_FROM_CACHE status must be true');
assert.equal(clientStatus.isReady, false, 'READY status must not be set before READY_FROM_CACHE');
7 changes: 2 additions & 5 deletions src/factory/browser.js
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ import { sdkManagerFactory } from '@splitsoftware/splitio-commons/src/sdkManager
import { sdkClientMethodCSFactory } from '@splitsoftware/splitio-commons/src/sdkClient/sdkClientMethodCSWithTT';
import { impressionObserverCSFactory } from '@splitsoftware/splitio-commons/src/trackers/impressionObserver/impressionObserverCS';
import { integrationsManagerFactory } from '@splitsoftware/splitio-commons/src/integrations/browser';
import { __InLocalStorageMockFactory } from '@splitsoftware/splitio-commons/src/utils/settingsValidation/storage/storageCS';
import { sdkFactory } from '@splitsoftware/splitio-commons/src/sdkFactory';
import { LOCALHOST_MODE, STORAGE_LOCALSTORAGE } from '@splitsoftware/splitio-commons/src/utils/constants';
import { createUserConsentAPI } from '@splitsoftware/splitio-commons/src/consent/sdkUserConsent';
@@ -20,10 +19,8 @@ const syncManagerOnlineCSFactory = syncManagerOnlineFactory(pollingManagerCSFact

function getStorage(settings) {
return settings.storage.type === STORAGE_LOCALSTORAGE ?
InLocalStorage(settings.storage)
: settings.storage.__originalType === STORAGE_LOCALSTORAGE ?
__InLocalStorageMockFactory
: InMemoryStorageCSFactory;
InLocalStorage(settings.storage) :
InMemoryStorageCSFactory;
}

/**
13 changes: 12 additions & 1 deletion src/factory/node.js
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import { pushManagerFactory } from '@splitsoftware/splitio-commons/src/sync/stre
import { pollingManagerSSFactory } from '@splitsoftware/splitio-commons/src/sync/polling/pollingManagerSS';
import { InRedisStorage } from '@splitsoftware/splitio-commons/src/storages/inRedis';
import { InMemoryStorageFactory } from '@splitsoftware/splitio-commons/src/storages/inMemory/InMemoryStorage';
import { getSnapshot } from '@splitsoftware/splitio-commons/src/storages/dataLoader';
import { sdkManagerFactory } from '@splitsoftware/splitio-commons/src/sdkManager';
import { sdkClientMethodFactory } from '@splitsoftware/splitio-commons/src/sdkClient/sdkClientMethod';
import { impressionObserverSSFactory } from '@splitsoftware/splitio-commons/src/trackers/impressionObserver/impressionObserverSS';
@@ -47,7 +48,17 @@ function getModules(settings) {

impressionsObserverFactory: impressionObserverSSFactory,

filterAdapterFactory: bloomFilterFactory
filterAdapterFactory: bloomFilterFactory,

extraProps: (params) => {
if (params.settings.mode !== CONSUMER_MODE) {
return {
getState(userKeys) {
return getSnapshot(params.storage, userKeys);
}
};
}
}
};

switch (settings.mode) {
2 changes: 1 addition & 1 deletion src/settings/defaults/version.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const packageVersion = '10.28.1-rc.2';
export const packageVersion = '10.28.1-rc.3';
18 changes: 2 additions & 16 deletions src/settings/storage/browser.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,29 @@
import { isLocalStorageAvailable } from '@splitsoftware/splitio-commons/src/utils/env/isLocalStorageAvailable';
import { LOCALHOST_MODE, STORAGE_MEMORY } from '@splitsoftware/splitio-commons/src/utils/constants';
import { STORAGE_MEMORY } from '@splitsoftware/splitio-commons/src/utils/constants';

const STORAGE_LOCALSTORAGE = 'LOCALSTORAGE';

export function validateStorage(settings) {
let {
log,
mode,
storage: {
type,
options = {},
prefix
} = { type: STORAGE_MEMORY },
} = settings;
let __originalType;

const fallbackToMemory = () => {
__originalType = type;
type = STORAGE_MEMORY;
};

// In localhost mode, fallback to Memory storage and track original type to emit SDK_READY_FROM_CACHE if corresponds.
// ATM, other mode settings (e.g., 'consumer') are ignored in client-side API, and so treated as standalone.
if (mode === LOCALHOST_MODE && type === STORAGE_LOCALSTORAGE) {
fallbackToMemory();
}

// If an invalid storage type is provided OR we want to use LOCALSTORAGE and
// it's not available, fallback into MEMORY
if (type !== STORAGE_MEMORY && type !== STORAGE_LOCALSTORAGE ||
type === STORAGE_LOCALSTORAGE && !isLocalStorageAvailable()) {
fallbackToMemory();
type = STORAGE_MEMORY;
log.error('Invalid or unavailable storage. Fallback into MEMORY storage');
}

return {
type,
options,
prefix,
__originalType
};
}
11 changes: 10 additions & 1 deletion types/splitio.d.ts
Original file line number Diff line number Diff line change
@@ -94,6 +94,7 @@ interface ISettings {
options: Object,
type: StorageType
},
readonly preloadedData?: SplitIO.PreloadedData,
readonly urls: {
events: string,
sdk: string,
@@ -953,6 +954,10 @@ declare namespace SplitIO {
* @typedef {string} ConsentStatus
*/
type ConsentStatus = 'GRANTED' | 'DECLINED' | 'UNKNOWN';
/**
* Defines the format of rollout plan data to preload on the factory storage (cache).
*/
type PreloadedData = Object;
/**
* Settings interface for SDK instances created on the browser
* @interface IBrowserSettings
@@ -1385,7 +1390,11 @@ declare namespace SplitIO {
* @function manager
* @returns {IManager} The manager instance.
*/
manager(): IManager
manager(): IManager,
/**
* @TODO add description
*/
getState(): PreloadedData,
}
/**
* This represents the interface for the SDK instance with synchronous storage.

0 comments on commit 170c81c

Please sign in to comment.