Skip to content

Commit f21d871

Browse files
authored
feat: Make the Evaluator customizable (#1733)
Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>
1 parent 1d1c1ad commit f21d871

3 files changed

Lines changed: 48 additions & 4 deletions

File tree

providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/FlagdOptions.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static dev.openfeature.contrib.providers.flagd.Config.fromValueProvider;
66

77
import dev.openfeature.contrib.providers.flagd.resolver.process.storage.connector.QueueSource;
8+
import dev.openfeature.contrib.tools.flagd.api.Evaluator;
89
import dev.openfeature.sdk.EvaluationContext;
910
import dev.openfeature.sdk.ImmutableContext;
1011
import dev.openfeature.sdk.Structure;
@@ -13,6 +14,7 @@
1314
import io.opentelemetry.api.OpenTelemetry;
1415
import java.util.List;
1516
import java.util.function.Function;
17+
import jdk.jfr.Experimental;
1618
import lombok.Builder;
1719
import lombok.Getter;
1820
import org.apache.commons.lang3.StringUtils;
@@ -141,7 +143,9 @@ public class FlagdOptions {
141143
*
142144
* <p>Only applicable for in-process resolver mode.
143145
*
144-
* @see <a href="https://github.com/open-feature/java-sdk-contrib/tree/main/providers/flagd#selector-filtering-in-process-mode-only">Selector filtering documentation</a>
146+
* @see <a
147+
* href="https://github.com/open-feature/java-sdk-contrib/tree/main/providers/flagd#selector-filtering-in-process-mode-only">Selector
148+
* filtering documentation</a>
145149
**/
146150
@Builder.Default
147151
private String selector = fallBackToEnvOrDefault(Config.SOURCE_SELECTOR_ENV_VAR_NAME, null);
@@ -232,6 +236,14 @@ public class FlagdOptions {
232236
private boolean reinitializeOnError = Boolean.parseBoolean(
233237
fallBackToEnvOrDefault(Config.REINITIALIZE_ON_ERROR_ENV_VAR_NAME, Config.DEFAULT_REINITIALIZE_ON_ERROR));
234238

239+
/**
240+
* The evaluator to use for flag evaluations. Defaults to {@code new FlagdCore()}. Only applicable in the in-process
241+
* mode
242+
*/
243+
@Builder.Default
244+
@Experimental
245+
private Evaluator evaluator = null;
246+
235247
/**
236248
* Builder overwrite in order to customize the "build" method.
237249
*

providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,20 @@ public class InProcessResolver implements Resolver {
4949
*/
5050
public InProcessResolver(
5151
FlagdOptions options, TriConsumer<ProviderEvent, ProviderEventDetails, Structure> onConnectionEvent) {
52+
Evaluator evaluator = options.getEvaluator();
53+
if (evaluator == null) {
54+
evaluator = new FlagdCore();
55+
}
5256
this.queueSource = getQueueSource(options);
53-
Evaluator flagdCore = new FlagdCore();
54-
this.evaluator = flagdCore;
55-
this.flagStore = new FlagStore(queueSource, flagdCore);
57+
this.evaluator = evaluator;
58+
this.flagStore = new FlagStore(queueSource, evaluator);
5659
this.onConnectionEvent = onConnectionEvent;
5760
}
5861

62+
Evaluator getEvaluator() {
63+
return evaluator;
64+
}
65+
5966
/**
6067
* Initialize in-process resolver.
6168
*/

providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolverTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.mockito.Mockito.mock;
2020
import static org.mockito.Mockito.times;
2121
import static org.mockito.Mockito.verify;
22+
import static org.mockito.Mockito.when;
2223

2324
import dev.openfeature.contrib.providers.flagd.Config;
2425
import dev.openfeature.contrib.providers.flagd.FlagdOptions;
@@ -27,6 +28,8 @@
2728
import dev.openfeature.contrib.providers.flagd.resolver.process.storage.StorageStateChange;
2829
import dev.openfeature.contrib.providers.flagd.resolver.process.storage.connector.file.FileQueueSource;
2930
import dev.openfeature.contrib.providers.flagd.resolver.process.storage.connector.sync.SyncStreamQueueSource;
31+
import dev.openfeature.contrib.tools.flagd.api.Evaluator;
32+
import dev.openfeature.contrib.tools.flagd.core.FlagdCore;
3033
import dev.openfeature.contrib.tools.flagd.core.model.FeatureFlag;
3134
import dev.openfeature.sdk.ErrorCode;
3235
import dev.openfeature.sdk.ImmutableContext;
@@ -57,6 +60,7 @@
5760
import org.junit.jupiter.api.AfterEach;
5861
import org.junit.jupiter.api.Assertions;
5962
import org.junit.jupiter.api.Test;
63+
import org.mockito.Mockito;
6064

6165
class InProcessResolverTest {
6266
private final List<InProcessResolver> resolversToShutdown = new ArrayList<>();
@@ -551,6 +555,27 @@ void testStateWatcherThreadIsCleanedUpDuringShutdown() throws Exception {
551555
// background threads can affect the count, making such assertions flaky in CI.
552556
}
553557

558+
@Test
559+
void usesSuppliedEvaluator() {
560+
var evaluator = Mockito.mock(Evaluator.class);
561+
var key = "key";
562+
var ctx = new ImmutableContext(key);
563+
when(evaluator.resolveBooleanValue(key, false, ctx)).thenReturn(Mockito.mock(ProviderEvaluation.class));
564+
var resolver = new InProcessResolver(
565+
FlagdOptions.builder().evaluator(evaluator).build(), (event, details, metadata) -> {});
566+
567+
resolver.booleanEvaluation(key, false, ctx);
568+
Mockito.verify(evaluator).resolveBooleanValue(key, false, ctx);
569+
assertThat(resolver.getEvaluator()).isEqualTo(evaluator);
570+
}
571+
572+
@Test
573+
void usesFlagdCoreEvaluatorWhenNotSupplied() {
574+
var resolver = new InProcessResolver(FlagdOptions.builder().build(), (event, details, metadata) -> {});
575+
576+
assertThat(resolver.getEvaluator()).isInstanceOf(FlagdCore.class);
577+
}
578+
554579
private long currentDaemonThreadCount() {
555580
return Thread.getAllStackTraces().keySet().stream()
556581
.filter(Thread::isDaemon)

0 commit comments

Comments
 (0)