Skip to content

Commit 3db4e45

Browse files
Update impression tests
1 parent 61ff938 commit 3db4e45

File tree

9 files changed

+182
-111
lines changed

9 files changed

+182
-111
lines changed

src/__tests__/browserSuites/impressions.debug.spec.js

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import splitChangesMock1 from '../mocks/splitchanges.since.-1.json';
44
import splitChangesMock2 from '../mocks/splitchanges.since.1457552620999.json';
55
import membershipsFacundo from '../mocks/memberships.facundo@split.io.json';
66
import { DEBUG } from '@splitsoftware/splitio-commons/src/utils/constants';
7+
import { truncateTimeFrame } from '@splitsoftware/splitio-commons/src/utils/time';
78
import { url } from '../testUtils';
89

910
const baseUrls = {
@@ -19,6 +20,8 @@ const settings = settingsFactory({
1920
streamingEnabled: false
2021
});
2122

23+
let truncatedTimeFrame;
24+
2225
export default function (fetchMock, assert) {
2326
// Mocking this specific route to make sure we only get the items we want to test from the handlers.
2427
fetchMock.getOnce(url(settings, '/splitChanges?s=1.2&since=-1'), { status: 200, body: splitChangesMock1 });
@@ -47,41 +50,21 @@ export default function (fetchMock, assert) {
4750
});
4851

4952
const client = splitio.client();
50-
const assertPayload = req => {
51-
const resp = JSON.parse(req.body);
52-
53-
assert.equal(resp.length, 1, 'We performed three evaluations so we should have 1 impressions type');
54-
55-
const alwaysOnWithConfigImpr = resp.filter(e => e.f === 'split_with_config')[0];
56-
57-
assert.equal(alwaysOnWithConfigImpr.i.length, 3);
58-
59-
function validateImpressionData(output, expected) {
60-
assert.equal(output.k, expected.keyName, 'Present impressions should have the correct key.');
61-
assert.equal(output.b, expected.bucketingKey, 'Present impressions should have the correct bucketingKey.');
62-
assert.equal(output.t, expected.treatment, 'Present impressions should have the correct treatment.');
63-
assert.equal(output.r, expected.label, 'Present impressions should have the correct label.');
64-
assert.equal(output.c, expected.changeNumber, 'Present impressions should have the correct changeNumber.');
65-
assert.equal(output.pt, expected.pt, 'Present impressions should have the correct previousTime.');
66-
}
67-
68-
validateImpressionData(alwaysOnWithConfigImpr.i[0], {
69-
keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n',
70-
bucketingKey: undefined, changeNumber: 828282828282, pt: undefined
71-
});
72-
validateImpressionData(alwaysOnWithConfigImpr.i[1], {
73-
keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n',
74-
bucketingKey: undefined, changeNumber: 828282828282, pt: alwaysOnWithConfigImpr.i[0].m
75-
});
76-
validateImpressionData(alwaysOnWithConfigImpr.i[2], {
77-
keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n',
78-
bucketingKey: undefined, changeNumber: 828282828282, pt: alwaysOnWithConfigImpr.i[1].m
79-
});
80-
};
8153

8254
fetchMock.postOnce(url(settings, '/testImpressions/bulk'), (url, req) => {
8355
assert.equal(req.headers.SplitSDKImpressionsMode, DEBUG);
84-
assertPayload(req);
56+
const data = JSON.parse(req.body);
57+
58+
assert.deepEqual(data, [{
59+
f: 'split_with_config',
60+
i: [{
61+
k: 'facundo@split.io', t: 'o.n', m: data[0].i[0].m, c: 828282828282, r: 'another expected label'
62+
}, {
63+
k: 'facundo@split.io', t: 'o.n', m: data[0].i[1].m, c: 828282828282, r: 'another expected label', pt: data[0].i[0].m,
64+
}, {
65+
k: 'facundo@split.io', t: 'o.n', m: data[0].i[2].m, c: 828282828282, r: 'another expected label', pt: data[0].i[1].m
66+
}]
67+
}]);
8568

8669
client.destroy().then(() => {
8770
assert.end();
@@ -90,9 +73,28 @@ export default function (fetchMock, assert) {
9073
return 200;
9174
});
9275

76+
fetchMock.postOnce(url(settings, '/testImpressions/count'), (url, opts) => {
77+
assert.deepEqual(JSON.parse(opts.body), {
78+
pf: [{ f: 'always_on_track_impressions_false', m: truncatedTimeFrame, rc: 1 }]
79+
}, 'We should generate impression count for the feature with track impressions disabled.');
80+
81+
return 200;
82+
});
83+
84+
fetchMock.postOnce(url(settings, '/v1/keys/cs'), (url, opts) => {
85+
assert.deepEqual(JSON.parse(opts.body), {
86+
keys: [{ fs: ['always_on_track_impressions_false'], k: 'facundo@split.io' }]
87+
}, 'We should track unique keys for the feature with track impressions disabled.');
88+
89+
return 200;
90+
});
91+
9392
client.ready().then(() => {
93+
truncatedTimeFrame = truncateTimeFrame(Date.now());
94+
9495
client.getTreatment('split_with_config');
9596
client.getTreatment('split_with_config');
9697
client.getTreatment('split_with_config');
98+
assert.equal(client.getTreatment('always_on_track_impressions_false'), 'on');
9799
});
98100
}

src/__tests__/browserSuites/impressions.none.spec.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ export default async function (fetchMock, assert) {
5858
pf: [
5959
{ f: 'split_with_config', m: truncatedTimeFrame, rc: 2 },
6060
{ f: 'always_off', m: truncatedTimeFrame, rc: 4 },
61-
{ f: 'always_on', m: truncatedTimeFrame, rc: 2 }
61+
{ f: 'always_on', m: truncatedTimeFrame, rc: 2 },
62+
{ f: 'always_on_track_impressions_false', m: truncatedTimeFrame, rc: 1 }
6263
]
6364
});
6465
return 200;
@@ -75,7 +76,7 @@ export default async function (fetchMock, assert) {
7576
},
7677
{
7778
k: 'emma@split.io',
78-
fs: ['always_off', 'always_on']
79+
fs: ['always_off', 'always_on', 'always_on_track_impressions_false']
7980
}
8081
]
8182
}, 'We performed evaluations for two keys, so we should have 2 item total.');
@@ -93,6 +94,7 @@ export default async function (fetchMock, assert) {
9394
client.getTreatment('always_on');
9495
client.getTreatment('always_off');
9596
client.getTreatment('split_with_config');
97+
sharedClient.getTreatment('always_on_track_impressions_false');
9698

9799
client.destroy().then(() => {
98100
assert.end();

src/__tests__/browserSuites/impressions.spec.js

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,19 @@ export default function (fetchMock, assert) {
4949
const assertPayload = req => {
5050
const resp = JSON.parse(req.body);
5151

52-
assert.equal(resp.length, 2, 'We performed three evaluations so we should have 2 impressions type');
52+
assert.equal(resp.length, 2, 'We performed evaluations for 3 features, but one with `trackImpressions` false, so we should have 2 items total');
5353

5454
const dependencyChildImpr = resp.filter(e => e.f === 'hierarchical_splits_test')[0];
55-
const alwaysOnWithConfigImpr = resp.filter(e => e.f === 'split_with_config')[0];
55+
const splitWithConfigImpr = resp.filter(e => e.f === 'split_with_config')[0];
56+
const alwaysOnWithTrackImpressionsFalse = resp.filter(e => e.f === 'always_on_track_impressions_false');
5657

5758
assert.true(dependencyChildImpr, 'Split we wanted to evaluate should be present on the impressions.');
5859
assert.false(resp.some(e => e.f === 'hierarchical_dep_always_on'), 'Parent split evaluations should not result in impressions.');
5960
assert.false(resp.some(e => e.f === 'hierarchical_dep_hierarchical'), 'No matter how deep is the chain.');
60-
assert.true(alwaysOnWithConfigImpr, 'Split evaluated with config should have generated an impression too.');
61-
assert.false(Object.prototype.hasOwnProperty.call(alwaysOnWithConfigImpr.i[0], 'configuration'), 'Impressions do not change with configuration evaluations.');
62-
assert.false(Object.prototype.hasOwnProperty.call(alwaysOnWithConfigImpr.i[0], 'config'), 'Impressions do not change with configuration evaluations.');
61+
assert.true(splitWithConfigImpr, 'Split evaluated with config should have generated an impression too.');
62+
assert.false(Object.prototype.hasOwnProperty.call(splitWithConfigImpr.i[0], 'configuration'), 'Impressions do not change with configuration evaluations.');
63+
assert.false(Object.prototype.hasOwnProperty.call(splitWithConfigImpr.i[0], 'config'), 'Impressions do not change with configuration evaluations.');
64+
assert.equal(alwaysOnWithTrackImpressionsFalse.length, 0);
6365

6466
const {
6567
k,
@@ -94,18 +96,26 @@ export default function (fetchMock, assert) {
9496
fetchMock.postOnce(url(settings, '/testImpressions/count'), (url, opts) => {
9597
const data = JSON.parse(opts.body);
9698

97-
assert.equal(data.pf.length, 1, 'We should generate impressions count for one feature.');
99+
assert.equal(data.pf.length, 2, 'We should generate impressions count for 2 features.');
98100

99101
// finding these validate the feature names collection too
100-
const dependencyChildImpr = data.pf.filter(e => e.f === 'hierarchical_splits_test')[0];
101-
const alwaysOnWithConfigImpr = data.pf.filter(e => e.f === 'split_with_config')[0];
102+
const splitWithConfigImpr = data.pf.filter(e => e.f === 'split_with_config')[0];
103+
const alwaysOnWithTrackImpressionsFalse = data.pf.filter(e => e.f === 'always_on_track_impressions_false')[0];
102104

103-
assert.equal(dependencyChildImpr.rc, 1);
104-
assert.equal(typeof dependencyChildImpr.m, 'number');
105-
assert.equal(dependencyChildImpr.m, truncatedTimeFrame);
106-
assert.equal(alwaysOnWithConfigImpr.rc, 3);
107-
assert.equal(typeof alwaysOnWithConfigImpr.m, 'number');
108-
assert.equal(alwaysOnWithConfigImpr.m, truncatedTimeFrame);
105+
assert.equal(splitWithConfigImpr.rc, 2);
106+
assert.equal(typeof splitWithConfigImpr.m, 'number');
107+
assert.equal(splitWithConfigImpr.m, truncatedTimeFrame);
108+
assert.equal(alwaysOnWithTrackImpressionsFalse.rc, 1);
109+
assert.equal(typeof alwaysOnWithTrackImpressionsFalse.m, 'number');
110+
assert.equal(alwaysOnWithTrackImpressionsFalse.m, truncatedTimeFrame);
111+
112+
return 200;
113+
});
114+
115+
fetchMock.postOnce(url(settings, '/v1/keys/cs'), (url, opts) => {
116+
assert.deepEqual(JSON.parse(opts.body), {
117+
keys: [{ fs: [ 'always_on_track_impressions_false' ], k: 'facundo@split.io' }]
118+
}, 'We should only track unique keys for features flags with track impressions disabled.');
109119

110120
return 200;
111121
});
@@ -120,5 +130,8 @@ export default function (fetchMock, assert) {
120130
}, 'We should get an evaluation as always.');
121131
client.getTreatmentWithConfig('split_with_config');
122132
client.getTreatmentWithConfig('split_with_config');
133+
134+
// Impression should not be tracked
135+
assert.equal(client.getTreatment('always_on_track_impressions_false'), 'on');
123136
});
124137
}

src/__tests__/browserSuites/telemetry.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export default async function telemetryBrowserSuite(fetchMock, t) {
7676

7777
// @TODO check if iDe value is correct
7878
assert.deepEqual(data, {
79-
mE: {}, hE: { sp: { 500: 1 }, ms: { 500: 1 } }, tR: 0, aR: 0, iQ: 4, iDe: 1, iDr: 0, spC: 32, seC: 1, skC: 1, eQ: 1, eD: 0, sE: [], t: [], ufs: {}
79+
mE: {}, hE: { sp: { 500: 1 }, ms: { 500: 1 } }, tR: 0, aR: 0, iQ: 4, iDe: 1, iDr: 0, spC: 33, seC: 1, skC: 1, eQ: 1, eD: 0, sE: [], t: [], ufs: {}
8080
}, 'metrics/usage JSON payload should be the expected');
8181

8282
finish.next();
@@ -96,7 +96,7 @@ export default async function telemetryBrowserSuite(fetchMock, t) {
9696
// @TODO check if iDe value is correct
9797
assert.deepEqual(data, {
9898
mL: {}, mE: {}, hE: {}, hL: {}, // errors and latencies were popped
99-
tR: 0, aR: 0, iQ: 4, iDe: 1, iDr: 0, spC: 32, seC: 1, skC: 1, eQ: 1, eD: 0, sE: [], t: [], ufs: {}
99+
tR: 0, aR: 0, iQ: 4, iDe: 1, iDr: 0, spC: 33, seC: 1, skC: 1, eQ: 1, eD: 0, sE: [], t: [], ufs: {}
100100
}, '2nd metrics/usage JSON payload should be the expected');
101101
return 200;
102102
});

src/__tests__/mocks/splitchanges.since.-1.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,7 @@
12651265
"trafficTypeId": null,
12661266
"trafficTypeName": null,
12671267
"name": "hierarchical_splits_test",
1268+
"trackImpressions": true,
12681269
"seed": 1276793945,
12691270
"changeNumber": 2828282828,
12701271
"status": "ACTIVE",
@@ -1381,6 +1382,45 @@
13811382
}
13821383
]
13831384
},
1385+
{
1386+
"orgId": null,
1387+
"environment": null,
1388+
"trafficTypeId": null,
1389+
"trafficTypeName": null,
1390+
"name": "always_on_track_impressions_false",
1391+
"trackImpressions": false,
1392+
"seed": -790401604,
1393+
"status": "ACTIVE",
1394+
"killed": false,
1395+
"defaultTreatment": "off",
1396+
"conditions": [
1397+
{
1398+
"matcherGroup": {
1399+
"combiner": "AND",
1400+
"matchers": [
1401+
{
1402+
"keySelector": {
1403+
"trafficType": "user",
1404+
"attribute": null
1405+
},
1406+
"matcherType": "ALL_KEYS",
1407+
"negate": false,
1408+
"userDefinedSegmentMatcherData": null,
1409+
"whitelistMatcherData": null,
1410+
"unaryNumericMatcherData": null,
1411+
"betweenMatcherData": null
1412+
}
1413+
]
1414+
},
1415+
"partitions": [
1416+
{
1417+
"treatment": "on",
1418+
"size": 100
1419+
}
1420+
]
1421+
}
1422+
]
1423+
},
13841424
{
13851425
"orgId": null,
13861426
"environment": null,
@@ -1426,6 +1466,7 @@
14261466
{
14271467
"trafficTypeName": null,
14281468
"name": "split_with_config",
1469+
"trackImpressions": true,
14291470
"algo": 2,
14301471
"seed": -1222652064,
14311472
"trafficAllocation": 100,

src/__tests__/nodeSuites/impressions.debug.spec.js

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { settingsFactory } from '../../settings';
33
import splitChangesMock1 from '../mocks/splitchanges.since.-1.json';
44
import splitChangesMock2 from '../mocks/splitchanges.since.1457552620999.json';
55
import { DEBUG } from '@splitsoftware/splitio-commons/src/utils/constants';
6+
import { truncateTimeFrame } from '@splitsoftware/splitio-commons/src/utils/time';
67
import { url } from '../testUtils';
78

89
const baseUrls = {
@@ -38,6 +39,8 @@ const config = {
3839
streamingEnabled: false
3940
};
4041

42+
let truncatedTimeFrame;
43+
4144
export default async function (key, fetchMock, assert) {
4245
// Mocking this specific route to make sure we only get the items we want to test from the handlers.
4346
fetchMock.getOnce(url(settings, '/splitChanges?s=1.1&since=-1'), { status: 200, body: splitChangesMock1 });
@@ -46,58 +49,53 @@ export default async function (key, fetchMock, assert) {
4649

4750
const splitio = SplitFactory(config);
4851
const client = splitio.client();
49-
let evaluationsStart = 0, readyEvaluationsStart = 0, evaluationsEnd = 0;
52+
let readyEvaluationsStart = 0;
5053

5154
fetchMock.postOnce(url(settings, '/testImpressions/bulk'), (url, opts) => {
5255
assert.equal(opts.headers.SplitSDKImpressionsMode, DEBUG);
5356
const data = JSON.parse(opts.body);
5457

55-
assert.equal(data.length, 1, 'We performed evaluations for one split, so we should have 1 item total.');
56-
57-
// finding these validate the feature names collection too
58-
const alwaysOnWithConfigImpr = data.filter(e => e.f === 'split_with_config')[0];
59-
60-
assert.equal(alwaysOnWithConfigImpr.i.length, 3);
61-
62-
function validateImpressionData(output, expected, performedWhenReady = true) {
63-
assert.equal(output.k, expected.keyName, 'Present impressions should have the correct key.');
64-
assert.equal(output.b, expected.bucketingKey, 'Present impressions should have the correct bucketingKey.');
65-
assert.equal(output.t, expected.treatment, 'Present impressions should have the correct treatment.');
66-
assert.equal(output.r, expected.label, 'Present impressions should have the correct label.');
67-
assert.equal(output.c, expected.changeNumber, 'Present impressions should have the correct changeNumber.');
68-
assert.equal(output.pt, expected.pt, 'Present impressions should have the correct previousTime.');
69-
assert.true(output.m >= (performedWhenReady ? readyEvaluationsStart : evaluationsStart) && output.m <= evaluationsEnd, 'Present impressions should have the correct timestamp (test with error margin).');
70-
}
58+
assert.deepEqual(data, [{
59+
f: 'split_with_config',
60+
i: [{
61+
k: 'facundo@split.io', t: 'o.n', m: data[0].i[0].m, c: 828282828282, r: 'another expected label', b: 'test_buck_key'
62+
}, {
63+
k: 'facundo@split.io', t: 'o.n', m: data[0].i[1].m, c: 828282828282, r: 'another expected label', b: 'test_buck_key', pt: data[0].i[0].m
64+
}, {
65+
k: 'facundo@split.io', t: 'o.n', m: data[0].i[2].m, c: 828282828282, r: 'another expected label', b: 'test_buck_key', pt: data[0].i[1].m
66+
}]
67+
}], 'We performed evaluations for one split, so we should have 1 item total.');
7168

7269
client.destroy().then(() => {
73-
validateImpressionData(alwaysOnWithConfigImpr.i[0], {
74-
keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n',
75-
bucketingKey: 'test_buck_key', changeNumber: 828282828282, pt: undefined
76-
});
77-
validateImpressionData(alwaysOnWithConfigImpr.i[1], {
78-
keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n',
79-
bucketingKey: 'test_buck_key', changeNumber: 828282828282, pt: alwaysOnWithConfigImpr.i[0].m
80-
});
81-
validateImpressionData(alwaysOnWithConfigImpr.i[2], {
82-
keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n',
83-
bucketingKey: 'test_buck_key', changeNumber: 828282828282, pt: alwaysOnWithConfigImpr.i[1].m
84-
});
85-
8670
assert.end();
8771
});
8872

8973
return 200;
9074
});
9175

92-
evaluationsStart = Date.now();
76+
fetchMock.postOnce(url(settings, '/testImpressions/count'), (url, opts) => {
77+
assert.deepEqual(JSON.parse(opts.body), {
78+
pf: [{ f: 'always_on_track_impressions_false', m: truncatedTimeFrame, rc: 1 }]
79+
}, 'We should generate impression count for the feature with track impressions disabled.');
80+
81+
return 200;
82+
});
83+
84+
fetchMock.postOnce(url(settings, '/v1/keys/ss'), (url, opts) => {
85+
assert.deepEqual(JSON.parse(opts.body), {
86+
keys: [{ f: 'always_on_track_impressions_false', ks: ['other_key'] }]
87+
}, 'We should track unique keys for the feature with track impressions disabled.');
88+
89+
return 200;
90+
});
9391

9492
await client.ready();
9593

9694
readyEvaluationsStart = Date.now();
95+
truncatedTimeFrame = truncateTimeFrame(readyEvaluationsStart);
9796

98-
client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config');
99-
client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config');
100-
client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config');
101-
102-
evaluationsEnd = Date.now();
97+
assert.equal(client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config'), 'o.n');
98+
assert.equal(client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config'), 'o.n');
99+
assert.equal(client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config'), 'o.n');
100+
assert.equal(client.getTreatment({ matchingKey: 'other_key', bucketingKey: 'test_buck_key' }, 'always_on_track_impressions_false'), 'on');
103101
}

0 commit comments

Comments
 (0)