Skip to content

Commit 376ce71

Browse files
committed
fix filter parameter handling
1 parent 0ff2561 commit 376ce71

2 files changed

Lines changed: 75 additions & 15 deletions

File tree

src/featureManagement/featureFlagConverter.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,68 +15,69 @@ export function convertToMicrosoftSchema(featureFlag: FeatureFlag): any {
1515
enabled: featureFlag.enabled
1616
};
1717

18-
if (featureFlag.description !== undefined) {
18+
if (featureFlag.description != null) {
1919
result.description = featureFlag.description;
2020
}
2121

2222
// conditions: filters -> client_filters, requirementType -> requirement_type
2323
const conditions: any = {
2424
client_filters: (featureFlag.conditions?.filters ?? []).map(filter => {
2525
const clientFilter: any = { name: filter.name };
26-
if (filter.parameters !== undefined) {
27-
clientFilter.parameters = filter.parameters;
26+
if (filter.parameters != null) {
27+
clientFilter.parameters = Object.fromEntries(
28+
Object.entries(filter.parameters).map(([name, value]) => [name, JSON.parse(value)]));
2829
}
2930
return clientFilter;
3031
})
3132
};
32-
if (featureFlag.conditions?.requirementType !== undefined) {
33+
if (featureFlag.conditions?.requirementType != null) {
3334
conditions.requirement_type = featureFlag.conditions.requirementType;
3435
}
3536
result.conditions = conditions;
3637

3738
// variants: value -> configuration_value, statusOverride -> status_override
38-
if (featureFlag.variants !== undefined) {
39+
if (featureFlag.variants != null) {
3940
result.variants = featureFlag.variants.map(variant => {
4041
const result_variant: any = { name: variant.name };
4142
if (variant.value !== undefined) {
4243
result_variant.configuration_value = variant.value;
4344
}
44-
if (variant.statusOverride !== undefined) {
45+
if (variant.statusOverride != null) {
4546
result_variant.status_override = variant.statusOverride;
4647
}
4748
return result_variant;
4849
});
4950
}
5051

5152
// allocation: camelCase -> snake_case
52-
if (featureFlag.allocation !== undefined) {
53+
if (featureFlag.allocation != null) {
5354
const allocation: any = {};
5455
const sourceAllocation = featureFlag.allocation;
55-
if (sourceAllocation.defaultWhenDisabled !== undefined) {
56+
if (sourceAllocation.defaultWhenDisabled != null) {
5657
allocation.default_when_disabled = sourceAllocation.defaultWhenDisabled;
5758
}
58-
if (sourceAllocation.defaultWhenEnabled !== undefined) {
59+
if (sourceAllocation.defaultWhenEnabled != null) {
5960
allocation.default_when_enabled = sourceAllocation.defaultWhenEnabled;
6061
}
61-
if (sourceAllocation.percentile !== undefined) {
62+
if (sourceAllocation.percentile != null) {
6263
allocation.percentile = sourceAllocation.percentile.map(p => ({ variant: p.variant, from: p.from, to: p.to }));
6364
}
64-
if (sourceAllocation.user !== undefined) {
65+
if (sourceAllocation.user != null) {
6566
allocation.user = sourceAllocation.user.map(u => ({ variant: u.variant, users: u.users }));
6667
}
67-
if (sourceAllocation.group !== undefined) {
68+
if (sourceAllocation.group != null) {
6869
allocation.group = sourceAllocation.group.map(g => ({ variant: g.variant, groups: g.groups }));
6970
}
70-
if (sourceAllocation.seed !== undefined) {
71+
if (sourceAllocation.seed != null) {
7172
allocation.seed = sourceAllocation.seed;
7273
}
7374
result.allocation = allocation;
7475
}
7576

7677
// telemetry: metadata is (re)populated later by the provider with ETag/FeatureFlagReference/AllocationId
77-
if (featureFlag.telemetry !== undefined) {
78+
if (featureFlag.telemetry != null) {
7879
const telemetry: any = { enabled: featureFlag.telemetry.enabled };
79-
if (featureFlag.telemetry.metadata !== undefined) {
80+
if (featureFlag.telemetry.metadata != null) {
8081
telemetry.metadata = featureFlag.telemetry.metadata;
8182
}
8283
result.telemetry = telemetry;

test/featureFlag.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,65 @@ describe("enhanced feature flags", function () {
524524
expect(featureFlags.find(ff => ff.id === "NewBeta").enabled).equals(false);
525525
});
526526

527+
it("should load an enhanced feature flag with null optional fields", async () => {
528+
mockAppConfigurationClientListConfigurationSettings([[]], undefined, [[
529+
createMockedEnhancedFeatureFlag("Minimal", {
530+
description: null,
531+
conditions: null,
532+
variants: null,
533+
allocation: null,
534+
telemetry: null
535+
})
536+
]]);
537+
538+
const settings = await load(createMockedConnectionString(), {
539+
featureFlagOptions: { enabled: true }
540+
});
541+
542+
const featureFlag = (settings.get<any>("feature_management").feature_flags as any[])
543+
.find(ff => ff.id === "Minimal");
544+
expect(featureFlag).not.undefined;
545+
expect(featureFlag.conditions.client_filters).deep.equals([]);
546+
expect(featureFlag).not.have.property("description");
547+
expect(featureFlag).not.have.property("variants");
548+
expect(featureFlag).not.have.property("allocation");
549+
expect(featureFlag).not.have.property("telemetry");
550+
});
551+
552+
it("should parse enhanced feature flag filter parameters", async () => {
553+
const audience = {
554+
Users: ["test@contoso.com"],
555+
Groups: [{ Name: "contoso.com", RolloutPercentage: 50 }],
556+
DefaultRolloutPercentage: 0
557+
};
558+
mockAppConfigurationClientListConfigurationSettings([[]], undefined, [[
559+
createMockedEnhancedFeatureFlag("Targeted", {
560+
conditions: {
561+
requirementType: "Any",
562+
filters: [{
563+
name: "Microsoft.Targeting",
564+
parameters: {
565+
Audience: JSON.stringify(audience),
566+
PlainText: "not-json",
567+
Percentage: "50"
568+
}
569+
}]
570+
}
571+
})
572+
]]);
573+
574+
const settings = await load(createMockedConnectionString(), {
575+
featureFlagOptions: { enabled: true }
576+
});
577+
578+
const featureFlag = (settings.get<any>("feature_management").feature_flags as any[])
579+
.find(ff => ff.id === "Targeted");
580+
const parameters = featureFlag.conditions.client_filters[0].parameters;
581+
expect(parameters.Audience).deep.equals(audience);
582+
expect(parameters.PlainText).equals("not-json");
583+
expect(parameters.Percentage).equals(50);
584+
});
585+
527586
it("should let an enhanced feature flag supersede a feature flag with the same name", async () => {
528587
// "Shared" is enabled and "ClassicOnly" exists; the dedicated endpoint returns "Shared" disabled
529588
const featureFlagSettings = [

0 commit comments

Comments
 (0)