Skip to content

Commit 4615c32

Browse files
Add readiness tests
1 parent 2838820 commit 4615c32

File tree

3 files changed

+157
-0
lines changed

3 files changed

+157
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { SplitFactory } from '../../';
2+
3+
// Mocks
4+
import mySegments from '../mocks/mysegments.nicolas@split.io.json';
5+
import myLargeSegments from '../mocks/mylargesegments.employees.json';
6+
import { nearlyEqual } from '../testUtils';
7+
8+
const FF = {
9+
name: 'FF',
10+
status: 'ACTIVE',
11+
conditions: [{
12+
matcherGroup: {
13+
combiner: 'AND',
14+
matchers: []
15+
}
16+
}]
17+
};
18+
19+
const FF_WITH_SEGMENTS = {
20+
name: 'FF_WITH_SEGMENTS',
21+
status: 'ACTIVE',
22+
conditions: [{
23+
matcherGroup: {
24+
combiner: 'AND',
25+
matchers: [{
26+
matcherType: 'IN_SEGMENT',
27+
userDefinedSegmentMatcherData: {
28+
segmentName: 'A'
29+
}
30+
}]
31+
}
32+
}]
33+
};
34+
35+
const FF_WITH_LARGE_SEGMENTS = {
36+
name: 'FF_WITH_LARGE_SEGMENTS',
37+
status: 'ACTIVE',
38+
conditions: [{
39+
matcherGroup: {
40+
combiner: 'AND',
41+
matchers: [{
42+
matcherType: 'IN_LARGE_SEGMENT',
43+
userDefinedSegmentMatcherData: {
44+
segmentName: 'A'
45+
}
46+
}]
47+
}
48+
}]
49+
};
50+
51+
const waitConfig = {
52+
core: {
53+
authorizationKey: '<fake-token>',
54+
key: 'emi@split.io'
55+
},
56+
urls: {
57+
sdk: 'https://sdk.baseurl/largeSegments',
58+
},
59+
sync: {
60+
largeSegmentsEnabled: true
61+
},
62+
streamingEnabled: false
63+
};
64+
65+
const noWaitConfig = {
66+
...waitConfig,
67+
startup: {
68+
waitForLargeSegments: false
69+
}
70+
};
71+
72+
const SEGMENTS_DELAY = 50;
73+
const LARGE_SEGMENTS_DELAY = 100;
74+
const TEST_END_DELAY = 150;
75+
76+
export default function (fetchMock, assert) {
77+
78+
const testCases = [
79+
{ waitForLargeSegments: true, featureFlagsWithSegments: true, featureFlagsWithLS: true },
80+
{ waitForLargeSegments: true, featureFlagsWithSegments: true, featureFlagsWithLS: false },
81+
{ waitForLargeSegments: true, featureFlagsWithSegments: false, featureFlagsWithLS: true },
82+
{ waitForLargeSegments: true, featureFlagsWithSegments: false, featureFlagsWithLS: false },
83+
{ waitForLargeSegments: false, featureFlagsWithSegments: true, featureFlagsWithLS: true },
84+
{ waitForLargeSegments: false, featureFlagsWithSegments: true, featureFlagsWithLS: false },
85+
{ waitForLargeSegments: false, featureFlagsWithSegments: false, featureFlagsWithLS: true },
86+
{ waitForLargeSegments: false, featureFlagsWithSegments: false, featureFlagsWithLS: false },
87+
88+
// Special cases where large segments are not supported for the given SDK key: `/myLargeSegments/*` responds with 403 and there cannot be FFs with large segments
89+
{ waitForLargeSegments: true, featureFlagsWithSegments: true, featureFlagsWithLS: false, myLargeSegmentsForbidden: true },
90+
{ waitForLargeSegments: false, featureFlagsWithSegments: true, featureFlagsWithLS: false, myLargeSegmentsForbidden: true },
91+
];
92+
93+
testCases.forEach(({ waitForLargeSegments, featureFlagsWithSegments, featureFlagsWithLS, myLargeSegmentsForbidden }) => {
94+
95+
const config = waitForLargeSegments ? waitConfig : noWaitConfig;
96+
97+
const splitChangesMock = {
98+
since: -1,
99+
till: 1457552620999,
100+
splits: [FF, featureFlagsWithSegments && FF_WITH_SEGMENTS, featureFlagsWithLS && FF_WITH_LARGE_SEGMENTS].filter(ff => ff)
101+
};
102+
103+
// smart ready: if FFs are not using segments (or LS) we don't need to wait for them
104+
const SDK_READY_DELAY = Math.max(
105+
featureFlagsWithSegments ? SEGMENTS_DELAY : 0,
106+
featureFlagsWithLS && waitForLargeSegments ? LARGE_SEGMENTS_DELAY : 0
107+
);
108+
109+
// emit SDK_UPDATE if large segments arrive after SDK_READY event is emitted and FFs are using them
110+
const shouldEmitSdkUpdate = waitForLargeSegments === false && featureFlagsWithLS === true && (LARGE_SEGMENTS_DELAY > SEGMENTS_DELAY || featureFlagsWithSegments === false);
111+
112+
assert.test(t => {
113+
fetchMock.getOnce(config.urls.sdk + '/splitChanges?s=1.1&since=-1', { status: 200, body: splitChangesMock });
114+
fetchMock.getOnce(config.urls.sdk + '/splitChanges?s=1.1&since=1457552620999', { status: 200, body: { since: 1457552620999, till: 1457552620999, splits: [] } });
115+
fetchMock.getOnce(config.urls.sdk + '/mySegments/emi%40split.io', { status: 200, body: mySegments }, { delay: SEGMENTS_DELAY });
116+
fetchMock.getOnce(config.urls.sdk + '/myLargeSegments/emi%40split.io', { status: myLargeSegmentsForbidden ? 403 : 200, body: myLargeSegments }, { delay: LARGE_SEGMENTS_DELAY });
117+
118+
// smart pausing: if FFs are not using segments (or LS) we don't need to fetch them
119+
if (featureFlagsWithSegments) fetchMock.getOnce(config.urls.sdk + '/mySegments/shared', { status: 200, body: mySegments }, { delay: SEGMENTS_DELAY });
120+
if (featureFlagsWithLS) fetchMock.getOnce(config.urls.sdk + '/myLargeSegments/shared', { status: myLargeSegmentsForbidden ? 403 : 200, body: myLargeSegments }, { delay: LARGE_SEGMENTS_DELAY });
121+
122+
const splitio = SplitFactory(config);
123+
const client = splitio.client();
124+
125+
const start = Date.now();
126+
client.once(client.Event.SDK_READY, () => {
127+
assert.true(nearlyEqual(Date.now() - start, SDK_READY_DELAY));
128+
129+
splitio.client('shared').ready().then(() => {
130+
assert.true(nearlyEqual(Date.now() - start, 2 * SDK_READY_DELAY));
131+
});
132+
});
133+
134+
let updateEmitted = false;
135+
136+
client.once(client.Event.SDK_UPDATE, () => {
137+
assert.true(nearlyEqual(Date.now() - start, LARGE_SEGMENTS_DELAY));
138+
updateEmitted = true;
139+
});
140+
141+
setTimeout(() => {
142+
assert.true(updateEmitted === shouldEmitSdkUpdate);
143+
client.destroy().then(() => { t.end(); });
144+
}, TEST_END_DELAY);
145+
});
146+
147+
});
148+
149+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"myLargeSegments": [
3+
"employees"
4+
],
5+
"changeNumber": 1234567890
6+
}

src/__tests__/online/browser.spec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import impressionsSuiteNone from '../browserSuites/impressions.none.spec';
99
import telemetrySuite from '../browserSuites/telemetry.spec';
1010
import impressionsListenerSuite from '../browserSuites/impressions-listener.spec';
1111
import readinessSuite from '../browserSuites/readiness.spec';
12+
import readinessWithLargeSegmentsSuite from '../browserSuites/readiness-large-segments.spec';
1213
import readyFromCache from '../browserSuites/ready-from-cache.spec';
1314
import { withoutBindingTT, bindingTT } from '../browserSuites/events.spec';
1415
import sharedInstantiationSuite from '../browserSuites/shared-instantiation.spec';
@@ -122,6 +123,7 @@ tape('## E2E CI Tests ##', function (assert) {
122123
assert.test('E2E / Manager API', managerSuite.bind(null, settings, fetchMock));
123124
/* Validate readiness */
124125
assert.test('E2E / Readiness', readinessSuite.bind(null, fetchMock));
126+
assert.test('E2E / Readiness with large segments', readinessWithLargeSegmentsSuite.bind(null, fetchMock));
125127
/* Validate headers for ip and hostname are not sended with requests (ignore setting IPAddressesEnabled) */
126128
assert.test('E2E / Ignore setting IPAddressesEnabled', ignoreIpAddressesSettingSuite.bind(null, fetchMock));
127129
/* Check that impressions and events are sended to backend via Beacon API or Fetch when pagehide/visibilitychange events are triggered. */

0 commit comments

Comments
 (0)