Skip to content

Commit 074de3d

Browse files
authored
test: Update Evaluation Definitions (#394)
<!-- Please use this template for your pull request. --> <!-- Please use the sections that you need and delete other sections --> ## This PR <!-- add the description of the PR here --> This pull request introduces several changes to the `OpenFeature.E2ETests` project, focusing on enhancing configuration and refactoring the step definitions for better state management and code clarity. The most important changes include updates to the VS Code configuration files, refactoring of the `BaseStepDefinitions` and `EvaluationStepDefinitions` classes, and enhancements to the feature flag evaluation logic. Configuration updates: * [`.vscode/extensions.json`](diffhunk://#diff-c16655a98a3ee89a7636a59c59a72b0e93649e3a1e947327cfc43a1336b4e912R1-R6): Added recommendations for the `cucumberopen.cucumber-official` and `ms-dotnettools.csdevkit` extensions. * [`.vscode/settings.json`](diffhunk://#diff-a5de3e5871ffcc383a2294845bd3df25d3eeff6c29ad46e3a396577c413bf357R1-R22): Enabled file nesting, added patterns for feature files, and excluded compilation results and other unnecessary files. Refactoring step definitions: * [`test/OpenFeature.E2ETests/Steps/BaseStepDefinitions.cs`](diffhunk://#diff-d602b805929d1f2c0a4e819949274cd996296363676f8f59efd1b2997845f46aL13-R80): Refactored to use a shared `State` class for managing feature flag state and evaluation results, replacing internal variables with properties of the `State` class. * [`test/OpenFeature.E2ETests/Steps/EvaluationStepDefinitions.cs`](diffhunk://#diff-9ca6e89533e4b3f7a2deaf8de6d6f07a80b7eab2afa6f2e8bfc682b9ca60dc6bL1-R167): Refactored to inherit from `BaseStepDefinitions`, using the shared `State` class for managing state and results, and converting synchronous methods to asynchronous. Enhancements to feature flag evaluation: * [`test/OpenFeature.E2ETests/Steps/BaseStepDefinitions.cs`](diffhunk://#diff-d602b805929d1f2c0a4e819949274cd996296363676f8f59efd1b2997845f46aL13-R80): Improved the flag evaluation logic by encapsulating flag properties in a `FlagState` class and updating the evaluation methods to use this new structure. * [`test/OpenFeature.E2ETests/Steps/BaseStepDefinitions.cs`](diffhunk://#diff-d602b805929d1f2c0a4e819949274cd996296363676f8f59efd1b2997845f46aR104-R158): Added new flag variants and context-aware flag evaluation logic to handle more complex scenarios. ### Related Issues <!-- add here the GitHub issue that this PR resolves if applicable --> Fixes #391 --------- Signed-off-by: André Silva <2493377+askpt@users.noreply.github.com>
1 parent b30350b commit 074de3d

11 files changed

Lines changed: 418 additions & 399 deletions

.vscode/extensions.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"recommendations": [
3+
"cucumberopen.cucumber-official",
4+
"ms-dotnettools.csdevkit"
5+
]
6+
}

.vscode/settings.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"explorer.fileNesting.enabled": true,
3+
"explorer.fileNesting.patterns": {
4+
// shows *.feature.cs files as nested items
5+
"*.feature": "${capture}.feature.cs"
6+
},
7+
"files.exclude": {
8+
// excludes compilation result
9+
"**/obj/": true,
10+
"**/bin/": true,
11+
"BenchmarkDotNet.Artifacts/": true,
12+
".idea/": true
13+
},
14+
"cucumber.glue": [
15+
// sets the location of the step definition classes
16+
"test/OpenFeature.E2ETests/Steps/*.cs"
17+
],
18+
"cucumber.features": [
19+
// sets the location of the feature files
20+
"test/OpenFeature.E2ETests/Features/*.feature"
21+
]
22+
}

test/OpenFeature.E2ETests/Steps/BaseStepDefinitions.cs

Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,75 +10,74 @@ namespace OpenFeature.E2ETests.Steps;
1010
[Binding]
1111
public class BaseStepDefinitions
1212
{
13-
internal FeatureClient? Client;
14-
private string _flagKey = null!;
15-
private string _defaultValue = null!;
16-
internal FlagType? FlagTypeEnum;
17-
internal object Result = null!;
13+
protected readonly State State;
14+
15+
public BaseStepDefinitions(State state)
16+
{
17+
this.State = state;
18+
}
1819

1920
[Given(@"a stable provider")]
2021
public void GivenAStableProvider()
2122
{
2223
var memProvider = new InMemoryProvider(E2EFlagConfig);
2324
Api.Instance.SetProviderAsync(memProvider).Wait();
24-
this.Client = Api.Instance.GetClient("TestClient", "1.0.0");
25+
this.State.Client = Api.Instance.GetClient("TestClient", "1.0.0");
2526
}
2627

2728
[Given(@"a Boolean-flag with key ""(.*)"" and a default value ""(.*)""")]
2829
[Given(@"a boolean-flag with key ""(.*)"" and a default value ""(.*)""")]
2930
public void GivenABoolean_FlagWithKeyAndADefaultValue(string key, string defaultType)
3031
{
31-
this._flagKey = key;
32-
this._defaultValue = defaultType;
33-
this.FlagTypeEnum = FlagType.Boolean;
32+
var flagState = new FlagState(key, defaultType, FlagType.Boolean);
33+
this.State.Flag = flagState;
3434
}
3535

3636
[Given(@"a Float-flag with key ""(.*)"" and a default value ""(.*)""")]
3737
[Given(@"a float-flag with key ""(.*)"" and a default value ""(.*)""")]
3838
public void GivenAFloat_FlagWithKeyAndADefaultValue(string key, string defaultType)
3939
{
40-
this._flagKey = key;
41-
this._defaultValue = defaultType;
42-
this.FlagTypeEnum = FlagType.Float;
40+
var flagState = new FlagState(key, defaultType, FlagType.Float);
41+
this.State.Flag = flagState;
4342
}
4443

4544
[Given(@"a Integer-flag with key ""(.*)"" and a default value ""(.*)""")]
4645
[Given(@"a integer-flag with key ""(.*)"" and a default value ""(.*)""")]
4746
public void GivenAnInteger_FlagWithKeyAndADefaultValue(string key, string defaultType)
4847
{
49-
this._flagKey = key;
50-
this._defaultValue = defaultType;
51-
this.FlagTypeEnum = FlagType.Integer;
48+
var flagState = new FlagState(key, defaultType, FlagType.Integer);
49+
this.State.Flag = flagState;
5250
}
5351

5452
[Given(@"a String-flag with key ""(.*)"" and a default value ""(.*)""")]
5553
[Given(@"a string-flag with key ""(.*)"" and a default value ""(.*)""")]
5654
public void GivenAString_FlagWithKeyAndADefaultValue(string key, string defaultType)
5755
{
58-
this._flagKey = key;
59-
this._defaultValue = defaultType;
60-
this.FlagTypeEnum = FlagType.String;
56+
var flagState = new FlagState(key, defaultType, FlagType.String);
57+
this.State.Flag = flagState;
6158
}
6259

6360
[When(@"the flag was evaluated with details")]
6461
public async Task WhenTheFlagWasEvaluatedWithDetails()
6562
{
66-
switch (this.FlagTypeEnum)
63+
var flag = this.State.Flag!;
64+
65+
switch (flag.Type)
6766
{
6867
case FlagType.Boolean:
69-
this.Result = await this.Client!
70-
.GetBooleanDetailsAsync(this._flagKey, bool.Parse(this._defaultValue)).ConfigureAwait(false);
68+
this.State.FlagEvaluationDetailsResult = await this.State.Client!
69+
.GetBooleanDetailsAsync(flag.Key, bool.Parse(flag.DefaultValue)).ConfigureAwait(false);
7170
break;
7271
case FlagType.Float:
73-
this.Result = await this.Client!
74-
.GetDoubleDetailsAsync(this._flagKey, double.Parse(this._defaultValue)).ConfigureAwait(false);
72+
this.State.FlagEvaluationDetailsResult = await this.State.Client!
73+
.GetDoubleDetailsAsync(flag.Key, double.Parse(flag.DefaultValue)).ConfigureAwait(false);
7574
break;
7675
case FlagType.Integer:
77-
this.Result = await this.Client!
78-
.GetIntegerDetailsAsync(this._flagKey, int.Parse(this._defaultValue)).ConfigureAwait(false);
76+
this.State.FlagEvaluationDetailsResult = await this.State.Client!
77+
.GetIntegerDetailsAsync(flag.Key, int.Parse(flag.DefaultValue)).ConfigureAwait(false);
7978
break;
8079
case FlagType.String:
81-
this.Result = await this.Client!.GetStringDetailsAsync(this._flagKey, this._defaultValue)
80+
this.State.FlagEvaluationDetailsResult = await this.State.Client!.GetStringDetailsAsync(flag.Key, flag.DefaultValue)
8281
.ConfigureAwait(false);
8382
break;
8483
}
@@ -102,22 +101,61 @@ public async Task WhenTheFlagWasEvaluatedWithDetails()
102101
defaultVariant: "on"
103102
)
104103
},
104+
{
105+
"string-flag", new Flag<string>(
106+
variants: new Dictionary<string, string>() { { "greeting", "hi" }, { "parting", "bye" } },
107+
defaultVariant: "greeting"
108+
)
109+
},
105110
{
106111
"integer-flag", new Flag<int>(
107-
variants: new Dictionary<string, int> { { "23", 23 }, { "42", 42 } },
108-
defaultVariant: "23"
112+
variants: new Dictionary<string, int>() { { "one", 1 }, { "ten", 10 } },
113+
defaultVariant: "ten"
109114
)
110115
},
111116
{
112117
"float-flag", new Flag<double>(
113-
variants: new Dictionary<string, double> { { "2.3", 2.3 }, { "4.2", 4.2 } },
114-
defaultVariant: "2.3"
118+
variants: new Dictionary<string, double>() { { "tenth", 0.1 }, { "half", 0.5 } },
119+
defaultVariant: "half"
115120
)
116121
},
117122
{
118-
"string-flag", new Flag<string>(
119-
variants: new Dictionary<string, string> { { "value", "value" }, { "value2", "value2" } },
120-
defaultVariant: "value"
123+
"object-flag", new Flag<Value>(
124+
variants: new Dictionary<string, Value>()
125+
{
126+
{ "empty", new Value() },
127+
{
128+
"template", new Value(Structure.Builder()
129+
.Set("showImages", true)
130+
.Set("title", "Check out these pics!")
131+
.Set("imagesPerPage", 100).Build()
132+
)
133+
}
134+
},
135+
defaultVariant: "template"
136+
)
137+
},
138+
{
139+
"context-aware", new Flag<string>(
140+
variants: new Dictionary<string, string>() { { "internal", "INTERNAL" }, { "external", "EXTERNAL" } },
141+
defaultVariant: "external",
142+
(context) =>
143+
{
144+
if (context.GetValue("fn").AsString == "Sulisław"
145+
&& context.GetValue("ln").AsString == "Świętopełk"
146+
&& context.GetValue("age").AsInteger == 29
147+
&& context.GetValue("customer").AsBoolean == false)
148+
{
149+
return "internal";
150+
}
151+
else return "external";
152+
}
153+
)
154+
},
155+
{
156+
"wrong-flag", new Flag<string>(
157+
variants: new Dictionary<string, string>() { { "one", "uno" }, { "two", "dos" } },
158+
defaultVariant: "one"
121159
)
122160
}
123161
};

0 commit comments

Comments
 (0)