Skip to content

Commit e097032

Browse files
committed
fixup: add provider-status tests
Signed-off-by: Simon Schrottner <[email protected]>
1 parent f3512f9 commit e097032

File tree

2 files changed

+137
-3
lines changed

2 files changed

+137
-3
lines changed

src/test/java/dev/openfeature/sdk/e2e/GherkinSpecTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@
1616
@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty")
1717
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "dev.openfeature.sdk.e2e.steps")
1818
@ConfigurationParameter(key = OBJECT_FACTORY_PROPERTY_NAME, value = "io.cucumber.picocontainer.PicoFactory")
19-
@ExcludeTags({"deprecated", "provider-status", "reason-codes", "async", "immutability", "evaluation-options"})
19+
@ExcludeTags({"deprecated", "reason-codes", "async", "immutability", "evaluation-options"})
2020
public class GherkinSpecTest {}
Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
11
package dev.openfeature.sdk.e2e.steps;
22

33
import static dev.openfeature.sdk.testutils.TestFlagsUtils.buildFlags;
4+
import static org.assertj.core.api.Assertions.assertThat;
5+
import static org.mockito.ArgumentMatchers.any;
6+
import static org.mockito.ArgumentMatchers.anyString;
7+
import static org.mockito.Mockito.doAnswer;
8+
import static org.mockito.Mockito.doThrow;
9+
import static org.mockito.Mockito.spy;
10+
import static org.mockito.Mockito.when;
411

12+
import dev.openfeature.sdk.ErrorCode;
13+
import dev.openfeature.sdk.EventProvider;
14+
import dev.openfeature.sdk.FeatureProvider;
515
import dev.openfeature.sdk.OpenFeatureAPI;
16+
import dev.openfeature.sdk.ProviderEvaluation;
17+
import dev.openfeature.sdk.ProviderEventDetails;
18+
import dev.openfeature.sdk.ProviderState;
19+
import dev.openfeature.sdk.Reason;
20+
import dev.openfeature.sdk.Value;
621
import dev.openfeature.sdk.e2e.State;
22+
import dev.openfeature.sdk.exceptions.FatalError;
723
import dev.openfeature.sdk.providers.memory.Flag;
824
import dev.openfeature.sdk.providers.memory.InMemoryProvider;
925
import io.cucumber.java.en.Given;
26+
import io.cucumber.java.en.Then;
1027
import java.util.Map;
28+
import org.awaitility.Awaitility;
1129

1230
public class ProviderSteps {
1331
private final State state;
@@ -16,11 +34,127 @@ public ProviderSteps(State state) {
1634
this.state = state;
1735
}
1836

19-
@Given("a stable provider")
20-
public void aStableProvider() {
37+
@Given("a {} provider")
38+
public void a_provider_with_status(String providerType) throws Exception {
39+
// Normalize input to handle both single word and quoted strings
40+
String normalizedType =
41+
providerType.toLowerCase().replaceAll("[\"\\s]+", " ").trim();
42+
43+
switch (normalizedType) {
44+
case "not ready":
45+
setupMockProvider(ErrorCode.PROVIDER_NOT_READY, "Provider in not ready state", ProviderState.NOT_READY);
46+
break;
47+
case "stable":
48+
case "ready":
49+
setupStableProvider();
50+
break;
51+
case "fatal":
52+
setupMockProvider(ErrorCode.PROVIDER_FATAL, "Provider in fatal state", ProviderState.FATAL);
53+
break;
54+
case "error":
55+
setupMockProvider(ErrorCode.GENERAL, "Provider in error state", ProviderState.ERROR);
56+
break;
57+
case "stale":
58+
setupMockProvider(null, null, ProviderState.STALE);
59+
break;
60+
default:
61+
throw new IllegalArgumentException("Unsupported provider type: " + providerType);
62+
}
63+
}
64+
65+
// ===============================
66+
// Provider Status Assertion Steps
67+
// ===============================
68+
69+
@Then("the provider status should be {string}")
70+
public void the_provider_status_should_be(String expectedStatus) {
71+
ProviderState actualStatus = state.client.getProviderState();
72+
ProviderState expected = ProviderState.valueOf(expectedStatus);
73+
assertThat(actualStatus).isEqualTo(expected);
74+
}
75+
76+
// ===============================
77+
// Helper Methods
78+
// ===============================
79+
80+
private void setupStableProvider() throws Exception {
2181
Map<String, Flag<?>> flags = buildFlags();
2282
InMemoryProvider provider = new InMemoryProvider(flags);
2383
OpenFeatureAPI.getInstance().setProviderAndWait(provider);
2484
state.client = OpenFeatureAPI.getInstance().getClient();
2585
}
86+
87+
private void setupMockProvider(ErrorCode errorCode, String errorMessage, ProviderState providerState)
88+
throws Exception {
89+
EventProvider mockProvider = spy(EventProvider.class);
90+
91+
switch (providerState) {
92+
case NOT_READY:
93+
doAnswer(invocationOnMock -> {
94+
while (true) {}
95+
})
96+
.when(mockProvider)
97+
.initialize(any());
98+
break;
99+
case FATAL:
100+
doThrow(new FatalError(errorMessage)).when(mockProvider).initialize(any());
101+
break;
102+
}
103+
// Configure all evaluation methods with a single helper
104+
configureMockEvaluations(mockProvider, errorCode, errorMessage);
105+
106+
OpenFeatureAPI.getInstance().setProvider(providerState.name(), mockProvider);
107+
state.client = OpenFeatureAPI.getInstance().getClient(providerState.name());
108+
109+
ProviderEventDetails details =
110+
ProviderEventDetails.builder().errorCode(errorCode).build();
111+
switch (providerState) {
112+
case FATAL:
113+
case ERROR:
114+
mockProvider.emitProviderReady(details);
115+
mockProvider.emitProviderError(details);
116+
break;
117+
case STALE:
118+
mockProvider.emitProviderReady(details);
119+
mockProvider.emitProviderStale(details);
120+
break;
121+
default:
122+
}
123+
Awaitility.await().until(() -> {
124+
ProviderState providerState1 = state.client.getProviderState();
125+
return providerState1 == providerState;
126+
});
127+
}
128+
129+
private void configureMockEvaluations(FeatureProvider mockProvider, ErrorCode errorCode, String errorMessage) {
130+
// Configure Boolean evaluation
131+
when(mockProvider.getBooleanEvaluation(anyString(), any(Boolean.class), any()))
132+
.thenAnswer(invocation -> createProviderEvaluation(invocation.getArgument(1), errorCode, errorMessage));
133+
134+
// Configure String evaluation
135+
when(mockProvider.getStringEvaluation(anyString(), any(String.class), any()))
136+
.thenAnswer(invocation -> createProviderEvaluation(invocation.getArgument(1), errorCode, errorMessage));
137+
138+
// Configure Integer evaluation
139+
when(mockProvider.getIntegerEvaluation(anyString(), any(Integer.class), any()))
140+
.thenAnswer(invocation -> createProviderEvaluation(invocation.getArgument(1), errorCode, errorMessage));
141+
142+
// Configure Double evaluation
143+
when(mockProvider.getDoubleEvaluation(anyString(), any(Double.class), any()))
144+
.thenAnswer(invocation -> createProviderEvaluation(invocation.getArgument(1), errorCode, errorMessage));
145+
146+
// Configure Object evaluation
147+
when(mockProvider.getObjectEvaluation(anyString(), any(Value.class), any()))
148+
.thenAnswer(invocation -> createProviderEvaluation(invocation.getArgument(1), errorCode, errorMessage));
149+
}
150+
151+
private <T> ProviderEvaluation<T> createProviderEvaluation(
152+
T defaultValue, ErrorCode errorCode, String errorMessage) {
153+
return ProviderEvaluation.<T>builder()
154+
.value(defaultValue)
155+
.errorCode(errorCode)
156+
.errorMessage(errorMessage)
157+
.reason(Reason.ERROR.toString())
158+
.build();
159+
}
26160
}

0 commit comments

Comments
 (0)