forked from open-feature/java-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOpenFeatureClientTest.java
158 lines (130 loc) · 6.39 KB
/
OpenFeatureClientTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package dev.openfeature.sdk;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.simplify4u.slf4jmock.LoggerMock;
import org.slf4j.Logger;
import dev.openfeature.sdk.exceptions.FatalError;
import dev.openfeature.sdk.fixtures.HookFixtures;
import dev.openfeature.sdk.testutils.TestEventsProvider;
class OpenFeatureClientTest implements HookFixtures {
private Logger logger;
@BeforeEach
void set_logger() {
logger = Mockito.mock(Logger.class);
LoggerMock.setMock(OpenFeatureClient.class, logger);
}
@AfterEach
void reset_logs() {
LoggerMock.setMock(OpenFeatureClient.class, logger);
}
@Test
@DisplayName("should not throw exception if hook has different type argument than hookContext")
void shouldNotThrowExceptionIfHookHasDifferentTypeArgumentThanHookContext() {
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProvider("shouldNotThrowExceptionIfHookHasDifferentTypeArgumentThanHookContext", new DoSomethingProvider());
Client client = api.getClient("shouldNotThrowExceptionIfHookHasDifferentTypeArgumentThanHookContext");
client.addHooks(mockBooleanHook(), mockStringHook());
FlagEvaluationDetails<Boolean> actual = client.getBooleanDetails("feature key", Boolean.FALSE);
assertThat(actual.getValue()).isTrue();
// I dislike this, but given the mocking tools available, there's no way that I know of to say "no errors were logged"
Mockito.verify(logger, never()).error(any());
Mockito.verify(logger, never()).error(anyString(), any(Throwable.class));
Mockito.verify(logger, never()).error(anyString(), any(Object.class));
Mockito.verify(logger, never()).error(anyString(), any(), any());
Mockito.verify(logger, never()).error(anyString(), any(), any());
}
@Test
@DisplayName("addHooks should allow chaining by returning the same client instance")
void addHooksShouldAllowChaining() {
OpenFeatureAPI api = mock(OpenFeatureAPI.class);
OpenFeatureClient client = new OpenFeatureClient(api, "name", "version");
Hook<?> hook1 = Mockito.mock(Hook.class);
Hook<?> hook2 = Mockito.mock(Hook.class);
OpenFeatureClient result = client.addHooks(hook1, hook2);
assertEquals(client, result);
}
@Test
@DisplayName("setEvaluationContext should allow chaining by returning the same client instance")
void setEvaluationContextShouldAllowChaining() {
OpenFeatureAPI api = mock(OpenFeatureAPI.class);
OpenFeatureClient client = new OpenFeatureClient(api, "name", "version");
EvaluationContext ctx = new ImmutableContext("targeting key", new HashMap<>());
OpenFeatureClient result = client.setEvaluationContext(ctx);
assertEquals(client, result);
}
@Test
@DisplayName("Should not call evaluation methods when the provider has state FATAL")
void shouldNotCallEvaluationMethodsWhenProviderIsInFatalErrorState() {
FeatureProvider provider = new TestEventsProvider(100, true, "fake fatal", true);
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
Client client = api.getClient("shouldNotCallEvaluationMethodsWhenProviderIsInFatalErrorState");
assertThrows(FatalError.class, () -> api.setProviderAndWait("shouldNotCallEvaluationMethodsWhenProviderIsInFatalErrorState", provider));
FlagEvaluationDetails<Boolean> details = client.getBooleanDetails("key", true);
assertThat(details.getErrorCode()).isEqualTo(ErrorCode.PROVIDER_FATAL);
}
@Test
@DisplayName("Should not call evaluation methods when the provider has state NOT_READY")
void shouldNotCallEvaluationMethodsWhenProviderIsInNotReadyState() {
FeatureProvider provider = new TestEventsProvider(5000);
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProvider("shouldNotCallEvaluationMethodsWhenProviderIsInNotReadyState", provider);
Client client = api.getClient("shouldNotCallEvaluationMethodsWhenProviderIsInNotReadyState");
FlagEvaluationDetails<Boolean> details = client.getBooleanDetails("key", true);
assertThat(details.getErrorCode()).isEqualTo(ErrorCode.PROVIDER_NOT_READY);
}
private static class MockProvider implements FeatureProvider {
private final AtomicBoolean evaluationCalled = new AtomicBoolean();
private final ProviderState providerState;
public MockProvider(ProviderState providerState) {
this.providerState = providerState;
}
public boolean isEvaluationCalled() {
return evaluationCalled.get();
}
@Override
public ProviderState getState() {
return providerState;
}
@Override
public Metadata getMetadata() {
return null;
}
@Override
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx) {
evaluationCalled.set(true);
return null;
}
@Override
public ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx) {
evaluationCalled.set(true);
return null;
}
@Override
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx) {
evaluationCalled.set(true);
return null;
}
@Override
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue, EvaluationContext ctx) {
evaluationCalled.set(true);
return null;
}
@Override
public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultValue, EvaluationContext ctx) {
evaluationCalled.set(true);
return null;
}
}
}