Skip to content

Commit bb87136

Browse files
committed
cleanup
1 parent 168a07b commit bb87136

4 files changed

Lines changed: 8 additions & 125 deletions

File tree

lib/core/decision_service/index.spec.ts

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,63 +1960,15 @@ describe('DecisionService', () => {
19601960
});
19611961
});
19621962

1963-
it("should consider global holdout even if local holdout is present", async () => {
1964-
const { decisionService } = getDecisionService();
1965-
const datafile = getHoldoutTestDatafile();
1966-
const newEntry = {
1967-
id: 'holdout_included_id',
1968-
key: 'holdout_included',
1969-
status: 'Running',
1970-
includedFlags: ['1001'],
1971-
excludedFlags: [],
1972-
audienceIds: ['4002'], // age_40 audience
1973-
audienceConditions: ['or', '4002'],
1974-
variations: [
1975-
{
1976-
id: 'holdout_variation_included_id',
1977-
key: 'holdout_variation_included',
1978-
variables: [],
1979-
},
1980-
],
1981-
trafficAllocation: [
1982-
{
1983-
entityId: 'holdout_variation_included_id',
1984-
endOfRange: 5000,
1985-
},
1986-
],
1987-
};
1988-
datafile.holdouts = [newEntry, ...datafile.holdouts];
1989-
const config = createProjectConfig(datafile);
1990-
const user = new OptimizelyUserContext({
1991-
optimizely: {} as any,
1992-
userId: 'tester',
1993-
attributes: {
1994-
age: 20, // satisfies both global holdout (age_22) and included holdout (age_40) audiences
1995-
},
1996-
});
1997-
const feature = config.featureKeyMap['flag_1'];
1998-
const value = decisionService.resolveVariationsForFeatureList('async', config, [feature], user, {}).get();
1999-
2000-
expect(value).toBeInstanceOf(Promise);
2001-
2002-
const variation = (await value)[0];
2003-
2004-
expect(variation.result).toEqual({
2005-
experiment: config.holdoutIdMap && config.holdoutIdMap['holdout_running_id'],
2006-
variation: config.variationIdMap['holdout_variation_running_id'],
2007-
decisionSource: DECISION_SOURCES.HOLDOUT,
2008-
});
2009-
});
2010-
2011-
it("should consider local holdout if misses global holdout", async () => {
1963+
it("should consider next global holdout if misses previous holdouts", async () => {
20121964
const { decisionService } = getDecisionService();
20131965
const datafile = getHoldoutTestDatafile();
20141966

20151967
datafile.holdouts.push({
20161968
id: 'holdout_included_specific_id',
20171969
key: 'holdout_included_specific',
20181970
status: 'Running',
2019-
includedFlags: ['1001'],
1971+
includedFlags: [],
20201972
excludedFlags: [],
20211973
audienceIds: ['4002'], // age_60 audience (age <= 60)
20221974
audienceConditions: ['or', '4002'],
@@ -2039,7 +1991,7 @@ describe('DecisionService', () => {
20391991
optimizely: {} as any,
20401992
userId: 'test_holdout_user',
20411993
attributes: {
2042-
age: 50, // Does not satisfy global holdout (age_22, age <= 22) but satisfies included holdout (age_60, age <= 60)
1994+
age: 50, // Does not satisfy first global holdout (age_22, age <= 22) but satisfies newly added holdout (age_60, age <= 60)
20431995
},
20441996
});
20451997
const feature = config.featureKeyMap['flag_1'];
@@ -2195,42 +2147,6 @@ describe('DecisionService', () => {
21952147
});
21962148
});
21972149

2198-
it('should skip holdouts excluded for specific flags', async () => {
2199-
const { decisionService } = getDecisionService();
2200-
const datafile = getHoldoutTestDatafile();
2201-
2202-
datafile.holdouts = datafile.holdouts.map((holdout: any) => {
2203-
if(holdout.id === 'holdout_running_id') {
2204-
return {
2205-
...holdout,
2206-
excludedFlags: ['1001']
2207-
}
2208-
}
2209-
return holdout;
2210-
});
2211-
2212-
const config = createProjectConfig(datafile);
2213-
const user = new OptimizelyUserContext({
2214-
optimizely: {} as any,
2215-
userId: 'tester',
2216-
attributes: {
2217-
age: 15, // satisfies age_22 audience condition (age <= 22) for global holdout, but holdout excludes flag_1
2218-
},
2219-
});
2220-
const feature = config.featureKeyMap['flag_1'];
2221-
const value = decisionService.resolveVariationsForFeatureList('async', config, [feature], user, {}).get();
2222-
2223-
expect(value).toBeInstanceOf(Promise);
2224-
2225-
const variation = (await value)[0];
2226-
2227-
expect(variation.result).toEqual({
2228-
experiment: config.experimentKeyMap['exp_1'],
2229-
variation: config.variationIdMap['5001'],
2230-
decisionSource: DECISION_SOURCES.FEATURE_TEST,
2231-
});
2232-
});
2233-
22342150
it('should handle multiple holdouts and use first matching one', async () => {
22352151
const { decisionService } = getDecisionService();
22362152
const datafile = getHoldoutTestDatafile();

lib/core/decision_service/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import {
3131
getVariationKeyFromId,
3232
isActive,
3333
ProjectConfig,
34-
getHoldoutsForFlag,
3534
} from '../../project_config/project_config';
3635
import { AudienceEvaluator, createAudienceEvaluator } from '../audience_evaluator';
3736
import * as stringValidator from '../../utils/string_value_validator';
@@ -943,7 +942,10 @@ export class DecisionService {
943942
reasons: decideReasons,
944943
});
945944
}
946-
const holdouts = getHoldoutsForFlag(configObj, feature.key);
945+
946+
// all global holouts should be evaluated for all flags
947+
// global holdouts are available in configObj.holdouts
948+
const { holdouts } = configObj;
947949

948950
for (const holdout of holdouts) {
949951
const holdoutDecision = this.getVariationForHoldout(configObj, holdout, user);

lib/project_config/project_config.spec.ts

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import testDatafile from '../tests/test_data';
3030
import configValidator from '../utils/config_validator';
3131
import { FEATURE_VARIABLE_TYPES } from '../utils/enums';
3232
import { keyBy, sprintf } from '../utils/fns';
33-
import projectConfig, { ProjectConfig, getHoldoutsForFlag } from './project_config';
33+
import projectConfig, { ProjectConfig } from './project_config';
3434

3535
const cloneDeep = (obj: any) => JSON.parse(JSON.stringify(obj));
3636
const logger = getMockLogger();
@@ -392,8 +392,6 @@ describe('createProjectConfig - holdouts', () => {
392392
holdout_id_2: configObj.holdouts[1],
393393
holdout_id_3: configObj.holdouts[2],
394394
});
395-
396-
expect(configObj.flagHoldoutsMap).toEqual({});
397395
});
398396

399397
it('should handle empty holdouts array', function() {
@@ -403,27 +401,6 @@ describe('createProjectConfig - holdouts', () => {
403401

404402
expect(configObj.holdouts).toEqual([]);
405403
expect(configObj.holdoutIdMap).toEqual({});
406-
expect(configObj.flagHoldoutsMap).toEqual({});
407-
});
408-
});
409-
410-
describe('getHoldoutsForFlag', () => {
411-
it('should return all holdouts for any flag', () => {
412-
const datafile = getHoldoutDatafile();
413-
const configObj = projectConfig.createProjectConfig(JSON.parse(JSON.stringify(datafile)));
414-
415-
// All holdouts now apply globally to all flags
416-
const feature1Holdouts = getHoldoutsForFlag(configObj, 'feature_1');
417-
expect(feature1Holdouts).toHaveLength(3);
418-
expect(feature1Holdouts).toEqual(configObj.holdouts);
419-
420-
const feature2Holdouts = getHoldoutsForFlag(configObj, 'feature_2');
421-
expect(feature2Holdouts).toHaveLength(3);
422-
expect(feature2Holdouts).toEqual(configObj.holdouts);
423-
424-
const feature3Holdouts = getHoldoutsForFlag(configObj, 'feature_3');
425-
expect(feature3Holdouts).toHaveLength(3);
426-
expect(feature3Holdouts).toEqual(configObj.holdouts);
427404
});
428405
});
429406

lib/project_config/project_config.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ export interface ProjectConfig {
113113
odpIntegrationConfig: OdpIntegrationConfig;
114114
holdouts: Holdout[];
115115
holdoutIdMap?: { [id: string]: Holdout };
116-
flagHoldoutsMap: { [key: string]: Holdout[]; }
117116
}
118117

119118
const EXPERIMENT_RUNNING_STATUS = 'Running';
@@ -387,24 +386,13 @@ const getEveryoneElseVariation = function(
387386
const parseHoldoutsConfig = (projectConfig: ProjectConfig): void => {
388387
projectConfig.holdouts = projectConfig.holdouts || [];
389388
projectConfig.holdoutIdMap = keyBy(projectConfig.holdouts, 'id');
390-
projectConfig.flagHoldoutsMap = {};
391389

392390
projectConfig.holdouts.forEach((holdout) => {
393391
holdout.variationKeyMap = keyBy(holdout.variations, 'key');
394392
assignBy(holdout.variations, 'id', projectConfig.variationIdMap);
395393
});
396394
}
397395

398-
export const getHoldoutsForFlag = (projectConfig: ProjectConfig, flagKey: string): Holdout[] => {
399-
if (projectConfig.flagHoldoutsMap[flagKey]) {
400-
return projectConfig.flagHoldoutsMap[flagKey];
401-
}
402-
403-
// All holdouts now apply to all flags (global holdouts)
404-
projectConfig.flagHoldoutsMap[flagKey] = projectConfig.holdouts;
405-
return projectConfig.holdouts;
406-
}
407-
408396
/**
409397
* Extract all audience segments used in this audience's conditions
410398
* @param {Audience} audience Object representing the audience being parsed

0 commit comments

Comments
 (0)