From 3db4e4536dba7f07095839d8050943c5f1ef0e92 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 10 Dec 2024 15:51:11 -0300 Subject: [PATCH 01/11] Update impression tests --- .../browserSuites/impressions.debug.spec.js | 66 ++++++++--------- .../browserSuites/impressions.none.spec.js | 6 +- .../browserSuites/impressions.spec.js | 41 +++++++---- src/__tests__/browserSuites/telemetry.spec.js | 4 +- .../mocks/splitchanges.since.-1.json | 41 +++++++++++ .../nodeSuites/impressions.debug.spec.js | 70 +++++++++---------- .../nodeSuites/impressions.none.spec.js | 10 ++- src/__tests__/nodeSuites/impressions.spec.js | 51 ++++++++------ src/__tests__/nodeSuites/telemetry.spec.js | 4 +- 9 files changed, 182 insertions(+), 111 deletions(-) diff --git a/src/__tests__/browserSuites/impressions.debug.spec.js b/src/__tests__/browserSuites/impressions.debug.spec.js index 18d875b4e..5f90b7004 100644 --- a/src/__tests__/browserSuites/impressions.debug.spec.js +++ b/src/__tests__/browserSuites/impressions.debug.spec.js @@ -4,6 +4,7 @@ import splitChangesMock1 from '../mocks/splitchanges.since.-1.json'; import splitChangesMock2 from '../mocks/splitchanges.since.1457552620999.json'; import membershipsFacundo from '../mocks/memberships.facundo@split.io.json'; import { DEBUG } from '@splitsoftware/splitio-commons/src/utils/constants'; +import { truncateTimeFrame } from '@splitsoftware/splitio-commons/src/utils/time'; import { url } from '../testUtils'; const baseUrls = { @@ -19,6 +20,8 @@ const settings = settingsFactory({ streamingEnabled: false }); +let truncatedTimeFrame; + export default function (fetchMock, assert) { // Mocking this specific route to make sure we only get the items we want to test from the handlers. fetchMock.getOnce(url(settings, '/splitChanges?s=1.2&since=-1'), { status: 200, body: splitChangesMock1 }); @@ -47,41 +50,21 @@ export default function (fetchMock, assert) { }); const client = splitio.client(); - const assertPayload = req => { - const resp = JSON.parse(req.body); - - assert.equal(resp.length, 1, 'We performed three evaluations so we should have 1 impressions type'); - - const alwaysOnWithConfigImpr = resp.filter(e => e.f === 'split_with_config')[0]; - - assert.equal(alwaysOnWithConfigImpr.i.length, 3); - - function validateImpressionData(output, expected) { - assert.equal(output.k, expected.keyName, 'Present impressions should have the correct key.'); - assert.equal(output.b, expected.bucketingKey, 'Present impressions should have the correct bucketingKey.'); - assert.equal(output.t, expected.treatment, 'Present impressions should have the correct treatment.'); - assert.equal(output.r, expected.label, 'Present impressions should have the correct label.'); - assert.equal(output.c, expected.changeNumber, 'Present impressions should have the correct changeNumber.'); - assert.equal(output.pt, expected.pt, 'Present impressions should have the correct previousTime.'); - } - - validateImpressionData(alwaysOnWithConfigImpr.i[0], { - keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n', - bucketingKey: undefined, changeNumber: 828282828282, pt: undefined - }); - validateImpressionData(alwaysOnWithConfigImpr.i[1], { - keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n', - bucketingKey: undefined, changeNumber: 828282828282, pt: alwaysOnWithConfigImpr.i[0].m - }); - validateImpressionData(alwaysOnWithConfigImpr.i[2], { - keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n', - bucketingKey: undefined, changeNumber: 828282828282, pt: alwaysOnWithConfigImpr.i[1].m - }); - }; fetchMock.postOnce(url(settings, '/testImpressions/bulk'), (url, req) => { assert.equal(req.headers.SplitSDKImpressionsMode, DEBUG); - assertPayload(req); + const data = JSON.parse(req.body); + + assert.deepEqual(data, [{ + f: 'split_with_config', + i: [{ + k: 'facundo@split.io', t: 'o.n', m: data[0].i[0].m, c: 828282828282, r: 'another expected label' + }, { + 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, + }, { + 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 + }] + }]); client.destroy().then(() => { assert.end(); @@ -90,9 +73,28 @@ export default function (fetchMock, assert) { return 200; }); + fetchMock.postOnce(url(settings, '/testImpressions/count'), (url, opts) => { + assert.deepEqual(JSON.parse(opts.body), { + pf: [{ f: 'always_on_track_impressions_false', m: truncatedTimeFrame, rc: 1 }] + }, 'We should generate impression count for the feature with track impressions disabled.'); + + return 200; + }); + + fetchMock.postOnce(url(settings, '/v1/keys/cs'), (url, opts) => { + assert.deepEqual(JSON.parse(opts.body), { + keys: [{ fs: ['always_on_track_impressions_false'], k: 'facundo@split.io' }] + }, 'We should track unique keys for the feature with track impressions disabled.'); + + return 200; + }); + client.ready().then(() => { + truncatedTimeFrame = truncateTimeFrame(Date.now()); + client.getTreatment('split_with_config'); client.getTreatment('split_with_config'); client.getTreatment('split_with_config'); + assert.equal(client.getTreatment('always_on_track_impressions_false'), 'on'); }); } diff --git a/src/__tests__/browserSuites/impressions.none.spec.js b/src/__tests__/browserSuites/impressions.none.spec.js index d90c407a7..2294c9695 100644 --- a/src/__tests__/browserSuites/impressions.none.spec.js +++ b/src/__tests__/browserSuites/impressions.none.spec.js @@ -58,7 +58,8 @@ export default async function (fetchMock, assert) { pf: [ { f: 'split_with_config', m: truncatedTimeFrame, rc: 2 }, { f: 'always_off', m: truncatedTimeFrame, rc: 4 }, - { f: 'always_on', m: truncatedTimeFrame, rc: 2 } + { f: 'always_on', m: truncatedTimeFrame, rc: 2 }, + { f: 'always_on_track_impressions_false', m: truncatedTimeFrame, rc: 1 } ] }); return 200; @@ -75,7 +76,7 @@ export default async function (fetchMock, assert) { }, { k: 'emma@split.io', - fs: ['always_off', 'always_on'] + fs: ['always_off', 'always_on', 'always_on_track_impressions_false'] } ] }, 'We performed evaluations for two keys, so we should have 2 item total.'); @@ -93,6 +94,7 @@ export default async function (fetchMock, assert) { client.getTreatment('always_on'); client.getTreatment('always_off'); client.getTreatment('split_with_config'); + sharedClient.getTreatment('always_on_track_impressions_false'); client.destroy().then(() => { assert.end(); diff --git a/src/__tests__/browserSuites/impressions.spec.js b/src/__tests__/browserSuites/impressions.spec.js index aa4cff4c0..7c72df87d 100644 --- a/src/__tests__/browserSuites/impressions.spec.js +++ b/src/__tests__/browserSuites/impressions.spec.js @@ -49,17 +49,19 @@ export default function (fetchMock, assert) { const assertPayload = req => { const resp = JSON.parse(req.body); - assert.equal(resp.length, 2, 'We performed three evaluations so we should have 2 impressions type'); + assert.equal(resp.length, 2, 'We performed evaluations for 3 features, but one with `trackImpressions` false, so we should have 2 items total'); const dependencyChildImpr = resp.filter(e => e.f === 'hierarchical_splits_test')[0]; - const alwaysOnWithConfigImpr = resp.filter(e => e.f === 'split_with_config')[0]; + const splitWithConfigImpr = resp.filter(e => e.f === 'split_with_config')[0]; + const alwaysOnWithTrackImpressionsFalse = resp.filter(e => e.f === 'always_on_track_impressions_false'); assert.true(dependencyChildImpr, 'Split we wanted to evaluate should be present on the impressions.'); assert.false(resp.some(e => e.f === 'hierarchical_dep_always_on'), 'Parent split evaluations should not result in impressions.'); assert.false(resp.some(e => e.f === 'hierarchical_dep_hierarchical'), 'No matter how deep is the chain.'); - assert.true(alwaysOnWithConfigImpr, 'Split evaluated with config should have generated an impression too.'); - assert.false(Object.prototype.hasOwnProperty.call(alwaysOnWithConfigImpr.i[0], 'configuration'), 'Impressions do not change with configuration evaluations.'); - assert.false(Object.prototype.hasOwnProperty.call(alwaysOnWithConfigImpr.i[0], 'config'), 'Impressions do not change with configuration evaluations.'); + assert.true(splitWithConfigImpr, 'Split evaluated with config should have generated an impression too.'); + assert.false(Object.prototype.hasOwnProperty.call(splitWithConfigImpr.i[0], 'configuration'), 'Impressions do not change with configuration evaluations.'); + assert.false(Object.prototype.hasOwnProperty.call(splitWithConfigImpr.i[0], 'config'), 'Impressions do not change with configuration evaluations.'); + assert.equal(alwaysOnWithTrackImpressionsFalse.length, 0); const { k, @@ -94,18 +96,26 @@ export default function (fetchMock, assert) { fetchMock.postOnce(url(settings, '/testImpressions/count'), (url, opts) => { const data = JSON.parse(opts.body); - assert.equal(data.pf.length, 1, 'We should generate impressions count for one feature.'); + assert.equal(data.pf.length, 2, 'We should generate impressions count for 2 features.'); // finding these validate the feature names collection too - const dependencyChildImpr = data.pf.filter(e => e.f === 'hierarchical_splits_test')[0]; - const alwaysOnWithConfigImpr = data.pf.filter(e => e.f === 'split_with_config')[0]; + const splitWithConfigImpr = data.pf.filter(e => e.f === 'split_with_config')[0]; + const alwaysOnWithTrackImpressionsFalse = data.pf.filter(e => e.f === 'always_on_track_impressions_false')[0]; - assert.equal(dependencyChildImpr.rc, 1); - assert.equal(typeof dependencyChildImpr.m, 'number'); - assert.equal(dependencyChildImpr.m, truncatedTimeFrame); - assert.equal(alwaysOnWithConfigImpr.rc, 3); - assert.equal(typeof alwaysOnWithConfigImpr.m, 'number'); - assert.equal(alwaysOnWithConfigImpr.m, truncatedTimeFrame); + assert.equal(splitWithConfigImpr.rc, 2); + assert.equal(typeof splitWithConfigImpr.m, 'number'); + assert.equal(splitWithConfigImpr.m, truncatedTimeFrame); + assert.equal(alwaysOnWithTrackImpressionsFalse.rc, 1); + assert.equal(typeof alwaysOnWithTrackImpressionsFalse.m, 'number'); + assert.equal(alwaysOnWithTrackImpressionsFalse.m, truncatedTimeFrame); + + return 200; + }); + + fetchMock.postOnce(url(settings, '/v1/keys/cs'), (url, opts) => { + assert.deepEqual(JSON.parse(opts.body), { + keys: [{ fs: [ 'always_on_track_impressions_false' ], k: 'facundo@split.io' }] + }, 'We should only track unique keys for features flags with track impressions disabled.'); return 200; }); @@ -120,5 +130,8 @@ export default function (fetchMock, assert) { }, 'We should get an evaluation as always.'); client.getTreatmentWithConfig('split_with_config'); client.getTreatmentWithConfig('split_with_config'); + + // Impression should not be tracked + assert.equal(client.getTreatment('always_on_track_impressions_false'), 'on'); }); } diff --git a/src/__tests__/browserSuites/telemetry.spec.js b/src/__tests__/browserSuites/telemetry.spec.js index 5ed7c331d..7f6fbc8bc 100644 --- a/src/__tests__/browserSuites/telemetry.spec.js +++ b/src/__tests__/browserSuites/telemetry.spec.js @@ -76,7 +76,7 @@ export default async function telemetryBrowserSuite(fetchMock, t) { // @TODO check if iDe value is correct assert.deepEqual(data, { - 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: {} + 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: {} }, 'metrics/usage JSON payload should be the expected'); finish.next(); @@ -96,7 +96,7 @@ export default async function telemetryBrowserSuite(fetchMock, t) { // @TODO check if iDe value is correct assert.deepEqual(data, { mL: {}, mE: {}, hE: {}, hL: {}, // errors and latencies were popped - tR: 0, aR: 0, iQ: 4, iDe: 1, iDr: 0, spC: 32, seC: 1, skC: 1, eQ: 1, eD: 0, sE: [], t: [], ufs: {} + tR: 0, aR: 0, iQ: 4, iDe: 1, iDr: 0, spC: 33, seC: 1, skC: 1, eQ: 1, eD: 0, sE: [], t: [], ufs: {} }, '2nd metrics/usage JSON payload should be the expected'); return 200; }); diff --git a/src/__tests__/mocks/splitchanges.since.-1.json b/src/__tests__/mocks/splitchanges.since.-1.json index ee21cf9cc..c31ac7e8b 100644 --- a/src/__tests__/mocks/splitchanges.since.-1.json +++ b/src/__tests__/mocks/splitchanges.since.-1.json @@ -1265,6 +1265,7 @@ "trafficTypeId": null, "trafficTypeName": null, "name": "hierarchical_splits_test", + "trackImpressions": true, "seed": 1276793945, "changeNumber": 2828282828, "status": "ACTIVE", @@ -1381,6 +1382,45 @@ } ] }, + { + "orgId": null, + "environment": null, + "trafficTypeId": null, + "trafficTypeName": null, + "name": "always_on_track_impressions_false", + "trackImpressions": false, + "seed": -790401604, + "status": "ACTIVE", + "killed": false, + "defaultTreatment": "off", + "conditions": [ + { + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "user", + "attribute": null + }, + "matcherType": "ALL_KEYS", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 100 + } + ] + } + ] + }, { "orgId": null, "environment": null, @@ -1426,6 +1466,7 @@ { "trafficTypeName": null, "name": "split_with_config", + "trackImpressions": true, "algo": 2, "seed": -1222652064, "trafficAllocation": 100, diff --git a/src/__tests__/nodeSuites/impressions.debug.spec.js b/src/__tests__/nodeSuites/impressions.debug.spec.js index 9d09415c0..08faa13e3 100644 --- a/src/__tests__/nodeSuites/impressions.debug.spec.js +++ b/src/__tests__/nodeSuites/impressions.debug.spec.js @@ -3,6 +3,7 @@ import { settingsFactory } from '../../settings'; import splitChangesMock1 from '../mocks/splitchanges.since.-1.json'; import splitChangesMock2 from '../mocks/splitchanges.since.1457552620999.json'; import { DEBUG } from '@splitsoftware/splitio-commons/src/utils/constants'; +import { truncateTimeFrame } from '@splitsoftware/splitio-commons/src/utils/time'; import { url } from '../testUtils'; const baseUrls = { @@ -38,6 +39,8 @@ const config = { streamingEnabled: false }; +let truncatedTimeFrame; + export default async function (key, fetchMock, assert) { // Mocking this specific route to make sure we only get the items we want to test from the handlers. 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) { const splitio = SplitFactory(config); const client = splitio.client(); - let evaluationsStart = 0, readyEvaluationsStart = 0, evaluationsEnd = 0; + let readyEvaluationsStart = 0; fetchMock.postOnce(url(settings, '/testImpressions/bulk'), (url, opts) => { assert.equal(opts.headers.SplitSDKImpressionsMode, DEBUG); const data = JSON.parse(opts.body); - assert.equal(data.length, 1, 'We performed evaluations for one split, so we should have 1 item total.'); - - // finding these validate the feature names collection too - const alwaysOnWithConfigImpr = data.filter(e => e.f === 'split_with_config')[0]; - - assert.equal(alwaysOnWithConfigImpr.i.length, 3); - - function validateImpressionData(output, expected, performedWhenReady = true) { - assert.equal(output.k, expected.keyName, 'Present impressions should have the correct key.'); - assert.equal(output.b, expected.bucketingKey, 'Present impressions should have the correct bucketingKey.'); - assert.equal(output.t, expected.treatment, 'Present impressions should have the correct treatment.'); - assert.equal(output.r, expected.label, 'Present impressions should have the correct label.'); - assert.equal(output.c, expected.changeNumber, 'Present impressions should have the correct changeNumber.'); - assert.equal(output.pt, expected.pt, 'Present impressions should have the correct previousTime.'); - assert.true(output.m >= (performedWhenReady ? readyEvaluationsStart : evaluationsStart) && output.m <= evaluationsEnd, 'Present impressions should have the correct timestamp (test with error margin).'); - } + assert.deepEqual(data, [{ + f: 'split_with_config', + i: [{ + k: 'facundo@split.io', t: 'o.n', m: data[0].i[0].m, c: 828282828282, r: 'another expected label', b: 'test_buck_key' + }, { + 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 + }, { + 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 + }] + }], 'We performed evaluations for one split, so we should have 1 item total.'); client.destroy().then(() => { - validateImpressionData(alwaysOnWithConfigImpr.i[0], { - keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n', - bucketingKey: 'test_buck_key', changeNumber: 828282828282, pt: undefined - }); - validateImpressionData(alwaysOnWithConfigImpr.i[1], { - keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n', - bucketingKey: 'test_buck_key', changeNumber: 828282828282, pt: alwaysOnWithConfigImpr.i[0].m - }); - validateImpressionData(alwaysOnWithConfigImpr.i[2], { - keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n', - bucketingKey: 'test_buck_key', changeNumber: 828282828282, pt: alwaysOnWithConfigImpr.i[1].m - }); - assert.end(); }); return 200; }); - evaluationsStart = Date.now(); + fetchMock.postOnce(url(settings, '/testImpressions/count'), (url, opts) => { + assert.deepEqual(JSON.parse(opts.body), { + pf: [{ f: 'always_on_track_impressions_false', m: truncatedTimeFrame, rc: 1 }] + }, 'We should generate impression count for the feature with track impressions disabled.'); + + return 200; + }); + + fetchMock.postOnce(url(settings, '/v1/keys/ss'), (url, opts) => { + assert.deepEqual(JSON.parse(opts.body), { + keys: [{ f: 'always_on_track_impressions_false', ks: ['other_key'] }] + }, 'We should track unique keys for the feature with track impressions disabled.'); + + return 200; + }); await client.ready(); readyEvaluationsStart = Date.now(); + truncatedTimeFrame = truncateTimeFrame(readyEvaluationsStart); - client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config'); - client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config'); - client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config'); - - evaluationsEnd = Date.now(); + assert.equal(client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config'), 'o.n'); + assert.equal(client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config'), 'o.n'); + assert.equal(client.getTreatment({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config'), 'o.n'); + assert.equal(client.getTreatment({ matchingKey: 'other_key', bucketingKey: 'test_buck_key' }, 'always_on_track_impressions_false'), 'on'); } diff --git a/src/__tests__/nodeSuites/impressions.none.spec.js b/src/__tests__/nodeSuites/impressions.none.spec.js index 4c726bca4..2e47f32e1 100644 --- a/src/__tests__/nodeSuites/impressions.none.spec.js +++ b/src/__tests__/nodeSuites/impressions.none.spec.js @@ -54,7 +54,8 @@ export default async function (key, fetchMock, assert) { pf: [ { f: 'split_with_config', m: truncatedTimeFrame, rc: 3 }, { f: 'always_off', m: truncatedTimeFrame, rc: 3 }, - { f: 'always_on', m: truncatedTimeFrame, rc: 5 } + { f: 'always_on', m: truncatedTimeFrame, rc: 5 }, + { f: 'always_on_track_impressions_false', m: truncatedTimeFrame, rc: 1 } ] }); return 200; @@ -76,9 +77,13 @@ export default async function (key, fetchMock, assert) { { f: 'always_on', ks: ['emma@split.io', 'emi@split.io', 'nico@split.io'] + }, + { + f: 'always_on_track_impressions_false', + ks: ['emi@split.io'] } ] - }, 'We performed evaluations for three split, so we should have 3 item total.'); + }, 'We performed evaluations for 4 flags, so we should have 4 items total.'); return 200; }); @@ -95,6 +100,7 @@ export default async function (key, fetchMock, assert) { client.getTreatment('nico@split.io', 'always_on'); client.getTreatment('emi@split.io', 'split_with_config'); client.getTreatment('emma@split.io', 'split_with_config'); + client.getTreatment('emi@split.io', 'always_on_track_impressions_false'); client.destroy().then(() => { assert.end(); diff --git a/src/__tests__/nodeSuites/impressions.spec.js b/src/__tests__/nodeSuites/impressions.spec.js index b5fb102a7..ef96a537b 100644 --- a/src/__tests__/nodeSuites/impressions.spec.js +++ b/src/__tests__/nodeSuites/impressions.spec.js @@ -49,23 +49,25 @@ export default async function (key, fetchMock, assert) { assert.equal(opts.headers.SplitSDKImpressionsMode, OPTIMIZED); const data = JSON.parse(opts.body); - assert.equal(data.length, 3, 'We performed evaluations for three splits, so we should have 3 items total.'); + assert.equal(data.length, 3, 'We performed evaluations for 4 features, but one with `trackImpressions` false, so we should have 3 items total.'); // finding these validate the feature names collection too const dependencyChildImpr = data.filter(e => e.f === 'hierarchical_splits_test')[0]; - const alwaysOnWithConfigImpr = data.filter(e => e.f === 'split_with_config')[0]; + const splitWithConfigImpr = data.filter(e => e.f === 'split_with_config')[0]; const notExistentSplitImpr = data.filter(e => e.f === 'not_existent_split')[0]; + const alwaysOnWithTrackImpressionsFalse = data.filter(e => e.f === 'always_on_track_impressions_false'); assert.equal(notExistentSplitImpr.i.length, 1); // Only one, the split not found is filtered by the non existent Split check. - assert.equal(alwaysOnWithConfigImpr.i.length, 2); + assert.equal(splitWithConfigImpr.i.length, 2); assert.equal(dependencyChildImpr.i.length, 1); + assert.equal(alwaysOnWithTrackImpressionsFalse.length, 0); assert.true(dependencyChildImpr, 'Split we wanted to evaluate should be present on the impressions.'); assert.false(data.some(e => e.f === 'hierarchical_dep_always_on'), 'Parent split evaluations should not result in impressions.'); assert.false(data.some(e => e.f === 'hierarchical_dep_hierarchical'), 'No matter how deep is the chain.'); - assert.true(alwaysOnWithConfigImpr, 'Split evaluated with config should have generated an impression too.'); - assert.false(Object.prototype.hasOwnProperty.call(alwaysOnWithConfigImpr.i[0], 'configuration'), 'Impressions do not change with configuration evaluations.'); - assert.false(Object.prototype.hasOwnProperty.call(alwaysOnWithConfigImpr.i[0], 'config'), 'Impressions do not change with configuration evaluations.'); + assert.true(splitWithConfigImpr, 'Split evaluated with config should have generated an impression too.'); + assert.false(Object.prototype.hasOwnProperty.call(splitWithConfigImpr.i[0], 'configuration'), 'Impressions do not change with configuration evaluations.'); + assert.false(Object.prototype.hasOwnProperty.call(splitWithConfigImpr.i[0], 'config'), 'Impressions do not change with configuration evaluations.'); function validateImpressionData(output, expected, performedWhenReady = true) { assert.equal(output.k, expected.keyName, 'Present impressions should have the correct key.'); @@ -84,7 +86,7 @@ export default async function (key, fetchMock, assert) { keyName: 'facundo@split.io', label: 'expected label', treatment: 'on', bucketingKey: undefined, changeNumber: 2828282828 }); - validateImpressionData(alwaysOnWithConfigImpr.i[0], { + validateImpressionData(splitWithConfigImpr.i[0], { keyName: 'facundo@split.io', label: 'another expected label', treatment: 'o.n', bucketingKey: 'test_buck_key', changeNumber: 828282828282 }); @@ -105,22 +107,26 @@ export default async function (key, fetchMock, assert) { fetchMock.postOnce(url(settings, '/testImpressions/count'), (url, opts) => { const data = JSON.parse(opts.body); - assert.equal(data.pf.length, 1, 'We should generate impression count for one feature.'); + assert.equal(data.pf.length, 2, 'We should generate impression count for 2 features.'); // finding these validate the feature names collection too - const dependencyChildImpr = data.pf.filter(e => e.f === 'hierarchical_splits_test')[0]; - const alwaysOnWithConfigImpr = data.pf.filter(e => e.f === 'split_with_config')[0]; - const notExistentSplitImpr = data.pf.filter(e => e.f === 'not_existent_split')[0]; - - assert.equal(dependencyChildImpr.rc, 1); - assert.equal(typeof dependencyChildImpr.m, 'number'); - assert.equal(dependencyChildImpr.m, truncatedTimeFrame); - assert.equal(alwaysOnWithConfigImpr.rc, 3); - assert.equal(typeof alwaysOnWithConfigImpr.m, 'number'); - assert.equal(alwaysOnWithConfigImpr.m, truncatedTimeFrame); - assert.equal(notExistentSplitImpr.rc, 1); - assert.equal(typeof notExistentSplitImpr.m, 'number'); - assert.equal(notExistentSplitImpr.m, truncatedTimeFrame); + const splitWithConfigImpr = data.pf.filter(e => e.f === 'split_with_config')[0]; + const alwaysOnWithTrackImpressionsFalse = data.pf.filter(e => e.f === 'always_on_track_impressions_false')[0]; + + assert.equal(splitWithConfigImpr.rc, 1); + assert.equal(typeof splitWithConfigImpr.m, 'number'); + assert.equal(splitWithConfigImpr.m, truncatedTimeFrame); + assert.equal(alwaysOnWithTrackImpressionsFalse.rc, 1); + assert.equal(typeof alwaysOnWithTrackImpressionsFalse.m, 'number'); + assert.equal(alwaysOnWithTrackImpressionsFalse.m, truncatedTimeFrame); + + return 200; + }); + + fetchMock.postOnce(url(settings, '/v1/keys/ss'), (url, opts) => { + assert.deepEqual(JSON.parse(opts.body), { + keys: [{ f: 'always_on_track_impressions_false', ks: ['other_key'] }] + }, 'We should only track unique keys for features flags with track impressions disabled.'); return 200; }); @@ -147,5 +153,8 @@ export default async function (key, fetchMock, assert) { client.getTreatmentWithConfig({ matchingKey: key, bucketingKey: 'test_buck_key' }, 'split_with_config'); client.getTreatmentWithConfig({ matchingKey: 'different', bucketingKey: 'test_buck_key' }, 'split_with_config'); + // Impression should not be tracked + assert.equal(client.getTreatment('other_key', 'always_on_track_impressions_false'), 'on'); + evaluationsEnd = Date.now(); } diff --git a/src/__tests__/nodeSuites/telemetry.spec.js b/src/__tests__/nodeSuites/telemetry.spec.js index a6a6bb66f..751e762e2 100644 --- a/src/__tests__/nodeSuites/telemetry.spec.js +++ b/src/__tests__/nodeSuites/telemetry.spec.js @@ -66,7 +66,7 @@ export default async function telemetryNodejsSuite(key, fetchMock, assert) { // @TODO check if iDe value is correct assert.deepEqual(data, { - mE: {}, hE: { sp: { 500: 1 } }, tR: 0, aR: 0, iQ: 4, iDe: 1, iDr: 0, spC: 32, seC: 3, skC: 3, eQ: 1, eD: 0, sE: [], t: [], ufs: {} + mE: {}, hE: { sp: { 500: 1 } }, tR: 0, aR: 0, iQ: 4, iDe: 1, iDr: 0, spC: 33, seC: 3, skC: 3, eQ: 1, eD: 0, sE: [], t: [], ufs: {} }, 'metrics/usage JSON payload should be the expected'); finish.next(); @@ -85,7 +85,7 @@ export default async function telemetryNodejsSuite(key, fetchMock, assert) { // @TODO check if iDe value is correct assert.deepEqual(data, { mL: {}, mE: {}, hE: {}, hL: {}, // errors and latencies were popped - tR: 0, aR: 0, iQ: 4, iDe: 1, iDr: 0, spC: 32, seC: 3, skC: 3, eQ: 1, eD: 0, sE: [], t: [], ufs: {} + tR: 0, aR: 0, iQ: 4, iDe: 1, iDr: 0, spC: 33, seC: 3, skC: 3, eQ: 1, eD: 0, sE: [], t: [], ufs: {} }, '2nd metrics/usage JSON payload should be the expected'); return 200; }); From 85578eb0263b23f7cebea9ecea5d96978c8d840e Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 10 Dec 2024 18:43:29 -0300 Subject: [PATCH 02/11] Update redis, listener and manager tests --- .../impressions-listener.spec.js | 8 ++- src/__tests__/browserSuites/manager.spec.js | 3 +- src/__tests__/consumer/node_redis.spec.js | 52 ++++++++++++------- src/__tests__/mocks/redis-commands.txt | 3 +- .../nodeSuites/impressions-listener.spec.js | 5 +- src/__tests__/nodeSuites/manager.spec.js | 3 +- 6 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/__tests__/browserSuites/impressions-listener.spec.js b/src/__tests__/browserSuites/impressions-listener.spec.js index 299dacaad..ca47995c2 100644 --- a/src/__tests__/browserSuites/impressions-listener.spec.js +++ b/src/__tests__/browserSuites/impressions-listener.spec.js @@ -57,17 +57,21 @@ export default function (assert) { keyName: 'marcio@split.io', treatment: 'no', bucketingKey: 'impr_bucketing_2', - label: 'default rule' + label: 'default rule', + pt: undefined }; assert.equal(listener.logImpression.callCount, 4, 'Impression listener logImpression method should be called after we call client.getTreatment, once per each impression generated.'); - assert.true(listener.logImpression.getCall(0).calledWithMatch({ + assert.true(listener.logImpression.getCall(0).calledWithExactly({ impression: { feature: 'hierarchical_splits_test', keyName: 'nicolas@split.io', treatment: 'on', + time: listener.logImpression.getCall(0).args[0].impression.time, bucketingKey: undefined, label: 'expected label', + changeNumber: 2828282828, + pt: undefined }, attributes: undefined, ...metaData diff --git a/src/__tests__/browserSuites/manager.spec.js b/src/__tests__/browserSuites/manager.spec.js index a5a09ff6d..c31aebeeb 100644 --- a/src/__tests__/browserSuites/manager.spec.js +++ b/src/__tests__/browserSuites/manager.spec.js @@ -41,7 +41,8 @@ export default async function (settings, fetchMock, assert) { 'treatments': map(mockSplits.splits[index].conditions[0].partitions, partition => partition.treatment), 'configs': mockSplits.splits[index].configurations || {}, 'sets': mockSplits.splits[index].sets || [], - 'defaultTreatment': mockSplits.splits[index].defaultTreatment + 'defaultTreatment': mockSplits.splits[index].defaultTreatment, + 'trackImpressions': true }); assert.equal(manager.split('non_existent'), null, 'Trying to get a manager.split() of a Split that does not exist returns null.'); diff --git a/src/__tests__/consumer/node_redis.spec.js b/src/__tests__/consumer/node_redis.spec.js index 8092f1910..081c1dcdb 100644 --- a/src/__tests__/consumer/node_redis.spec.js +++ b/src/__tests__/consumer/node_redis.spec.js @@ -61,7 +61,7 @@ const expectedImpressionCount = [ ]; const expectedSplitName = 'hierarchical_splits_testing_on'; -const expectedSplitView = { name: 'hierarchical_splits_testing_on', trafficType: 'user', killed: false, changeNumber: 1487277320548, treatments: ['on', 'off'], configs: {}, sets: [], defaultTreatment: 'off' }; +const expectedSplitView = { name: 'hierarchical_splits_testing_on', trafficType: 'user', killed: false, changeNumber: 1487277320548, treatments: ['on', 'off'], configs: {}, sets: [], defaultTreatment: 'off', trackImpressions: true }; const MOCKS = { '': 'redis-commands', @@ -150,11 +150,12 @@ tape('Node.js Redis', function (t) { assert.equal(await client.getTreatment('UT_Segment_member', 'always-on'), 'on', 'Evaluations using Redis storage should be correct.'); - // Below splits were added manually to the redis_mock.json file. + // Below feature flags were added manually to the redis_mock.json file. // They are all_keys (always evaluate to on) which depend from always-on split. the _on/off is what treatment they are expecting there. assert.equal(await client.getTreatment('UT_Segment_member', 'hierarchical_splits_testing_on'), 'on', 'Evaluations using Redis storage should be correct.'); assert.equal(await client.getTreatment('UT_Segment_member', 'hierarchical_splits_testing_off'), 'off', 'Evaluations using Redis storage should be correct.'); assert.equal(await client.getTreatment('UT_Segment_member', 'hierarchical_splits_testing_on_negated'), 'off', 'Evaluations using Redis storage should be correct.'); + assert.equal(await client.getTreatment('other_key', 'always-on-track-impressions-false'), 'on', 'Evaluations using Redis storage should be correct.'); assert.equal(typeof client.track().then, 'function', 'Track calls should always return a promise on Redis mode, even when parameters are incorrect.'); @@ -163,35 +164,46 @@ tape('Node.js Redis', function (t) { // Manager methods const splitNames = await manager.names(); - assert.equal(splitNames.length, 25, 'manager `names` method returns the list of split names asynchronously'); + assert.equal(splitNames.length, 26, 'manager `names` method returns the list of split names asynchronously'); assert.equal(splitNames.indexOf(expectedSplitName) > -1, true, 'list of split names should contain expected splits'); assert.deepEqual(await manager.split(expectedSplitName), expectedSplitView, 'manager `split` method returns the split view of the given split name asynchronously'); const splitViews = await manager.splits(); - assert.equal(splitViews.length, 25, 'manager `splits` method returns the list of split views asynchronously'); + assert.equal(splitViews.length, 26, 'manager `splits` method returns the list of split views asynchronously'); assert.deepEqual(splitViews.find(splitView => splitView.name === expectedSplitName), expectedSplitView, 'manager `split` method returns the split view of the given split name asynchronously'); await client.ready(); // promise already resolved await client.destroy(); - // Validate stored impressions and events - exec(`echo "LLEN ${config.storage.prefix}.SPLITIO.impressions \n LLEN ${config.storage.prefix}.SPLITIO.events" | redis-cli -p ${redisPort}`, (error, stdout) => { - if (error) assert.fail('Redis server should be reachable'); + // Validate Impression Counts and Unique Keys for 'always-on-track-impressions-false' + exec(`echo "HGETALL ${config.storage.prefix}.SPLITIO.impressions.count" | redis-cli -p ${redisPort}`, async (error, stdout) => { + const trackedImpressionCounts = stdout.split('\n').filter(line => line !== ''); + assert.deepEqual(trackedImpressionCounts, [`always-on-track-impressions-false::${truncateTimeFrame(timeFrame)}`, '1',], 'Tracked impression counts should be stored in Redis TODO'); - const trackedImpressionsAndEvents = stdout.split('\n').filter(line => line !== '').map(line => parseInt(line)); - assert.deepEqual(trackedImpressionsAndEvents, [TOTAL_RAW_IMPRESSIONS, TOTAL_EVENTS], 'Tracked impressions and events should be stored in Redis'); + exec(`echo "LRANGE ${config.storage.prefix}.SPLITIO.uniquekeys 0 20" | redis-cli -p ${redisPort}`, async (error, stdout) => { + const storedUniqueKeys = stdout.split('\n').filter(line => line !== '').map(JSON.parse); + assert.deepEqual(storedUniqueKeys, [{ 'f': 'always-on-track-impressions-false', 'ks': ['other_key'] }], 'Unique keys should be stored in Redis TODO'); - // Validate stored telemetry - exec(`echo "HLEN ${config.storage.prefix}.SPLITIO.telemetry.latencies \n HLEN ${config.storage.prefix}.SPLITIO.telemetry.exceptions \n HGET ${config.storage.prefix}.SPLITIO.telemetry.init nodejs-${version}/${HOSTNAME_VALUE}/${IP_VALUE}" | redis-cli -p ${redisPort}`, (error, stdout) => { - if (error) assert.fail('Redis server should be reachable'); + // Validate stored impressions and events + exec(`echo "LLEN ${config.storage.prefix}.SPLITIO.impressions \n LLEN ${config.storage.prefix}.SPLITIO.events" | redis-cli -p ${redisPort}`, (error, stdout) => { + if (error) assert.fail('Redis server should be reachable'); - const [latencies, exceptions, configValue] = stdout.split('\n').filter(line => line !== '').map(JSON.parse); + const trackedImpressionsAndEvents = stdout.split('\n').filter(line => line !== '').map(line => parseInt(line)); + assert.deepEqual(trackedImpressionsAndEvents, [TOTAL_RAW_IMPRESSIONS, TOTAL_EVENTS], 'Tracked impressions and events should be stored in Redis'); - assert.true(latencies > 0, 'There are stored latencies'); - assert.true(exceptions === 0, 'There aren\'t stored exceptions'); - assert.deepEqual(configValue, { oM: 1, st: 'redis', aF: 1, rF: 0 }, 'There is stored telemetry config'); + // Validate stored telemetry + exec(`echo "HLEN ${config.storage.prefix}.SPLITIO.telemetry.latencies \n HLEN ${config.storage.prefix}.SPLITIO.telemetry.exceptions \n HGET ${config.storage.prefix}.SPLITIO.telemetry.init 'nodejs-${version}/${HOSTNAME_VALUE}/${IP_VALUE}'" | redis-cli -p ${redisPort}`, (error, stdout) => { + if (error) assert.fail('Redis server should be reachable'); + + const [latencies, exceptions, configValue] = stdout.split('\n').filter(line => line !== '').map(JSON.parse); - // close server connection - server.close().then(assert.end); + assert.true(latencies > 0, 'There are stored latencies'); + assert.true(exceptions === 0, 'There aren\'t stored exceptions'); + assert.deepEqual(configValue, { oM: 1, st: 'redis', aF: 1, rF: 0 }, 'There is stored telemetry config'); + + // close server connection + server.close().then(assert.end); + }); + }); }); }); }); @@ -304,7 +316,7 @@ tape('Node.js Redis', function (t) { assert.deepEqual(trackedImpressionsAndEvents, [TOTAL_RAW_IMPRESSIONS - DEDUPED_IMPRESSIONS, TOTAL_EVENTS], 'Tracked impressions and events should be stored in Redis'); // Validate stored telemetry - exec(`echo "HLEN ${config.storage.prefix}.SPLITIO.telemetry.latencies \n HLEN ${config.storage.prefix}.SPLITIO.telemetry.exceptions \n HGET ${config.storage.prefix}.SPLITIO.telemetry.init nodejs-${version}/${HOSTNAME_VALUE}/${IP_VALUE}" | redis-cli -p ${redisPort}`, (error, stdout) => { + exec(`echo "HLEN ${config.storage.prefix}.SPLITIO.telemetry.latencies \n HLEN ${config.storage.prefix}.SPLITIO.telemetry.exceptions \n HGET ${config.storage.prefix}.SPLITIO.telemetry.init 'nodejs-${version}/${HOSTNAME_VALUE}/${IP_VALUE}'" | redis-cli -p ${redisPort}`, (error, stdout) => { if (error) assert.fail('Redis server should be reachable'); const [latencies, exceptions, configValue] = stdout.split('\n').filter(line => line !== '').map(JSON.parse); @@ -406,7 +418,7 @@ tape('Node.js Redis', function (t) { assert.deepEqual(trackedImpressionsAndEvents, [0, TOTAL_EVENTS], 'No impressions are stored in Redis in NONE impressions mode'); // Validate stored telemetry - exec(`echo "HLEN ${config.storage.prefix}.SPLITIO.telemetry.latencies \n HLEN ${config.storage.prefix}.SPLITIO.telemetry.exceptions \n HGET ${config.storage.prefix}.SPLITIO.telemetry.init nodejs-${version}/${HOSTNAME_VALUE}/${IP_VALUE}" | redis-cli -p ${redisPort}`, (error, stdout) => { + exec(`echo "HLEN ${config.storage.prefix}.SPLITIO.telemetry.latencies \n HLEN ${config.storage.prefix}.SPLITIO.telemetry.exceptions \n HGET ${config.storage.prefix}.SPLITIO.telemetry.init 'nodejs-${version}/${HOSTNAME_VALUE}/${IP_VALUE}'" | redis-cli -p ${redisPort}`, (error, stdout) => { if (error) assert.fail('Redis server should be reachable'); const [latencies, exceptions, configValue] = stdout.split('\n').filter(line => line !== '').map(JSON.parse); diff --git a/src/__tests__/mocks/redis-commands.txt b/src/__tests__/mocks/redis-commands.txt index 2e5daae42..a1e68b7e8 100644 --- a/src/__tests__/mocks/redis-commands.txt +++ b/src/__tests__/mocks/redis-commands.txt @@ -21,7 +21,7 @@ SET 'REDIS_NODE_UT.SPLITIO.split.always-off' '{"changeNumber":1491519038393, SET 'REDIS_NODE_UT.SPLITIO.split.always-on' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"always-on","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.always-o.n-with-config' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"always-o.n-with-config","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"o.n","size":100},{"treatment":"off","size":0}],"label":"in segment all"}],"configurations":{"o.n":"{\"color\":\"brown\"}"}}' SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_off' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_off","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["off"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' -SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_on' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_on","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["on"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' +SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_on' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_on","trackImpressions":true,"seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["on"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_on_negated' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_on","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":true,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["on"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.labels' '{"changeNumber":1492023661334,"trafficTypeName":"user","name":"labels","seed":-1240661267,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"demo"},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":"n"},"matcherType":"EQUAL_TO","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"NUMBER","value":123},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment all and in segment demo and n = 123"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.nico_not' '{"changeNumber":1489412422181,"trafficTypeName":"user","name":"nico_not","seed":-788702424,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"qa"},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment qa"}]}' @@ -39,3 +39,4 @@ SET 'REDIS_NODE_UT.SPLITIO.split.testing_traffic_type' '{"changeNumber":1489 SET 'REDIS_NODE_UT.SPLITIO.split.testing_traffic_types' '{"changeNumber":1490974465415,"trafficTypeName":"machine","name":"testing_traffic_types","seed":475616886,"status":"ACTIVE","killed":false,"defaultTreatment":"on","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"","attribute":""},"matcherType":"WHITELIST","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":["sarasa"]},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100}],"label":"whitelisted"},{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"","attribute":""},"matcherType":"WHITELIST","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":["excluded"]},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"off","size":100}],"label":"whitelisted"},{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"machine","attribute":""},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"testing_traffic_type"},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment all and in segment testing_traffic_type"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.traffic_allocation_testing' '{"changeNumber":1490974123779,"trafficTypeName":"user","name":"traffic_allocation_testing","seed":1716284102,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.splits.till' 1492723024413 +SET 'REDIS_NODE_UT.SPLITIO.split.always-on-track-impressions-false' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"always-on-track-impressions-false","trackImpressions":false,"seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' diff --git a/src/__tests__/nodeSuites/impressions-listener.spec.js b/src/__tests__/nodeSuites/impressions-listener.spec.js index 7fda529f4..984c36d1e 100644 --- a/src/__tests__/nodeSuites/impressions-listener.spec.js +++ b/src/__tests__/nodeSuites/impressions-listener.spec.js @@ -46,13 +46,16 @@ export default function (assert) { setTimeout(() => { assert.true(listener.logImpression.callCount, 4, 'Impression listener logImpression method should be called after we call client.getTreatment, once per each impression generated.'); - assert.true(listener.logImpression.getCall(0).calledWithMatch({ + assert.true(listener.logImpression.getCall(0).calledWithExactly({ impression: { feature: 'hierarchical_splits_test', keyName: 'nicolas@split.io', treatment: 'on', + time: listener.logImpression.getCall(0).args[0].impression.time, bucketingKey: undefined, label: 'expected label', + changeNumber: 2828282828, + pt: undefined }, attributes: undefined, ...metaData diff --git a/src/__tests__/nodeSuites/manager.spec.js b/src/__tests__/nodeSuites/manager.spec.js index 00a707dc9..82588949c 100644 --- a/src/__tests__/nodeSuites/manager.spec.js +++ b/src/__tests__/nodeSuites/manager.spec.js @@ -40,7 +40,8 @@ export default async function (settings, fetchMock, assert) { 'treatments': map(mockSplits.splits[index].conditions[0].partitions, partition => partition.treatment), 'configs': mockSplits.splits[index].configurations || {}, 'sets': mockSplits.splits[index].sets || [], - 'defaultTreatment': mockSplits.splits[index].defaultTreatment + 'defaultTreatment': mockSplits.splits[index].defaultTreatment, + 'trackImpressions': true }); assert.equal(manager.split('non_existent'), null, 'Trying to get a manager.split() of a Split that does not exist returns null.'); From d2575628f78448266b1e7b4e2c5ac876652d760e Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 11 Dec 2024 14:40:33 -0300 Subject: [PATCH 03/11] Upgrade JS commons --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index a6959f97e..11769016b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "11.0.3", "license": "Apache-2.0", "dependencies": { - "@splitsoftware/splitio-commons": "2.0.2", + "@splitsoftware/splitio-commons": "2.0.3-rc.0", "bloom-filters": "^3.0.4", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -351,9 +351,9 @@ "dev": true }, "node_modules/@splitsoftware/splitio-commons": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.2.tgz", - "integrity": "sha512-r2m3kwWnSuROT+7zTzhWBrM0DMRBGJNQcTyvXw8zLPPmBs/PnmAnxCy7uRpfMHOGbP9Q3Iju0bU/H5dG8svyiw==", + "version": "2.0.3-rc.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.3-rc.0.tgz", + "integrity": "sha512-18Zpm5rXH+Cn3lR4K6Np9os3XK6cH9KUsM7a3MOdBVoVMZPr6PzVuIf4Eet6vbVDGKbk9h0aYrAA2Tm7DU4dWg==", "dependencies": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" @@ -7537,9 +7537,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.2.tgz", - "integrity": "sha512-r2m3kwWnSuROT+7zTzhWBrM0DMRBGJNQcTyvXw8zLPPmBs/PnmAnxCy7uRpfMHOGbP9Q3Iju0bU/H5dG8svyiw==", + "version": "2.0.3-rc.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.3-rc.0.tgz", + "integrity": "sha512-18Zpm5rXH+Cn3lR4K6Np9os3XK6cH9KUsM7a3MOdBVoVMZPr6PzVuIf4Eet6vbVDGKbk9h0aYrAA2Tm7DU4dWg==", "requires": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" diff --git a/package.json b/package.json index d62fd35b1..a1409bafa 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "node": ">=14.0.0" }, "dependencies": { - "@splitsoftware/splitio-commons": "2.0.2", + "@splitsoftware/splitio-commons": "2.0.3-rc.0", "bloom-filters": "^3.0.4", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", From f4c2de6ac93283a8b9b5bc93570b69e80904abf2 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 11 Dec 2024 16:20:55 -0300 Subject: [PATCH 04/11] Update ts-test --- src/__tests__/nodeSuites/lazy-init.spec.js | 24 ++++++++++++++++++++-- ts-tests/index.ts | 3 ++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/__tests__/nodeSuites/lazy-init.spec.js b/src/__tests__/nodeSuites/lazy-init.spec.js index bee1efbc9..9cb5f9735 100644 --- a/src/__tests__/nodeSuites/lazy-init.spec.js +++ b/src/__tests__/nodeSuites/lazy-init.spec.js @@ -33,13 +33,23 @@ export default function (settings, fetchMock, t) { fetchMock.getOnce('https://not-called/api/splitChanges?s=1.1&since=1457552620999', { status: 200, body: { splits: [], since: 1457552620999, till: 1457552620999 } }); fetchMock.postOnce('https://not-called/api/testImpressions/bulk', 200); fetchMock.postOnce('https://not-called/api/events/bulk', 200); + fetchMock.get('https://not-called/api/v2/auth?s=1.1', 200); // Validate that init and destroy are idempotent for (let i = 0; i < 3; i++) { splitio.init(); splitio.init(); splitio.destroy(); splitio.destroy(); } splitio.init(); await splitio.client().ready(); - assert.true(splitio.client().__getStatus().isReady, 'Split SDK is ready'); + + assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: false, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + + await splitio.destroy(); + assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: false, isTimedout: false, hasTimedout: false, isDestroyed: true, isOperational: false, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + + splitio.init(); + + assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: false, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + await splitio.destroy(); assert.end(); @@ -81,13 +91,23 @@ export default function (settings, fetchMock, t) { fetchMock.getOnce('https://not-called/api/memberships/other-user', { status: 200, body: {} }); fetchMock.postOnce('https://not-called/api/testImpressions/bulk', 200); fetchMock.postOnce('https://not-called/api/events/bulk', 200); + fetchMock.get('https://not-called/api/v2/auth?s=1.2&users=user-99', 200); // Validate that init and destroy are idempotent for (let i = 0; i < 3; i++) { splitio.init(); splitio.init(); splitio.destroy(); splitio.destroy(); } splitio.init(); await splitio.client().ready(); - assert.true(splitio.client().__getStatus().isReady, 'Split SDK is ready'); + + assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: false, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + + await splitio.destroy(); + assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: false, isTimedout: false, hasTimedout: false, isDestroyed: true, isOperational: false, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + + splitio.init(); + + assert.deepEqual(splitio.client().__getStatus(), { isReady: true, isReadyFromCache: false, isTimedout: false, hasTimedout: false, isDestroyed: false, isOperational: true, lastUpdate: splitio.client().__getStatus().lastUpdate }, 'Status'); + await splitio.destroy(); assert.end(); diff --git a/ts-tests/index.ts b/ts-tests/index.ts index 9e9a2c32a..5f52bdf8c 100644 --- a/ts-tests/index.ts +++ b/ts-tests/index.ts @@ -134,7 +134,8 @@ splitView = { off: '{"dimensions":"{\"height\":20,\"width\":40}"}' }, sets: ['set_a', 'set_b'], - defaultTreatment: 'off' + defaultTreatment: 'off', + trackImpressions: true }; splitViews = [splitView]; From c04606134b828fb67d353b529115389a043d2582 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 11 Dec 2024 16:39:02 -0300 Subject: [PATCH 05/11] Fix localhost mode tests --- src/__tests__/offline/browser.spec.js | 6 +++--- src/__tests__/offline/node.spec.js | 24 ++++++++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/__tests__/offline/browser.spec.js b/src/__tests__/offline/browser.spec.js index bce2020eb..81bc3efd3 100644 --- a/src/__tests__/offline/browser.spec.js +++ b/src/__tests__/offline/browser.spec.js @@ -168,10 +168,10 @@ tape('Browser offline mode', function (assert) { // Manager tests const expectedSplitView1 = { - name: 'testing_split', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['on'], configs: {}, defaultTreatment: 'control', sets: [] + name: 'testing_split', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['on'], configs: {}, defaultTreatment: 'control', sets: [], trackImpressions: true }; const expectedSplitView2 = { - name: 'testing_split_with_config', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['off'], configs: { off: '{ "color": "blue" }' }, defaultTreatment: 'control', sets: [] + name: 'testing_split_with_config', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['off'], configs: { off: '{ "color": "blue" }' }, defaultTreatment: 'control', sets: [], trackImpressions: true }; assert.deepEqual(manager.names(), ['testing_split', 'testing_split_with_config']); assert.deepEqual(manager.split('testing_split'), expectedSplitView1); @@ -282,7 +282,7 @@ tape('Browser offline mode', function (assert) { // Manager tests const expectedSplitView3 = { - name: 'testing_split_with_config', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['nope'], configs: {}, defaultTreatment: 'control', sets: [] + name: 'testing_split_with_config', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['nope'], configs: {}, defaultTreatment: 'control', sets: [], trackImpressions: true }; assert.deepEqual(manager.names(), ['testing_split', 'testing_split_2', 'testing_split_3', 'testing_split_with_config']); assert.deepEqual(manager.split('testing_split'), expectedSplitView1); diff --git a/src/__tests__/offline/node.spec.js b/src/__tests__/offline/node.spec.js index ef12324b2..3e3166b6c 100644 --- a/src/__tests__/offline/node.spec.js +++ b/src/__tests__/offline/node.spec.js @@ -250,17 +250,17 @@ function ManagerDotSplitTests(assert) { const expectedView1 = { name: 'testing_split', changeNumber: 0, killed: false, trafficType: 'localhost', treatments: ['on'], configs: {}, defaultTreatment: 'control', - sets: [] + sets: [], trackImpressions: true }; const expectedView2 = { name: 'testing_split2', changeNumber: 0, killed: false, trafficType: 'localhost', treatments: ['off'], configs: {}, defaultTreatment: 'control', - sets: [] + sets: [], trackImpressions: true }; const expectedView3 = { name: 'testing_split3', changeNumber: 0, killed: false, trafficType: 'localhost', treatments: ['custom_treatment'], configs: {}, defaultTreatment: 'control', - sets: [] + sets: [], trackImpressions: true }; assert.deepEqual(manager.split('testing_split'), expectedView1); @@ -294,7 +294,8 @@ function ManagerDotYamlTests(mockFileName, assert) { treatments: ['on'], configs: {}, sets: [], - defaultTreatment: 'control' + defaultTreatment: 'control', + trackImpressions: true }; const expectedView2 = { name: 'testing_split_only_wl', @@ -304,7 +305,8 @@ function ManagerDotYamlTests(mockFileName, assert) { treatments: ['whitelisted'], configs: {}, sets: [], - defaultTreatment: 'control' + defaultTreatment: 'control', + trackImpressions: true }; const expectedView3 = { name: 'testing_split_with_wl', @@ -317,7 +319,8 @@ function ManagerDotYamlTests(mockFileName, assert) { multi_key_wl: '{"color": "brown"}' }, sets: [], - defaultTreatment: 'control' + defaultTreatment: 'control', + trackImpressions: true }; const expectedView4 = { name: 'testing_split_off_with_config', @@ -329,7 +332,8 @@ function ManagerDotYamlTests(mockFileName, assert) { off: '{"color": "green"}' }, sets: [], - defaultTreatment: 'control' + defaultTreatment: 'control', + trackImpressions: true }; assert.deepEqual(manager.split('testing_split_on'), expectedView1); @@ -410,15 +414,15 @@ function MultipleInstancesTests(assert) { const expectedView1 = { name: 'testing_split', changeNumber: 0, killed: false, trafficType: 'localhost', - treatments: ['on'], configs: {}, sets: [] + treatments: ['on'], configs: {}, sets: [], trackImpressions: true }; const expectedView2 = { name: 'testing_split2', changeNumber: 0, killed: false, trafficType: 'localhost', - treatments: ['off'], configs: {}, sets: [] + treatments: ['off'], configs: {}, sets: [], trackImpressions: true }; const expectedView3 = { name: 'testing_split3', changeNumber: 0, killed: false, trafficType: 'localhost', - treatments: ['custom_treatment'], configs: {}, sets: [] + treatments: ['custom_treatment'], configs: {}, sets: [], trackImpressions: true }; assert.deepEqual(manager.split('testing_split'), expectedView1); From 36372f08ef069e0554063a9149f1633e754a14c0 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 15 Jan 2025 11:06:44 -0300 Subject: [PATCH 06/11] Update changelog entry --- CHANGES.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index dcc52ef76..a4a7e4fc6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +11.1.0 (January XX, 2025) + - Added support for the new impressions tracking toggle available on feature flags, both respecting the setting and including the new field being returned on `SplitView` type objects. Read more in our docs. + 11.0.4 (January 9, 2025) - Bugfixing - Updated @splitsoftware/splitio-commons package to version 2.0.3, which properly handles rejected promises when using targeting rules with segment matchers in consumer modes (e.g., Redis and Pluggable storages). From dd4a46b9e0a25e5f0197c48c1357a96afe9afd6c Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 17 Jan 2025 17:09:34 -0300 Subject: [PATCH 07/11] Fix tests --- package-lock.json | 14 ++++++------- package.json | 2 +- .../browserSuites/impressions.spec.js | 2 +- src/__tests__/browserSuites/manager.spec.js | 2 +- src/__tests__/consumer/node_redis.spec.js | 2 +- src/__tests__/mocks/redis-commands.txt | 4 ++-- .../mocks/splitchanges.since.-1.json | 6 +++--- src/__tests__/nodeSuites/impressions.spec.js | 2 +- src/__tests__/nodeSuites/manager.spec.js | 2 +- src/__tests__/offline/browser.spec.js | 6 +++--- src/__tests__/offline/node.spec.js | 20 +++++++++---------- ts-tests/index.ts | 2 +- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 39dcad689..7cdd1431a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "11.0.4", "license": "Apache-2.0", "dependencies": { - "@splitsoftware/splitio-commons": "2.0.3-rc.0", + "@splitsoftware/splitio-commons": "2.1.0", "bloom-filters": "^3.0.4", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", @@ -351,9 +351,9 @@ "dev": true }, "node_modules/@splitsoftware/splitio-commons": { - "version": "2.0.3-rc.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.3-rc.0.tgz", - "integrity": "sha512-18Zpm5rXH+Cn3lR4K6Np9os3XK6cH9KUsM7a3MOdBVoVMZPr6PzVuIf4Eet6vbVDGKbk9h0aYrAA2Tm7DU4dWg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.1.0.tgz", + "integrity": "sha512-7SJRBia0Pi72s76drH8kG2cVnCqkjMHMJQWJSFnG+rE/UOx9AROmuviOkY6tv6qYPJFqFQQGHGX6lXjxZhYzkw==", "dependencies": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" @@ -7537,9 +7537,9 @@ "dev": true }, "@splitsoftware/splitio-commons": { - "version": "2.0.3-rc.0", - "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.0.3-rc.0.tgz", - "integrity": "sha512-18Zpm5rXH+Cn3lR4K6Np9os3XK6cH9KUsM7a3MOdBVoVMZPr6PzVuIf4Eet6vbVDGKbk9h0aYrAA2Tm7DU4dWg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.1.0.tgz", + "integrity": "sha512-7SJRBia0Pi72s76drH8kG2cVnCqkjMHMJQWJSFnG+rE/UOx9AROmuviOkY6tv6qYPJFqFQQGHGX6lXjxZhYzkw==", "requires": { "@types/ioredis": "^4.28.0", "tslib": "^2.3.1" diff --git a/package.json b/package.json index 5c8b74924..579d960fd 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "node": ">=14.0.0" }, "dependencies": { - "@splitsoftware/splitio-commons": "2.0.3-rc.0", + "@splitsoftware/splitio-commons": "2.1.0", "bloom-filters": "^3.0.4", "ioredis": "^4.28.0", "js-yaml": "^3.13.1", diff --git a/src/__tests__/browserSuites/impressions.spec.js b/src/__tests__/browserSuites/impressions.spec.js index 7c72df87d..33e60106a 100644 --- a/src/__tests__/browserSuites/impressions.spec.js +++ b/src/__tests__/browserSuites/impressions.spec.js @@ -49,7 +49,7 @@ export default function (fetchMock, assert) { const assertPayload = req => { const resp = JSON.parse(req.body); - assert.equal(resp.length, 2, 'We performed evaluations for 3 features, but one with `trackImpressions` false, so we should have 2 items total'); + assert.equal(resp.length, 2, 'We performed evaluations for 3 features, but one with `impressionsDisabled` true, so we should have 2 items total'); const dependencyChildImpr = resp.filter(e => e.f === 'hierarchical_splits_test')[0]; const splitWithConfigImpr = resp.filter(e => e.f === 'split_with_config')[0]; diff --git a/src/__tests__/browserSuites/manager.spec.js b/src/__tests__/browserSuites/manager.spec.js index c31aebeeb..9c64cc52c 100644 --- a/src/__tests__/browserSuites/manager.spec.js +++ b/src/__tests__/browserSuites/manager.spec.js @@ -42,7 +42,7 @@ export default async function (settings, fetchMock, assert) { 'configs': mockSplits.splits[index].configurations || {}, 'sets': mockSplits.splits[index].sets || [], 'defaultTreatment': mockSplits.splits[index].defaultTreatment, - 'trackImpressions': true + 'impressionsDisabled': false }); assert.equal(manager.split('non_existent'), null, 'Trying to get a manager.split() of a Split that does not exist returns null.'); diff --git a/src/__tests__/consumer/node_redis.spec.js b/src/__tests__/consumer/node_redis.spec.js index 081c1dcdb..25f1809fb 100644 --- a/src/__tests__/consumer/node_redis.spec.js +++ b/src/__tests__/consumer/node_redis.spec.js @@ -61,7 +61,7 @@ const expectedImpressionCount = [ ]; const expectedSplitName = 'hierarchical_splits_testing_on'; -const expectedSplitView = { name: 'hierarchical_splits_testing_on', trafficType: 'user', killed: false, changeNumber: 1487277320548, treatments: ['on', 'off'], configs: {}, sets: [], defaultTreatment: 'off', trackImpressions: true }; +const expectedSplitView = { name: 'hierarchical_splits_testing_on', trafficType: 'user', killed: false, changeNumber: 1487277320548, treatments: ['on', 'off'], configs: {}, sets: [], defaultTreatment: 'off', impressionsDisabled: false }; const MOCKS = { '': 'redis-commands', diff --git a/src/__tests__/mocks/redis-commands.txt b/src/__tests__/mocks/redis-commands.txt index a1e68b7e8..9c87b56e0 100644 --- a/src/__tests__/mocks/redis-commands.txt +++ b/src/__tests__/mocks/redis-commands.txt @@ -21,7 +21,7 @@ SET 'REDIS_NODE_UT.SPLITIO.split.always-off' '{"changeNumber":1491519038393, SET 'REDIS_NODE_UT.SPLITIO.split.always-on' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"always-on","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.always-o.n-with-config' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"always-o.n-with-config","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"o.n","size":100},{"treatment":"off","size":0}],"label":"in segment all"}],"configurations":{"o.n":"{\"color\":\"brown\"}"}}' SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_off' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_off","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["off"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' -SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_on' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_on","trackImpressions":true,"seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["on"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' +SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_on' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_on","impressionsDisabled":false,"seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["on"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_on_negated' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_on","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":true,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["on"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.labels' '{"changeNumber":1492023661334,"trafficTypeName":"user","name":"labels","seed":-1240661267,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"demo"},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":"n"},"matcherType":"EQUAL_TO","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"NUMBER","value":123},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment all and in segment demo and n = 123"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.nico_not' '{"changeNumber":1489412422181,"trafficTypeName":"user","name":"nico_not","seed":-788702424,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"qa"},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment qa"}]}' @@ -39,4 +39,4 @@ SET 'REDIS_NODE_UT.SPLITIO.split.testing_traffic_type' '{"changeNumber":1489 SET 'REDIS_NODE_UT.SPLITIO.split.testing_traffic_types' '{"changeNumber":1490974465415,"trafficTypeName":"machine","name":"testing_traffic_types","seed":475616886,"status":"ACTIVE","killed":false,"defaultTreatment":"on","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"","attribute":""},"matcherType":"WHITELIST","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":["sarasa"]},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100}],"label":"whitelisted"},{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"","attribute":""},"matcherType":"WHITELIST","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":["excluded"]},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"off","size":100}],"label":"whitelisted"},{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"machine","attribute":""},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"testing_traffic_type"},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment all and in segment testing_traffic_type"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.traffic_allocation_testing' '{"changeNumber":1490974123779,"trafficTypeName":"user","name":"traffic_allocation_testing","seed":1716284102,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.splits.till' 1492723024413 -SET 'REDIS_NODE_UT.SPLITIO.split.always-on-track-impressions-false' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"always-on-track-impressions-false","trackImpressions":false,"seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' +SET 'REDIS_NODE_UT.SPLITIO.split.always-on-track-impressions-false' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"always-on-track-impressions-false","impressionsDisabled":true,"seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' diff --git a/src/__tests__/mocks/splitchanges.since.-1.json b/src/__tests__/mocks/splitchanges.since.-1.json index c31ac7e8b..372b030b8 100644 --- a/src/__tests__/mocks/splitchanges.since.-1.json +++ b/src/__tests__/mocks/splitchanges.since.-1.json @@ -1265,7 +1265,7 @@ "trafficTypeId": null, "trafficTypeName": null, "name": "hierarchical_splits_test", - "trackImpressions": true, + "impressionsDisabled": false, "seed": 1276793945, "changeNumber": 2828282828, "status": "ACTIVE", @@ -1388,7 +1388,7 @@ "trafficTypeId": null, "trafficTypeName": null, "name": "always_on_track_impressions_false", - "trackImpressions": false, + "impressionsDisabled": true, "seed": -790401604, "status": "ACTIVE", "killed": false, @@ -1466,7 +1466,7 @@ { "trafficTypeName": null, "name": "split_with_config", - "trackImpressions": true, + "impressionsDisabled": false, "algo": 2, "seed": -1222652064, "trafficAllocation": 100, diff --git a/src/__tests__/nodeSuites/impressions.spec.js b/src/__tests__/nodeSuites/impressions.spec.js index ef96a537b..e7615140c 100644 --- a/src/__tests__/nodeSuites/impressions.spec.js +++ b/src/__tests__/nodeSuites/impressions.spec.js @@ -49,7 +49,7 @@ export default async function (key, fetchMock, assert) { assert.equal(opts.headers.SplitSDKImpressionsMode, OPTIMIZED); const data = JSON.parse(opts.body); - assert.equal(data.length, 3, 'We performed evaluations for 4 features, but one with `trackImpressions` false, so we should have 3 items total.'); + assert.equal(data.length, 3, 'We performed evaluations for 4 features, but one with `impressionsDisabled` true, so we should have 3 items total.'); // finding these validate the feature names collection too const dependencyChildImpr = data.filter(e => e.f === 'hierarchical_splits_test')[0]; diff --git a/src/__tests__/nodeSuites/manager.spec.js b/src/__tests__/nodeSuites/manager.spec.js index 82588949c..869d65e3b 100644 --- a/src/__tests__/nodeSuites/manager.spec.js +++ b/src/__tests__/nodeSuites/manager.spec.js @@ -41,7 +41,7 @@ export default async function (settings, fetchMock, assert) { 'configs': mockSplits.splits[index].configurations || {}, 'sets': mockSplits.splits[index].sets || [], 'defaultTreatment': mockSplits.splits[index].defaultTreatment, - 'trackImpressions': true + 'impressionsDisabled': false }); assert.equal(manager.split('non_existent'), null, 'Trying to get a manager.split() of a Split that does not exist returns null.'); diff --git a/src/__tests__/offline/browser.spec.js b/src/__tests__/offline/browser.spec.js index 81bc3efd3..4411914cf 100644 --- a/src/__tests__/offline/browser.spec.js +++ b/src/__tests__/offline/browser.spec.js @@ -168,10 +168,10 @@ tape('Browser offline mode', function (assert) { // Manager tests const expectedSplitView1 = { - name: 'testing_split', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['on'], configs: {}, defaultTreatment: 'control', sets: [], trackImpressions: true + name: 'testing_split', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['on'], configs: {}, defaultTreatment: 'control', sets: [], impressionsDisabled: false }; const expectedSplitView2 = { - name: 'testing_split_with_config', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['off'], configs: { off: '{ "color": "blue" }' }, defaultTreatment: 'control', sets: [], trackImpressions: true + name: 'testing_split_with_config', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['off'], configs: { off: '{ "color": "blue" }' }, defaultTreatment: 'control', sets: [], impressionsDisabled: false }; assert.deepEqual(manager.names(), ['testing_split', 'testing_split_with_config']); assert.deepEqual(manager.split('testing_split'), expectedSplitView1); @@ -282,7 +282,7 @@ tape('Browser offline mode', function (assert) { // Manager tests const expectedSplitView3 = { - name: 'testing_split_with_config', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['nope'], configs: {}, defaultTreatment: 'control', sets: [], trackImpressions: true + name: 'testing_split_with_config', trafficType: 'localhost', killed: false, changeNumber: 0, treatments: ['nope'], configs: {}, defaultTreatment: 'control', sets: [], impressionsDisabled: false }; assert.deepEqual(manager.names(), ['testing_split', 'testing_split_2', 'testing_split_3', 'testing_split_with_config']); assert.deepEqual(manager.split('testing_split'), expectedSplitView1); diff --git a/src/__tests__/offline/node.spec.js b/src/__tests__/offline/node.spec.js index 3e3166b6c..cbc6e40d3 100644 --- a/src/__tests__/offline/node.spec.js +++ b/src/__tests__/offline/node.spec.js @@ -250,17 +250,17 @@ function ManagerDotSplitTests(assert) { const expectedView1 = { name: 'testing_split', changeNumber: 0, killed: false, trafficType: 'localhost', treatments: ['on'], configs: {}, defaultTreatment: 'control', - sets: [], trackImpressions: true + sets: [], impressionsDisabled: false }; const expectedView2 = { name: 'testing_split2', changeNumber: 0, killed: false, trafficType: 'localhost', treatments: ['off'], configs: {}, defaultTreatment: 'control', - sets: [], trackImpressions: true + sets: [], impressionsDisabled: false }; const expectedView3 = { name: 'testing_split3', changeNumber: 0, killed: false, trafficType: 'localhost', treatments: ['custom_treatment'], configs: {}, defaultTreatment: 'control', - sets: [], trackImpressions: true + sets: [], impressionsDisabled: false }; assert.deepEqual(manager.split('testing_split'), expectedView1); @@ -295,7 +295,7 @@ function ManagerDotYamlTests(mockFileName, assert) { configs: {}, sets: [], defaultTreatment: 'control', - trackImpressions: true + impressionsDisabled: false }; const expectedView2 = { name: 'testing_split_only_wl', @@ -306,7 +306,7 @@ function ManagerDotYamlTests(mockFileName, assert) { configs: {}, sets: [], defaultTreatment: 'control', - trackImpressions: true + impressionsDisabled: false }; const expectedView3 = { name: 'testing_split_with_wl', @@ -320,7 +320,7 @@ function ManagerDotYamlTests(mockFileName, assert) { }, sets: [], defaultTreatment: 'control', - trackImpressions: true + impressionsDisabled: false }; const expectedView4 = { name: 'testing_split_off_with_config', @@ -333,7 +333,7 @@ function ManagerDotYamlTests(mockFileName, assert) { }, sets: [], defaultTreatment: 'control', - trackImpressions: true + impressionsDisabled: false }; assert.deepEqual(manager.split('testing_split_on'), expectedView1); @@ -414,15 +414,15 @@ function MultipleInstancesTests(assert) { const expectedView1 = { name: 'testing_split', changeNumber: 0, killed: false, trafficType: 'localhost', - treatments: ['on'], configs: {}, sets: [], trackImpressions: true + treatments: ['on'], configs: {}, sets: [], impressionsDisabled: false }; const expectedView2 = { name: 'testing_split2', changeNumber: 0, killed: false, trafficType: 'localhost', - treatments: ['off'], configs: {}, sets: [], trackImpressions: true + treatments: ['off'], configs: {}, sets: [], impressionsDisabled: false }; const expectedView3 = { name: 'testing_split3', changeNumber: 0, killed: false, trafficType: 'localhost', - treatments: ['custom_treatment'], configs: {}, sets: [], trackImpressions: true + treatments: ['custom_treatment'], configs: {}, sets: [], impressionsDisabled: false }; assert.deepEqual(manager.split('testing_split'), expectedView1); diff --git a/ts-tests/index.ts b/ts-tests/index.ts index 5f52bdf8c..823e00771 100644 --- a/ts-tests/index.ts +++ b/ts-tests/index.ts @@ -135,7 +135,7 @@ splitView = { }, sets: ['set_a', 'set_b'], defaultTreatment: 'off', - trackImpressions: true + impressionsDisabled: false }; splitViews = [splitView]; From 174d5fa87fc0237f611f5ee25edc2ea126b607c6 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 17 Jan 2025 17:15:35 -0300 Subject: [PATCH 08/11] Stable version --- CHANGES.txt | 2 +- package-lock.json | 4 ++-- package.json | 2 +- src/settings/defaults/version.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index a4a7e4fc6..035f6bcff 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,4 @@ -11.1.0 (January XX, 2025) +11.1.0 (January 17, 2025) - Added support for the new impressions tracking toggle available on feature flags, both respecting the setting and including the new field being returned on `SplitView` type objects. Read more in our docs. 11.0.4 (January 9, 2025) diff --git a/package-lock.json b/package-lock.json index 7cdd1431a..9c46f2f66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio", - "version": "11.0.4", + "version": "11.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio", - "version": "11.0.4", + "version": "11.1.0", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio-commons": "2.1.0", diff --git a/package.json b/package.json index 579d960fd..efc19f4d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio", - "version": "11.0.4", + "version": "11.1.0", "description": "Split SDK", "files": [ "README.md", diff --git a/src/settings/defaults/version.js b/src/settings/defaults/version.js index 563a20863..eb209ae90 100644 --- a/src/settings/defaults/version.js +++ b/src/settings/defaults/version.js @@ -1 +1 @@ -export const packageVersion = '11.0.4'; +export const packageVersion = '11.1.0'; From 19e9f2a71b7f03cce621e339e13a0b58ecb2b7ce Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 17 Jan 2025 17:23:23 -0300 Subject: [PATCH 09/11] Update changelog entry --- CHANGES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.txt b/CHANGES.txt index 035f6bcff..070dc76c4 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,6 @@ 11.1.0 (January 17, 2025) - Added support for the new impressions tracking toggle available on feature flags, both respecting the setting and including the new field being returned on `SplitView` type objects. Read more in our docs. + - Updated @splitsoftware/splitio-commons package to version 2.1.0. 11.0.4 (January 9, 2025) - Bugfixing - Updated @splitsoftware/splitio-commons package to version 2.0.3, which properly handles rejected promises when using targeting rules with segment matchers in consumer modes (e.g., Redis and Pluggable storages). From 4eb5613d6bb72848d5ed9e95bc6b466f8d911047 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 17 Jan 2025 18:05:22 -0300 Subject: [PATCH 10/11] Test polishing --- src/__tests__/consumer/node_redis.spec.js | 8 ++++---- src/__tests__/mocks/redis-commands.txt | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/__tests__/consumer/node_redis.spec.js b/src/__tests__/consumer/node_redis.spec.js index 25f1809fb..1612104af 100644 --- a/src/__tests__/consumer/node_redis.spec.js +++ b/src/__tests__/consumer/node_redis.spec.js @@ -155,7 +155,7 @@ tape('Node.js Redis', function (t) { assert.equal(await client.getTreatment('UT_Segment_member', 'hierarchical_splits_testing_on'), 'on', 'Evaluations using Redis storage should be correct.'); assert.equal(await client.getTreatment('UT_Segment_member', 'hierarchical_splits_testing_off'), 'off', 'Evaluations using Redis storage should be correct.'); assert.equal(await client.getTreatment('UT_Segment_member', 'hierarchical_splits_testing_on_negated'), 'off', 'Evaluations using Redis storage should be correct.'); - assert.equal(await client.getTreatment('other_key', 'always-on-track-impressions-false'), 'on', 'Evaluations using Redis storage should be correct.'); + assert.equal(await client.getTreatment('other_key', 'always-on-impressions-disabled-true'), 'on', 'Evaluations using Redis storage should be correct.'); assert.equal(typeof client.track().then, 'function', 'Track calls should always return a promise on Redis mode, even when parameters are incorrect.'); @@ -174,14 +174,14 @@ tape('Node.js Redis', function (t) { await client.ready(); // promise already resolved await client.destroy(); - // Validate Impression Counts and Unique Keys for 'always-on-track-impressions-false' + // Validate Impression Counts and Unique Keys for 'always-on-impressions-disabled-true' exec(`echo "HGETALL ${config.storage.prefix}.SPLITIO.impressions.count" | redis-cli -p ${redisPort}`, async (error, stdout) => { const trackedImpressionCounts = stdout.split('\n').filter(line => line !== ''); - assert.deepEqual(trackedImpressionCounts, [`always-on-track-impressions-false::${truncateTimeFrame(timeFrame)}`, '1',], 'Tracked impression counts should be stored in Redis TODO'); + assert.deepEqual(trackedImpressionCounts, [`always-on-impressions-disabled-true::${truncateTimeFrame(timeFrame)}`, '1',], 'Tracked impression counts should be stored in Redis TODO'); exec(`echo "LRANGE ${config.storage.prefix}.SPLITIO.uniquekeys 0 20" | redis-cli -p ${redisPort}`, async (error, stdout) => { const storedUniqueKeys = stdout.split('\n').filter(line => line !== '').map(JSON.parse); - assert.deepEqual(storedUniqueKeys, [{ 'f': 'always-on-track-impressions-false', 'ks': ['other_key'] }], 'Unique keys should be stored in Redis TODO'); + assert.deepEqual(storedUniqueKeys, [{ 'f': 'always-on-impressions-disabled-true', 'ks': ['other_key'] }], 'Unique keys should be stored in Redis TODO'); // Validate stored impressions and events exec(`echo "LLEN ${config.storage.prefix}.SPLITIO.impressions \n LLEN ${config.storage.prefix}.SPLITIO.events" | redis-cli -p ${redisPort}`, (error, stdout) => { diff --git a/src/__tests__/mocks/redis-commands.txt b/src/__tests__/mocks/redis-commands.txt index 9c87b56e0..e3ad7c35a 100644 --- a/src/__tests__/mocks/redis-commands.txt +++ b/src/__tests__/mocks/redis-commands.txt @@ -22,7 +22,7 @@ SET 'REDIS_NODE_UT.SPLITIO.split.always-on' '{"changeNumber":1487277320548," SET 'REDIS_NODE_UT.SPLITIO.split.always-o.n-with-config' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"always-o.n-with-config","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"o.n","size":100},{"treatment":"off","size":0}],"label":"in segment all"}],"configurations":{"o.n":"{\"color\":\"brown\"}"}}' SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_off' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_off","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["off"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_on' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_on","impressionsDisabled":false,"seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["on"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' -SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_on_negated' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_on","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":true,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["on"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' +SET 'REDIS_NODE_UT.SPLITIO.split.hierarchical_splits_testing_on_negated' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"hierarchical_splits_testing_on_negated","seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":true,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"dependencyMatcherData":{"split":"always-on","treatments":["on"]},"matcherType":"IN_SPLIT_TREATMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":null,"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.labels' '{"changeNumber":1492023661334,"trafficTypeName":"user","name":"labels","seed":-1240661267,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"demo"},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"user","attribute":"n"},"matcherType":"EQUAL_TO","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"NUMBER","value":123},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment all and in segment demo and n = 123"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.nico_not' '{"changeNumber":1489412422181,"trafficTypeName":"user","name":"nico_not","seed":-788702424,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"qa"},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment qa"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.not_part_of' '{"changeNumber":1492627582227,"trafficTypeName":"user","name":"not_part_of","seed":-1643575289,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":"setx"},"matcherType":"PART_OF_SET","negate":true,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":["a","b","c"]},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"setx not part of [a, b, ...]"}]}' @@ -39,4 +39,4 @@ SET 'REDIS_NODE_UT.SPLITIO.split.testing_traffic_type' '{"changeNumber":1489 SET 'REDIS_NODE_UT.SPLITIO.split.testing_traffic_types' '{"changeNumber":1490974465415,"trafficTypeName":"machine","name":"testing_traffic_types","seed":475616886,"status":"ACTIVE","killed":false,"defaultTreatment":"on","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"","attribute":""},"matcherType":"WHITELIST","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":["sarasa"]},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100}],"label":"whitelisted"},{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"","attribute":""},"matcherType":"WHITELIST","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":["excluded"]},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"off","size":100}],"label":"whitelisted"},{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}},{"keySelector":{"trafficType":"machine","attribute":""},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"testing_traffic_type"},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":100}],"label":"in segment all and in segment testing_traffic_type"}]}' SET 'REDIS_NODE_UT.SPLITIO.split.traffic_allocation_testing' '{"changeNumber":1490974123779,"trafficTypeName":"user","name":"traffic_allocation_testing","seed":1716284102,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' SET 'REDIS_NODE_UT.SPLITIO.splits.till' 1492723024413 -SET 'REDIS_NODE_UT.SPLITIO.split.always-on-track-impressions-false' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"always-on-track-impressions-false","impressionsDisabled":true,"seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' +SET 'REDIS_NODE_UT.SPLITIO.split.always-on-impressions-disabled-true' '{"changeNumber":1487277320548,"trafficTypeName":"user","name":"always-on-impressions-disabled-true","impressionsDisabled":true,"seed":1684183541,"status":"ACTIVE","killed":false,"defaultTreatment":"off","conditions":[{"matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"user","attribute":""},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":{"segmentName":""},"unaryNumericMatcherData":{"dataType":"","value":0},"whitelistMatcherData":{"whitelist":null},"betweenMatcherData":{"dataType":"","start":0,"end":0}}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0}],"label":"in segment all"}]}' From ce98bb717acbedbda8b6e2870ba77a8d3a366f02 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 17 Jan 2025 18:09:57 -0300 Subject: [PATCH 11/11] Test polishing --- src/__tests__/consumer/node_redis.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/__tests__/consumer/node_redis.spec.js b/src/__tests__/consumer/node_redis.spec.js index 1612104af..a2317ce48 100644 --- a/src/__tests__/consumer/node_redis.spec.js +++ b/src/__tests__/consumer/node_redis.spec.js @@ -282,7 +282,7 @@ tape('Node.js Redis', function (t) { // this should be deduped assert.equal(await client.getTreatment('UT_Segment_member', 'always-on'), 'on', 'Evaluations using Redis storage should be correct.'); - // Below splits were added manually to the redis_mock.json file. + // Below feature flags were added manually to the redis_mock.json file. // They are all_keys (always evaluate to on) which depend from always-on split. the _on/off is what treatment they are expecting there. assert.equal(await client.getTreatment('UT_Segment_member', 'hierarchical_splits_testing_on'), 'on', 'Evaluations using Redis storage should be correct.'); // this should be deduped @@ -384,7 +384,7 @@ tape('Node.js Redis', function (t) { assert.equal(await client.getTreatment('UT_Segment_member', 'always-on'), 'on', 'Evaluations using Redis storage should be correct.'); - // Below splits were added manually to the redis_mock.json file. + // Below feature flags were added manually to the redis_mock.json file. // They are all_keys (always evaluate to on) which depend from always-on split. the _on/off is what treatment they are expecting there. assert.equal(await client.getTreatment('UT_Segment_member', 'hierarchical_splits_testing_on'), 'on', 'Evaluations using Redis storage should be correct.'); assert.equal(await client.getTreatment('UT_Segment_member', 'hierarchical_splits_testing_off'), 'off', 'Evaluations using Redis storage should be correct.');