Skip to content

Commit 1c7dc66

Browse files
authored
fix: false positive of a falsy variant value check (#651)
Signed-off-by: Michael Beemer <[email protected]>
1 parent bbd9aee commit 1c7dc66

File tree

2 files changed

+73
-33
lines changed

2 files changed

+73
-33
lines changed

libs/shared/flagd-core/src/lib/flagd-core.spec.ts

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,80 @@ import { FlagdCore } from './flagd-core';
22
import { GeneralError, StandardResolutionReasons, TypeMismatchError } from '@openfeature/core';
33

44
describe('flagd-core resolving', () => {
5-
const flagCfg = `{"flags":{"myBoolFlag":{"state":"ENABLED","variants":{"on":true,"off":false},"defaultVariant":"on"},"myStringFlag":{"state":"ENABLED","variants":{"key1":"val1","key2":"val2"},"defaultVariant":"key1"},"myFloatFlag":{"state":"ENABLED","variants":{"one":1.23,"two":2.34},"defaultVariant":"one"},"myIntFlag":{"state":"ENABLED","variants":{"one":1,"two":2},"defaultVariant":"one"},"myObjectFlag":{"state":"ENABLED","variants":{"object1":{"key":"val"},"object2":{"key":true}},"defaultVariant":"object1"},"fibAlgo":{"variants":{"recursive":"recursive","memo":"memo","loop":"loop","binet":"binet"},"defaultVariant":"recursive","state":"ENABLED","targeting":{"if":[{"$ref":"emailWithFaas"},"binet",null]}},"targetedFlag":{"variants":{"first":"AAA","second":"BBB","third":"CCC"},"defaultVariant":"first","state":"ENABLED","targeting":{"if":[{"in":["@openfeature.dev",{"var":"email"}]},"second",{"in":["Chrome",{"var":"userAgent"}]},"third",null]}}},"$evaluators":{"emailWithFaas":{"in":["@faas.com",{"var":["email"]}]}}}`;
6-
let core: FlagdCore;
7-
8-
beforeAll(() => {
9-
core = new FlagdCore();
10-
core.setConfigurations(flagCfg);
11-
});
12-
13-
it('should resolve boolean flag', () => {
14-
const resolved = core.resolveBooleanEvaluation('myBoolFlag', false, {}, console);
15-
expect(resolved.value).toBeTruthy();
16-
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
17-
expect(resolved.variant).toBe('on');
18-
});
19-
20-
it('should resolve string flag', () => {
21-
const resolved = core.resolveStringEvaluation('myStringFlag', 'key2', {}, console);
22-
expect(resolved.value).toBe('val1');
23-
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
24-
expect(resolved.variant).toBe('key1');
25-
});
26-
27-
it('should resolve number flag', () => {
28-
const resolved = core.resolveNumberEvaluation('myFloatFlag', 2.34, {}, console);
29-
expect(resolved.value).toBe(1.23);
30-
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
31-
expect(resolved.variant).toBe('one');
5+
describe('truthy variant values', () => {
6+
const flagCfg = `{"flags":{"myBoolFlag":{"state":"ENABLED","variants":{"on":true,"off":false},"defaultVariant":"on"},"myStringFlag":{"state":"ENABLED","variants":{"key1":"val1","key2":"val2"},"defaultVariant":"key1"},"myFloatFlag":{"state":"ENABLED","variants":{"one":1.23,"two":2.34},"defaultVariant":"one"},"myIntFlag":{"state":"ENABLED","variants":{"one":1,"two":2},"defaultVariant":"one"},"myObjectFlag":{"state":"ENABLED","variants":{"object1":{"key":"val"},"object2":{"key":true}},"defaultVariant":"object1"},"fibAlgo":{"variants":{"recursive":"recursive","memo":"memo","loop":"loop","binet":"binet"},"defaultVariant":"recursive","state":"ENABLED","targeting":{"if":[{"$ref":"emailWithFaas"},"binet",null]}},"targetedFlag":{"variants":{"first":"AAA","second":"BBB","third":"CCC"},"defaultVariant":"first","state":"ENABLED","targeting":{"if":[{"in":["@openfeature.dev",{"var":"email"}]},"second",{"in":["Chrome",{"var":"userAgent"}]},"third",null]}}},"$evaluators":{"emailWithFaas":{"in":["@faas.com",{"var":["email"]}]}}}`;
7+
let core: FlagdCore;
8+
9+
beforeAll(() => {
10+
core = new FlagdCore();
11+
core.setConfigurations(flagCfg);
12+
});
13+
14+
it('should resolve boolean flag', () => {
15+
const resolved = core.resolveBooleanEvaluation('myBoolFlag', false, {}, console);
16+
expect(resolved.value).toBe(true);
17+
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
18+
expect(resolved.variant).toBe('on');
19+
});
20+
21+
it('should resolve string flag', () => {
22+
const resolved = core.resolveStringEvaluation('myStringFlag', 'key2', {}, console);
23+
expect(resolved.value).toBe('val1');
24+
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
25+
expect(resolved.variant).toBe('key1');
26+
});
27+
28+
it('should resolve number flag', () => {
29+
const resolved = core.resolveNumberEvaluation('myFloatFlag', 2.34, {}, console);
30+
expect(resolved.value).toBe(1.23);
31+
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
32+
expect(resolved.variant).toBe('one');
33+
});
34+
35+
it('should resolve object flag', () => {
36+
const resolved = core.resolveObjectEvaluation('myObjectFlag', { key: true }, {}, console);
37+
expect(resolved.value).toStrictEqual({ key: 'val' });
38+
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
39+
expect(resolved.variant).toBe('object1');
40+
});
3241
});
3342

34-
it('should resolve object flag', () => {
35-
const resolved = core.resolveObjectEvaluation('myObjectFlag', { key: true }, {}, console);
36-
expect(resolved.value).toStrictEqual({ key: 'val' });
37-
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
38-
expect(resolved.variant).toBe('object1');
43+
describe('falsy variant values', () => {
44+
const flagCfg = `{"flags":{"myBoolFlag":{"state":"ENABLED","variants":{"on":true,"off":false},"defaultVariant":"off"},"myStringFlag":{"state":"ENABLED","variants":{"key1":"","key2":""},"defaultVariant":"key1"},"myFloatFlag":{"state":"ENABLED","variants":{"zero":0.0,"one":1.34},"defaultVariant":"zero"},"myIntFlag":{"state":"ENABLED","variants":{"zero":0,"one":1},"defaultVariant":"zero"},"myObjectFlag":{"state":"ENABLED","variants":{"object1":{},"object2":{"key":true}},"defaultVariant":"object1"},"fibAlgo":{"variants":{"recursive":"recursive","memo":"memo","loop":"loop","binet":"binet"},"defaultVariant":"recursive","state":"ENABLED","targeting":{"if":[{"$ref":"emailWithFaas"},"binet",null]}},"targetedFlag":{"variants":{"first":"AAA","second":"BBB","third":"CCC"},"defaultVariant":"first","state":"ENABLED","targeting":{"if":[{"in":["@openfeature.dev",{"var":"email"}]},"second",{"in":["Chrome",{"var":"userAgent"}]},"third",null]}}},"$evaluators":{"emailWithFaas":{"in":["@faas.com",{"var":["email"]}]}}}`;
45+
let core: FlagdCore;
46+
47+
beforeAll(() => {
48+
core = new FlagdCore();
49+
core.setConfigurations(flagCfg);
50+
});
51+
52+
it('should resolve boolean flag', () => {
53+
const resolved = core.resolveBooleanEvaluation('myBoolFlag', false, {}, console);
54+
expect(resolved.value).toBe(false);
55+
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
56+
expect(resolved.variant).toBe('off');
57+
});
58+
59+
it('should resolve string flag', () => {
60+
const resolved = core.resolveStringEvaluation('myStringFlag', 'key2', {}, console);
61+
expect(resolved.value).toBe('');
62+
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
63+
expect(resolved.variant).toBe('key1');
64+
});
65+
66+
it('should resolve number flag', () => {
67+
const resolved = core.resolveNumberEvaluation('myFloatFlag', 2.34, {}, console);
68+
expect(resolved.value).toBe(0);
69+
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
70+
expect(resolved.variant).toBe('zero');
71+
});
72+
73+
it('should resolve object flag', () => {
74+
const resolved = core.resolveObjectEvaluation('myObjectFlag', { key: true }, {}, console);
75+
expect(resolved.value).toStrictEqual({});
76+
expect(resolved.reason).toBe(StandardResolutionReasons.STATIC);
77+
expect(resolved.variant).toBe('object1');
78+
});
3979
});
4080
});
4181

libs/shared/flagd-core/src/lib/flagd-core.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export class FlagdCore {
120120
}
121121

122122
const resolvedVariant = flag.variants.get(variant);
123-
if (!resolvedVariant) {
123+
if (resolvedVariant === undefined) {
124124
throw new GeneralError(`Variant ${variant} not found in flag with key ${flagKey}`);
125125
}
126126

0 commit comments

Comments
 (0)