11package dev .openfeature .sdk .e2e .steps ;
22
33import 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 ;
515import 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 ;
621import dev .openfeature .sdk .e2e .State ;
22+ import dev .openfeature .sdk .exceptions .FatalError ;
723import dev .openfeature .sdk .providers .memory .Flag ;
824import dev .openfeature .sdk .providers .memory .InMemoryProvider ;
925import io .cucumber .java .en .Given ;
26+ import io .cucumber .java .en .Then ;
1027import java .util .Map ;
28+ import org .awaitility .Awaitility ;
1129
1230public 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