Skip to content

Commit ea616c6

Browse files
Convert to integration tests
1 parent 7cf2690 commit ea616c6

File tree

9 files changed

+196
-150
lines changed

9 files changed

+196
-150
lines changed

fixtures/evaluation.json

Lines changed: 0 additions & 121 deletions
This file was deleted.

fixtures/evaluation/cases.json

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
[
2+
{
3+
"description": "enabled when the evaluation context matches its required segment",
4+
"configuration": {
5+
"slug": "feature-a",
6+
"context": { "license": "trial" },
7+
"defaultValue": false
8+
},
9+
"expected": {
10+
"value": true
11+
}
12+
},
13+
{
14+
"description": "disabled when the evaluation context does not match its required segment",
15+
"configuration": {
16+
"slug": "feature-a",
17+
"context": { "license": "enterprise" },
18+
"defaultValue": false
19+
},
20+
"expected": {
21+
"value": false
22+
}
23+
},
24+
{
25+
"description": "disabled when no evaluation context is provided and toggle has required segments",
26+
"configuration": {
27+
"slug": "feature-a",
28+
"defaultValue": false
29+
},
30+
"expected": {
31+
"value": false
32+
}
33+
},
34+
{
35+
"description": "enabled when context matches one value from a multi-value segment key",
36+
"configuration": {
37+
"slug": "feature-b",
38+
"context": { "region": "us" },
39+
"defaultValue": false
40+
},
41+
"expected": {
42+
"value": true
43+
}
44+
},
45+
{
46+
"description": "enabled regardless of context when toggle has no required segments",
47+
"configuration": {
48+
"slug": "feature-c",
49+
"defaultValue": false
50+
},
51+
"expected": {
52+
"value": true
53+
}
54+
},
55+
{
56+
"description": "disabled when toggle is not enabled regardless of context",
57+
"configuration": {
58+
"slug": "feature-d",
59+
"context": {},
60+
"defaultValue": false
61+
},
62+
"expected": {
63+
"value": false
64+
}
65+
},
66+
{
67+
"description": "returns FLAG_NOT_FOUND and default value when flag key is not a slug",
68+
"configuration": {
69+
"slug": "not a slug",
70+
"defaultValue": true
71+
},
72+
"expected": {
73+
"value": true,
74+
"errorCode": "FLAG_NOT_FOUND"
75+
}
76+
},
77+
{
78+
"description": "returns FLAG_NOT_FOUND and default value when slug does not match any toggle",
79+
"configuration": {
80+
"slug": "unknown-feature",
81+
"defaultValue": true
82+
},
83+
"expected": {
84+
"value": true,
85+
"errorCode": "FLAG_NOT_FOUND"
86+
}
87+
}
88+
]

fixtures/evaluation/toggles.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[
2+
{
3+
"name": "My Feature A",
4+
"slug": "feature-a",
5+
"isEnabled": true,
6+
"segments": [
7+
{ "key": "license", "value": "trial" }
8+
]
9+
},
10+
{
11+
"name": "My Feature B",
12+
"slug": "feature-b",
13+
"isEnabled": true,
14+
"segments": [
15+
{ "key": "region", "value": "us" },
16+
{ "key": "region", "value": "au" }
17+
]
18+
},
19+
{
20+
"name": "My Feature C",
21+
"slug": "feature-c",
22+
"isEnabled": true,
23+
"segments": []
24+
},
25+
{
26+
"name": "My Feature D",
27+
"slug": "feature-d",
28+
"isEnabled": false,
29+
"segments": []
30+
}
31+
]

src/Octopus.OpenFeature.Provider.Tests/FixtureEvaluationTests.cs renamed to src/Octopus.OpenFeature.Provider.IntegrationTests/FixtureEvaluationTests.cs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using System.Text.Json;
22
using FluentAssertions;
33
using FluentAssertions.Execution;
4-
using Microsoft.Extensions.Logging.Abstractions;
54
using OpenFeature.Constant;
65
using OpenFeature.Model;
6+
using WireMock.RequestBuilders;
7+
using WireMock.ResponseBuilders;
8+
using WireMock.Server;
79

8-
namespace Octopus.OpenFeature.Provider.Tests;
10+
namespace Octopus.OpenFeature.Provider.IntegrationTests;
911

1012
public class FixtureEvaluationTests
1113
{
@@ -14,55 +16,70 @@ public static TheoryData<FixtureTestData> GetTestCases()
1416
var data = new TheoryData<FixtureTestData>();
1517

1618
var fixtureDir = Path.Combine(AppContext.BaseDirectory, "Fixtures");
17-
foreach (var file in Directory.GetFiles(fixtureDir, "*.json"))
19+
foreach (var dir in Directory.GetDirectories(fixtureDir))
1820
{
19-
var json = File.ReadAllText(file);
20-
var fixture = JsonSerializer.Deserialize<FixtureFile>(json, JsonSerializerOptions.Web)
21-
?? throw new InvalidOperationException($"Failed to deserialize fixture file: {file}");
21+
var togglesJson = File.ReadAllText(Path.Combine(dir, "toggles.json"));
22+
var casesJson = File.ReadAllText(Path.Combine(dir, "cases.json"));
23+
var cases = JsonSerializer.Deserialize<FixtureCase[]>(casesJson, JsonSerializerOptions.Web)
24+
?? throw new InvalidOperationException($"Failed to deserialize cases in {dir}");
2225

23-
foreach (var testCase in fixture.Cases)
26+
foreach (var testCase in cases)
2427
{
25-
data.Add(new FixtureTestData(fixture.Toggles, testCase));
28+
data.Add(new FixtureTestData(togglesJson, testCase));
2629
}
27-
2830
}
2931

3032
return data;
3133
}
3234

3335
[Theory]
3436
[MemberData(nameof(GetTestCases))]
35-
public void Evaluate(FixtureTestData testData)
37+
public async Task Evaluate(FixtureTestData testData)
3638
{
37-
var toggles = new FeatureToggles(testData.Toggles, []);
38-
var featureContext = new OctopusFeatureContext(toggles, NullLoggerFactory.Instance);
39+
using var server = WireMockServer.Start();
40+
41+
server
42+
.Given(Request.Create().WithPath("/api/featuretoggles/v3/").UsingGet())
43+
.RespondWith(Response.Create()
44+
.WithStatusCode(200)
45+
.WithHeader("ContentHash", Convert.ToBase64String([0x01]))
46+
.WithBody(testData.TogglesJson));
47+
48+
var configuration = new OctopusFeatureConfiguration("test-identifier", new ProductMetadata("test-agent"))
49+
{
50+
ServerUri = new Uri(server.Url!)
51+
};
52+
53+
var provider = new OctopusFeatureProvider(configuration);
54+
await provider.InitializeAsync(EvaluationContext.Empty);
3955

4056
var evaluationContext = BuildContext(testData.Case.Configuration.Context);
4157

42-
var result = featureContext.Evaluate(
58+
var result = await provider.ResolveBooleanValueAsync(
4359
testData.Case.Configuration.Slug,
4460
testData.Case.Configuration.DefaultValue,
4561
evaluationContext);
4662

63+
await provider.ShutdownAsync();
64+
4765
using var scope = new AssertionScope(testData.Case.Description);
4866
result.Value.Should().Be(testData.Case.Expected.Value);
4967

5068
if (testData.Case.Expected.ErrorCode is { } errorCode)
5169
{
5270
result.ErrorType.Should().Be(MapErrorCode(errorCode));
5371
}
54-
5572
else
5673
{
5774
result.ErrorType.Should().Be(ErrorType.None);
5875
}
59-
6076
}
6177

6278
static EvaluationContext? BuildContext(Dictionary<string, string>? context)
6379
{
6480
if (context is null)
6581
{
82+
6683
return null;
6784
}
6885

@@ -85,11 +102,10 @@ public void Evaluate(FixtureTestData testData)
85102
};
86103
}
87104

88-
public class FixtureTestData(FeatureToggleEvaluation[] toggles, FixtureCase @case)
105+
public class FixtureTestData(string togglesJson, FixtureCase @case)
89106
{
90-
public FeatureToggleEvaluation[] Toggles { get; } = toggles;
107+
public string TogglesJson { get; } = togglesJson;
91108
public FixtureCase Case { get; } = @case;
92109

93-
// Controls the name shown in Test Explorer for each theory row
94110
public override string ToString() => Case.Description;
95111
}

src/Octopus.OpenFeature.Provider.Tests/FixtureModels.cs renamed to src/Octopus.OpenFeature.Provider.IntegrationTests/FixtureModels.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
namespace Octopus.OpenFeature.Provider.Tests;
2-
3-
public record FixtureFile(
4-
FeatureToggleEvaluation[] Toggles,
5-
FixtureCase[] Cases);
1+
namespace Octopus.OpenFeature.Provider.IntegrationTests;
62

73
public record FixtureCase(
84
string Description,

0 commit comments

Comments
 (0)