22
33import static datadog .trace .api .openfeature .Provider .METADATA ;
44import static java .time .Duration .ofSeconds ;
5+ import static java .util .concurrent .TimeUnit .MILLISECONDS ;
6+ import static java .util .concurrent .TimeUnit .SECONDS ;
57import static org .awaitility .Awaitility .await ;
68import static org .hamcrest .CoreMatchers .equalTo ;
79import static org .hamcrest .MatcherAssert .assertThat ;
10+ import static org .junit .jupiter .api .Assertions .assertThrows ;
811import static org .mockito .ArgumentMatchers .any ;
12+ import static org .mockito .ArgumentMatchers .anyLong ;
913import static org .mockito .ArgumentMatchers .eq ;
1014import static org .mockito .Mockito .mock ;
1115import static org .mockito .Mockito .times ;
1418
1519import datadog .trace .api .featureflag .FeatureFlagGateway ;
1620import datadog .trace .api .featureflag .ufc .v1 .ServerConfiguration ;
21+ import datadog .trace .api .openfeature .Provider .Options ;
1722import dev .openfeature .sdk .Client ;
1823import dev .openfeature .sdk .EvaluationContext ;
1924import dev .openfeature .sdk .EventDetails ;
2025import dev .openfeature .sdk .Features ;
2126import dev .openfeature .sdk .FlagEvaluationDetails ;
2227import dev .openfeature .sdk .OpenFeatureAPI ;
2328import dev .openfeature .sdk .ProviderEvaluation ;
29+ import dev .openfeature .sdk .ProviderEvent ;
2430import dev .openfeature .sdk .ProviderState ;
2531import dev .openfeature .sdk .Value ;
32+ import dev .openfeature .sdk .exceptions .FatalError ;
33+ import dev .openfeature .sdk .exceptions .ProviderNotReadyError ;
2634import java .util .concurrent .ExecutorService ;
2735import java .util .concurrent .Executors ;
2836import java .util .function .Consumer ;
@@ -81,32 +89,55 @@ public void testSetProviderAndWait() {
8189 }
8290
8391 @ Test
84- public void testFailureToLoadInternalApi () {
85- @ SuppressWarnings ("unchecked" )
86- final Consumer <EventDetails > consumer = mock (Consumer .class );
87-
92+ public void testSetProviderAndWaitTimeout () {
93+ final Consumer <EventDetails > readyEvent = mock (Consumer .class );
8894 final OpenFeatureAPI api = OpenFeatureAPI .getInstance ();
89- api .onProviderError (consumer );
90- api .setProviderAndWait (
91- new Provider () {
92- @ Override
93- protected Class <?> loadEvaluatorClass () throws ClassNotFoundException {
94- throw new ClassNotFoundException (
95- "Class " + FeatureFlagGateway .class .getName () + " not found" );
96- }
97- });
95+ final Client client = api .getClient ();
96+ client .on (ProviderEvent .PROVIDER_READY , readyEvent );
97+
98+ // we time out after 10 millis without receiving the initial config
99+ assertThrows (
100+ ProviderNotReadyError .class ,
101+ () -> api .setProviderAndWait (new Provider (new Options ().initTimeout (10 , MILLISECONDS ))));
102+
103+ // ready has not yet been called
104+ verify (readyEvent , times (0 )).accept (any ());
105+
106+ // dispatch an initial configuration
107+ FeatureFlagGateway .dispatch (mock (ServerConfiguration .class ));
98108
109+ // ready is called after receiving the configuration
99110 await ()
100111 .atMost (ofSeconds (1 ))
101112 .untilAsserted (
102113 () -> {
103- verify (consumer , times (1 )).accept (eventDetailsCaptor .capture ());
104- final EventDetails eventDetails = eventDetailsCaptor .getValue ();
105- assertThat (eventDetails .getProviderName (), equalTo (METADATA ));
106- assertThat (api .getClient ().getProviderState (), equalTo (ProviderState .ERROR ));
114+ verify (readyEvent , times (1 )).accept (eventDetailsCaptor .capture ());
115+ final EventDetails details = eventDetailsCaptor .getValue ();
116+ assertThat (details .getProviderName (), equalTo (METADATA ));
107117 });
108118 }
109119
120+ @ Test
121+ public void testFailureToLoadInternalApi () {
122+ @ SuppressWarnings ("unchecked" )
123+ final Consumer <EventDetails > consumer = mock (Consumer .class );
124+
125+ final OpenFeatureAPI api = OpenFeatureAPI .getInstance ();
126+ api .onProviderError (consumer );
127+
128+ assertThrows (
129+ FatalError .class ,
130+ () ->
131+ api .setProviderAndWait (
132+ new Provider () {
133+ @ Override
134+ protected Class <?> loadEvaluatorClass () throws ClassNotFoundException {
135+ throw new ClassNotFoundException (
136+ "Class " + FeatureFlagGateway .class .getName () + " not found" );
137+ }
138+ }));
139+ }
140+
110141 public interface EvaluateMethod <E > {
111142 FlagEvaluationDetails <E > evaluate (Features client , String flag , E defaultValue );
112143 }
@@ -127,6 +158,7 @@ public <E> void testProviderEvaluation(
127158 final String flag , final E defaultValue , final EvaluateMethod <E > method ) throws Exception {
128159 FeatureFlagGateway .dispatch (mock (ServerConfiguration .class ));
129160 final FeatureFlagEvaluator evaluator = mock (FeatureFlagEvaluator .class );
161+ when (evaluator .initialize (anyLong (), any (), any ())).thenReturn (true );
130162 when (evaluator .evaluate (any (), any (), any (), any ()))
131163 .thenAnswer (
132164 invocation ->
@@ -135,12 +167,12 @@ public <E> void testProviderEvaluation(
135167 .reason ("MOCK" )
136168 .build ());
137169 final OpenFeatureAPI api = OpenFeatureAPI .getInstance ();
138- api .setProviderAndWait (new Provider (evaluator ));
170+ api .setProviderAndWait (new Provider (new Options (). initTimeout ( 10 , SECONDS ), evaluator ));
139171 final Client client = api .getClient ();
140172 final FlagEvaluationDetails <E > result = method .evaluate (client , flag , defaultValue );
141173 assertThat (result .getValue (), equalTo (defaultValue ));
142174 assertThat (result .getReason (), equalTo ("MOCK" ));
143- verify (evaluator , times (1 )).initialize (any ());
175+ verify (evaluator , times (1 )).initialize (eq ( 10L ), eq ( SECONDS ), any ());
144176 verify (evaluator , times (1 ))
145177 .evaluate (any (), eq (flag ), eq (defaultValue ), any (EvaluationContext .class ));
146178 }
0 commit comments