Skip to content

Commit 4ce2b95

Browse files
authored
test: Add missing gherkin tests (#390)
<!-- 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 includes several changes aimed at improving the test setup, enhancing the metadata handling, and refactoring the code for better readability and maintainability. ### Test Setup Improvements: * [`.github/workflows/e2e.yml`](diffhunk://#diff-3e103440521ada06efd263ae09b259e5507e4b8f7408308dc227621ad9efa31eL34-R34): Updated the `Initialize Tests` step to copy all Gherkin feature files instead of just `evaluation.feature`. * [`test/OpenFeature.E2ETests/OpenFeature.E2ETests.csproj`](diffhunk://#diff-ab2ad60395e1cc72b327459243ed8c5711efbd88531a3b3b813fb6c4c6019886R32-R38): Added a new `GherkinRestore` target to copy Gherkin files before the build. ### Metadata Handling Enhancements: * [`src/OpenFeature/Model/ImmutableMetadata.cs`](diffhunk://#diff-bf57504fda39c85dbda91d3829514b8b014f1293e5b5e53e490f4f4b74f0905bR88-R89): Added an internal `Count` property to the `ImmutableMetadata` class. * [`src/OpenFeature/Providers/Memory/Flag.cs`](diffhunk://#diff-ba67e6465022bead062d71042b8f5d67b47ec11e06c4eefe2b9f473ac34fc8d1R22-R36): Introduced an optional `flagMetadata` parameter to the `Flag` class and updated the `Evaluate` method to include `flagMetadata` in the `ResolutionDetails`. [[1]](diffhunk://#diff-ba67e6465022bead062d71042b8f5d67b47ec11e06c4eefe2b9f473ac34fc8d1R22-R36) [[2]](diffhunk://#diff-ba67e6465022bead062d71042b8f5d67b47ec11e06c4eefe2b9f473ac34fc8d1L47-R51) [[3]](diffhunk://#diff-ba67e6465022bead062d71042b8f5d67b47ec11e06c4eefe2b9f473ac34fc8d1L68-R73) ### Code Refactoring: * [`build/Common.tests.props`](diffhunk://#diff-5472aa271be4e6ac0c793a3c1b9226e4f9a7907a6baa99ea16542fb89107ae86L8-R12): Simplified the condition for identifying test projects by removing the dot before 'Tests'. * [`test/OpenFeature.E2ETests/Steps/EvaluationStepDefinitions.cs`](diffhunk://#diff-9ca6e89533e4b3f7a2deaf8de6d6f07a80b7eab2afa6f2e8bfc682b9ca60dc6bL10-R103): Refactored the class to use private fields with underscore prefixes for better readability and consistency. [[1]](diffhunk://#diff-9ca6e89533e4b3f7a2deaf8de6d6f07a80b7eab2afa6f2e8bfc682b9ca60dc6bL10-R103) [[2]](diffhunk://#diff-9ca6e89533e4b3f7a2deaf8de6d6f07a80b7eab2afa6f2e8bfc682b9ca60dc6bL115-R118) [[3]](diffhunk://#diff-9ca6e89533e4b3f7a2deaf8de6d6f07a80b7eab2afa6f2e8bfc682b9ca60dc6bL130-R133) [[4]](diffhunk://#diff-9ca6e89533e4b3f7a2deaf8de6d6f07a80b7eab2afa6f2e8bfc682b9ca60dc6bL145-R148) [[5]](diffhunk://#diff-9ca6e89533e4b3f7a2deaf8de6d6f07a80b7eab2afa6f2e8bfc682b9ca60dc6bL160-R163) [[6]](diffhunk://#diff-9ca6e89533e4b3f7a2deaf8de6d6f07a80b7eab2afa6f2e8bfc682b9ca60dc6bL175-R178) [[7]](diffhunk://#diff-9ca6e89533e4b3f7a2deaf8de6d6f07a80b7eab2afa6f2e8bfc682b9ca60dc6bL190-R194) ### Related Issues <!-- add here the GitHub issue that this PR resolves if applicable --> Fixes #376 ### Follow-up Tasks - Cleanup `test/OpenFeature.E2ETests/Steps/EvaluationStepDefinitions.cs` file. It should apply the same patterns as discussed in the PR. See #391 --------- Signed-off-by: André Silva <2493377+askpt@users.noreply.github.com>
1 parent 85075ac commit 4ce2b95

14 files changed

Lines changed: 544 additions & 79 deletions

File tree

.github/workflows/e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
- name: Initialize Tests
3232
run: |
3333
git submodule update --init --recursive
34-
cp spec/specification/assets/gherkin/evaluation.feature test/OpenFeature.E2ETests/Features/
34+
cp spec/specification/assets/gherkin/*.feature test/OpenFeature.E2ETests/Features/
3535
3636
- name: Run Tests
3737
run: dotnet test test/OpenFeature.E2ETests/ --configuration Release --logger GitHubActions

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ ASALocalRun/
350350
!.vscode/extensions.json
351351

352352
# integration tests
353-
test/OpenFeature.E2ETests/Features/evaluation.feature
354-
test/OpenFeature.E2ETests/Features/evaluation.feature.cs
353+
test/OpenFeature.E2ETests/Features/*.feature
354+
test/OpenFeature.E2ETests/Features/*.feature.cs
355355
cs-report.json
356356
specification.json

build/Common.tests.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
<IsPackable>false</IsPackable>
66
</PropertyGroup>
77

8-
<PropertyGroup Condition="$(MSBuildProjectName.EndsWith('.Tests'))">
8+
<PropertyGroup Condition="$(MSBuildProjectName.EndsWith('Tests'))">
99
<IsTestProject>true</IsTestProject>
1010
</PropertyGroup>
1111

12-
<ItemGroup Condition="$(MSBuildProjectName.EndsWith('.Tests'))">
12+
<ItemGroup Condition="$(MSBuildProjectName.EndsWith('Tests'))">
1313
<Content Include="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'OpenFeature.sln'))\build\xunit.runner.json">
1414
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
1515
</Content>

build/xunit.runner.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
22
"maxParallelThreads": 1,
3-
"parallelizeTestCollections": false
4-
}
3+
"parallelizeTestCollections": false,
4+
"parallelizeAssembly": false
5+
}

src/OpenFeature/Model/ImmutableMetadata.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,6 @@ public ImmutableMetadata(Dictionary<string, object> metadata)
8585

8686
return value is T tValue ? tValue : null;
8787
}
88+
89+
internal int Count => this._metadata.Count;
8890
}

src/OpenFeature/Providers/Memory/Flag.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,21 @@ public sealed class Flag<T> : Flag
1919
private readonly Dictionary<string, T> _variants;
2020
private readonly string _defaultVariant;
2121
private readonly Func<EvaluationContext, string>? _contextEvaluator;
22+
private readonly ImmutableMetadata? _flagMetadata;
2223

2324
/// <summary>
2425
/// Flag representation for the in-memory provider.
2526
/// </summary>
2627
/// <param name="variants">dictionary of variants and their corresponding values</param>
2728
/// <param name="defaultVariant">default variant (should match 1 key in variants dictionary)</param>
2829
/// <param name="contextEvaluator">optional context-sensitive evaluation function</param>
29-
public Flag(Dictionary<string, T> variants, string defaultVariant, Func<EvaluationContext, string>? contextEvaluator = null)
30+
/// <param name="flagMetadata">optional metadata for the flag</param>
31+
public Flag(Dictionary<string, T> variants, string defaultVariant, Func<EvaluationContext, string>? contextEvaluator = null, ImmutableMetadata? flagMetadata = null)
3032
{
3133
this._variants = variants;
3234
this._defaultVariant = defaultVariant;
3335
this._contextEvaluator = contextEvaluator;
36+
this._flagMetadata = flagMetadata;
3437
}
3538

3639
internal ResolutionDetails<T> Evaluate(string flagKey, T _, EvaluationContext? evaluationContext)
@@ -44,7 +47,8 @@ internal ResolutionDetails<T> Evaluate(string flagKey, T _, EvaluationContext? e
4447
flagKey,
4548
value,
4649
variant: this._defaultVariant,
47-
reason: Reason.Static
50+
reason: Reason.Static,
51+
flagMetadata: this._flagMetadata
4852
);
4953
}
5054
else
@@ -65,7 +69,8 @@ internal ResolutionDetails<T> Evaluate(string flagKey, T _, EvaluationContext? e
6569
flagKey,
6670
value,
6771
variant: variant,
68-
reason: Reason.TargetingMatch
72+
reason: Reason.TargetingMatch,
73+
flagMetadata: this._flagMetadata
6974
);
7075
}
7176
}

test/OpenFeature.E2ETests/OpenFeature.E2ETests.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,11 @@
2929
<ProjectReference Include="..\..\src\OpenFeature\OpenFeature.csproj" />
3030
</ItemGroup>
3131

32+
<Target Name="GherkinRestore" BeforeTargets="CoreBuild">
33+
<ItemGroup>
34+
<GherkinFiles Include="..\..\spec\specification\assets\gherkin\*" />
35+
</ItemGroup>
36+
<Copy SourceFiles="@(GherkinFiles)" DestinationFolder="Features/"/>
37+
</Target>
38+
3239
</Project>
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using OpenFeature.E2ETests.Utils;
4+
using OpenFeature.Model;
5+
using OpenFeature.Providers.Memory;
6+
using Reqnroll;
7+
8+
namespace OpenFeature.E2ETests.Steps;
9+
10+
[Binding]
11+
public class BaseStepDefinitions
12+
{
13+
internal FeatureClient? Client;
14+
private string _flagKey = null!;
15+
private string _defaultValue = null!;
16+
internal FlagType? FlagTypeEnum;
17+
internal object Result = null!;
18+
19+
[Given(@"a stable provider")]
20+
public void GivenAStableProvider()
21+
{
22+
var memProvider = new InMemoryProvider(E2EFlagConfig);
23+
Api.Instance.SetProviderAsync(memProvider).Wait();
24+
this.Client = Api.Instance.GetClient("TestClient", "1.0.0");
25+
}
26+
27+
[Given(@"a Boolean-flag with key ""(.*)"" and a default value ""(.*)""")]
28+
[Given(@"a boolean-flag with key ""(.*)"" and a default value ""(.*)""")]
29+
public void GivenABoolean_FlagWithKeyAndADefaultValue(string key, string defaultType)
30+
{
31+
this._flagKey = key;
32+
this._defaultValue = defaultType;
33+
this.FlagTypeEnum = FlagType.Boolean;
34+
}
35+
36+
[Given(@"a Float-flag with key ""(.*)"" and a default value ""(.*)""")]
37+
[Given(@"a float-flag with key ""(.*)"" and a default value ""(.*)""")]
38+
public void GivenAFloat_FlagWithKeyAndADefaultValue(string key, string defaultType)
39+
{
40+
this._flagKey = key;
41+
this._defaultValue = defaultType;
42+
this.FlagTypeEnum = FlagType.Float;
43+
}
44+
45+
[Given(@"a Integer-flag with key ""(.*)"" and a default value ""(.*)""")]
46+
[Given(@"a integer-flag with key ""(.*)"" and a default value ""(.*)""")]
47+
public void GivenAnInteger_FlagWithKeyAndADefaultValue(string key, string defaultType)
48+
{
49+
this._flagKey = key;
50+
this._defaultValue = defaultType;
51+
this.FlagTypeEnum = FlagType.Integer;
52+
}
53+
54+
[Given(@"a String-flag with key ""(.*)"" and a default value ""(.*)""")]
55+
[Given(@"a string-flag with key ""(.*)"" and a default value ""(.*)""")]
56+
public void GivenAString_FlagWithKeyAndADefaultValue(string key, string defaultType)
57+
{
58+
this._flagKey = key;
59+
this._defaultValue = defaultType;
60+
this.FlagTypeEnum = FlagType.String;
61+
}
62+
63+
[When(@"the flag was evaluated with details")]
64+
public async Task WhenTheFlagWasEvaluatedWithDetails()
65+
{
66+
switch (this.FlagTypeEnum)
67+
{
68+
case FlagType.Boolean:
69+
this.Result = await this.Client!
70+
.GetBooleanDetailsAsync(this._flagKey, bool.Parse(this._defaultValue)).ConfigureAwait(false);
71+
break;
72+
case FlagType.Float:
73+
this.Result = await this.Client!
74+
.GetDoubleDetailsAsync(this._flagKey, double.Parse(this._defaultValue)).ConfigureAwait(false);
75+
break;
76+
case FlagType.Integer:
77+
this.Result = await this.Client!
78+
.GetIntegerDetailsAsync(this._flagKey, int.Parse(this._defaultValue)).ConfigureAwait(false);
79+
break;
80+
case FlagType.String:
81+
this.Result = await this.Client!.GetStringDetailsAsync(this._flagKey, this._defaultValue)
82+
.ConfigureAwait(false);
83+
break;
84+
}
85+
}
86+
87+
private static readonly IDictionary<string, Flag> E2EFlagConfig = new Dictionary<string, Flag>
88+
{
89+
{
90+
"metadata-flag", new Flag<bool>(
91+
variants: new Dictionary<string, bool> { { "on", true }, { "off", false } },
92+
defaultVariant: "on",
93+
flagMetadata: new ImmutableMetadata(new Dictionary<string, object>
94+
{
95+
{ "string", "1.0.2" }, { "integer", 2 }, { "float", 0.1 }, { "boolean", true }
96+
})
97+
)
98+
},
99+
{
100+
"boolean-flag", new Flag<bool>(
101+
variants: new Dictionary<string, bool> { { "on", true }, { "off", false } },
102+
defaultVariant: "on"
103+
)
104+
},
105+
{
106+
"integer-flag", new Flag<int>(
107+
variants: new Dictionary<string, int> { { "23", 23 }, { "42", 42 } },
108+
defaultVariant: "23"
109+
)
110+
},
111+
{
112+
"float-flag", new Flag<double>(
113+
variants: new Dictionary<string, double> { { "2.3", 2.3 }, { "4.2", 4.2 } },
114+
defaultVariant: "2.3"
115+
)
116+
},
117+
{
118+
"string-flag", new Flag<string>(
119+
variants: new Dictionary<string, string> { { "value", "value" }, { "value2", "value2" } },
120+
defaultVariant: "value"
121+
)
122+
}
123+
};
124+
}

0 commit comments

Comments
 (0)