Skip to content

Commit 4e6a1c9

Browse files
trekforevererikeldridge
authored andcommitted
Add tests for percent condition eval
1 parent 31d6c9a commit 4e6a1c9

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed

test/unit/remote-config/remote-config-condition-evaluator.spec.ts

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
import * as chai from 'chai';
2020
import { RemoteConfigConditionEvaluator } from '../../../src/remote-config/remote-config-condition-evaluator-internal';
21+
import { PercentConditionOperator, RemoteConfigServerPercentCondition } from '../../../src/remote-config/remote-config-api';
22+
import { v4 as uuidv4 } from 'uuid';
23+
import { clone } from 'lodash';
2124

2225
const expect = chai.expect;
2326

@@ -108,5 +111,248 @@ describe('RemoteConfigConditionEvaluator', () => {
108111
expect(evaluator.evaluateConditions([condition], context)).deep.equals(
109112
new Map([["is_enabled", false]]));
110113
});
114+
115+
describe('percentCondition', () => {
116+
it('should evaluate less or equal to max to true', () => {
117+
const condition = {
118+
name: 'is_enabled',
119+
condition: {
120+
or: {
121+
conditions: [{
122+
and: {
123+
conditions: [{
124+
percent: {
125+
operator: PercentConditionOperator.LESS_OR_EQUAL,
126+
seed: "abcdef",
127+
microPercent: 100_000_000
128+
}
129+
}],
130+
}
131+
}]
132+
}
133+
}
134+
};
135+
const evaluator = new RemoteConfigConditionEvaluator();
136+
expect(evaluator.evaluateConditions([condition])).deep.equals(
137+
new Map([["is_enabled", true]]));
138+
});
139+
140+
it('should evaluate greater than min to true', () => {
141+
const condition = {
142+
name: 'is_enabled',
143+
condition: {
144+
or: {
145+
conditions: [{
146+
and: {
147+
conditions: [{
148+
percent: {
149+
operator: PercentConditionOperator.GREATER_THAN,
150+
seed: "abcdef",
151+
microPercent: 0
152+
}
153+
}],
154+
}
155+
}]
156+
}
157+
}
158+
};
159+
const evaluator = new RemoteConfigConditionEvaluator();
160+
expect(evaluator.evaluateConditions([condition])).deep.equals(
161+
new Map([["is_enabled", true]]));
162+
});
163+
164+
it('should evaluate between min and max to true', () => {
165+
const condition = {
166+
name: 'is_enabled',
167+
condition: {
168+
or: {
169+
conditions: [{
170+
and: {
171+
conditions: [{
172+
percent: {
173+
operator: PercentConditionOperator.BETWEEN,
174+
seed: "abcdef",
175+
microPercentRange: {
176+
microPercentLowerBound: 0,
177+
microPercentUpperBound: 100_000_000
178+
}
179+
}
180+
}],
181+
}
182+
}]
183+
}
184+
}
185+
};
186+
const evaluator = new RemoteConfigConditionEvaluator();
187+
expect(evaluator.evaluateConditions([condition])).deep.equals(
188+
new Map([["is_enabled", true]]));
189+
});
190+
191+
it('should evaluate less or equal to min to false', () => {
192+
const condition = {
193+
name: 'is_enabled',
194+
condition: {
195+
or: {
196+
conditions: [{
197+
and: {
198+
conditions: [{
199+
percent: {
200+
operator: PercentConditionOperator.LESS_OR_EQUAL,
201+
seed: "abcdef",
202+
microPercent: 0
203+
}
204+
}],
205+
}
206+
}]
207+
}
208+
}
209+
};
210+
const evaluator = new RemoteConfigConditionEvaluator();
211+
expect(evaluator.evaluateConditions([condition])).deep.equals(
212+
new Map([["is_enabled", false]]));
213+
});
214+
215+
it('should evaluate greater than max to false', () => {
216+
const condition = {
217+
name: 'is_enabled',
218+
condition: {
219+
or: {
220+
conditions: [{
221+
and: {
222+
conditions: [{
223+
percent: {
224+
operator: PercentConditionOperator.GREATER_THAN,
225+
seed: "abcdef",
226+
microPercent: 100_000_000
227+
}
228+
}],
229+
}
230+
}]
231+
}
232+
}
233+
};
234+
const evaluator = new RemoteConfigConditionEvaluator();
235+
expect(evaluator.evaluateConditions([condition])).deep.equals(
236+
new Map([["is_enabled", false]]));
237+
});
238+
239+
it('should evaluate between equal bounds to false', () => {
240+
const condition = {
241+
name: 'is_enabled',
242+
condition: {
243+
or: {
244+
conditions: [{
245+
and: {
246+
conditions: [{
247+
percent: {
248+
operator: PercentConditionOperator.BETWEEN,
249+
seed: "abcdef",
250+
microPercentRange: {
251+
microPercentLowerBound: 50000000,
252+
microPercentUpperBound: 50000000
253+
}
254+
}
255+
}],
256+
}
257+
}]
258+
}
259+
}
260+
};
261+
const evaluator = new RemoteConfigConditionEvaluator();
262+
expect(evaluator.evaluateConditions([condition])).deep.equals(
263+
new Map([["is_enabled", false]]));
264+
});
265+
266+
it('should evaluate less or equal to 10% to approx 10%', () => {
267+
const percentCondition = {
268+
operator: PercentConditionOperator.LESS_OR_EQUAL,
269+
microPercent: 10_000_000 // 10%
270+
};
271+
const evaluator = new RemoteConfigConditionEvaluator();
272+
// run this evaluator 100 times, and log the number of true assignments
273+
const truthyAssignments = evaluateRandomAssignments(percentCondition, 100_000, evaluator);
274+
expect(truthyAssignments).to.be.greaterThanOrEqual(10000 - 250);
275+
expect(truthyAssignments).to.be.lessThanOrEqual(10000 + 250);
276+
});
277+
278+
it('should evaluate between 0 to 10% to approx 10%', () => {
279+
const percentCondition = {
280+
operator: PercentConditionOperator.BETWEEN,
281+
microPercentRange: {
282+
microPercentLowerBound: 0,
283+
microPercentUpperBound: 10_000_000
284+
}
285+
};
286+
const evaluator = new RemoteConfigConditionEvaluator();
287+
// run this evaluator 100 times, and log the number of true assignments
288+
const truthyAssignments = evaluateRandomAssignments(percentCondition, 100_000, evaluator);
289+
expect(truthyAssignments).to.be.greaterThanOrEqual(10000 - 250);
290+
expect(truthyAssignments).to.be.lessThanOrEqual(10000 + 250);
291+
});
292+
293+
it('should evaluate greater than 10% to approx 90%', () => {
294+
const percentCondition = {
295+
operator: PercentConditionOperator.GREATER_THAN,
296+
microPercent: 10_000_000
297+
};
298+
const evaluator = new RemoteConfigConditionEvaluator();
299+
// run this evaluator 100 times, and log the number of true assignments
300+
const truthyAssignments = evaluateRandomAssignments(percentCondition, 100_000, evaluator);
301+
expect(truthyAssignments).to.be.greaterThanOrEqual(90000 - 250);
302+
expect(truthyAssignments).to.be.lessThanOrEqual(90000 + 250);
303+
});
304+
305+
it('should evaluate between 40% to 60% to approx 20%', () => {
306+
const percentCondition = {
307+
operator: PercentConditionOperator.BETWEEN,
308+
microPercentRange: {
309+
microPercentLowerBound: 40_000_000,
310+
microPercentUpperBound: 60_000_000
311+
}
312+
};
313+
const evaluator = new RemoteConfigConditionEvaluator();
314+
// run this evaluator 100 times, and log the number of true assignments
315+
const truthyAssignments = evaluateRandomAssignments(percentCondition, 100_000, evaluator);
316+
expect(truthyAssignments).to.be.greaterThanOrEqual(20000 - 250);
317+
expect(truthyAssignments).to.be.lessThanOrEqual(20000 + 250);
318+
});
319+
320+
it('should evaluate between interquartile range to approx 50%', () => {
321+
const percentCondition = {
322+
operator: PercentConditionOperator.BETWEEN,
323+
microPercentRange: {
324+
microPercentLowerBound: 25_000_000,
325+
microPercentUpperBound: 75_000_000
326+
}
327+
};
328+
const evaluator = new RemoteConfigConditionEvaluator();
329+
// run this evaluator 100 times, and log the number of true assignments
330+
const truthyAssignments = evaluateRandomAssignments(percentCondition, 100_000, evaluator);
331+
expect(truthyAssignments).to.be.greaterThanOrEqual(50000 - 250);
332+
expect(truthyAssignments).to.be.lessThanOrEqual(50000 + 250);
333+
});
334+
335+
// Returns the number of assignments which evaluate to true for the specified percent condition
336+
// This method randomly generates the ids for each assignment for this purpose
337+
function evaluateRandomAssignments(
338+
condition: RemoteConfigServerPercentCondition,
339+
numOfAssignments: number,
340+
conditionEvaluator: RemoteConfigConditionEvaluator): number {
341+
let evalTrueCount = 0;
342+
for (let i = 0; i < numOfAssignments; i++) {
343+
let id = uuidv4();
344+
let clonedCondition = {
345+
...clone(condition),
346+
seed: id
347+
};
348+
349+
if (conditionEvaluator.evaluateConditions([{
350+
name: 'is_enabled',
351+
condition: { percent: clonedCondition }
352+
}]).get('is_enabled') == true) { evalTrueCount++ }
353+
}
354+
return evalTrueCount;
355+
}
356+
});
111357
});
112358
});

0 commit comments

Comments
 (0)