diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml
new file mode 100644
index 000000000..3d374f555
--- /dev/null
+++ b/checkstyle-suppressions.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/checkstyle.xml b/checkstyle.xml
index 9e524577a..f03d82985 100644
--- a/checkstyle.xml
+++ b/checkstyle.xml
@@ -1,7 +1,5 @@
-
+
-
-
+
+
-
+
-
+
+
+
-
+
+
-
-
+
-
+
-
-
-
+
+
+
-
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+
+
-
+
-
-
+
+
-
+
-
+ OBJBLOCK, STATIC_INIT, RECORD_DEF, COMPACT_CTOR_DEF" />
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+ LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN,
+ NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR,
+ SR_ASSIGN, STAR, STAR_ASSIGN, LITERAL_ASSERT, TYPE_EXTENSION_AND" />
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
+ METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA,
+ RECORD_DEF" />
-
-
+
+
-
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
-
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
\ No newline at end of file
diff --git a/eclipse-java-google-style.xml.bak b/eclipse-java-google-style.xml.bak
new file mode 100644
index 000000000..2380bc2c8
--- /dev/null
+++ b/eclipse-java-google-style.xml.bak
@@ -0,0 +1,337 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hooks/open-telemetry/src/main/java/dev/openfeature/contrib/hooks/otel/OpenTelemetryHook.java b/hooks/open-telemetry/src/main/java/dev/openfeature/contrib/hooks/otel/OpenTelemetryHook.java
index 24100d424..8cd8cf4ec 100644
--- a/hooks/open-telemetry/src/main/java/dev/openfeature/contrib/hooks/otel/OpenTelemetryHook.java
+++ b/hooks/open-telemetry/src/main/java/dev/openfeature/contrib/hooks/otel/OpenTelemetryHook.java
@@ -4,20 +4,21 @@
import dev.openfeature.javasdk.NoOpProvider;
import dev.openfeature.javasdk.OpenFeatureAPI;
-/**
+/**
* A placeholder.
*/
public class OpenTelemetryHook {
-
- /**
+
+ /**
* Create a new OpenTelemetryHook instance.
*/
- public OpenTelemetryHook() {
+ private OpenTelemetryHook() {
}
- /**
- * A test method...
- * @return {boolean}
+ /**
+ * A test.
+ *
+ * @return boolean
*/
public static boolean test() {
OpenFeatureAPI.getInstance().setProvider(new NoOpProvider());
diff --git a/pom.xml b/pom.xml
index 0d5e545b2..b9c172d98 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,6 +33,14 @@
0.0.3
+
+
+ org.projectlombok
+ lombok
+ 1.18.24
+ provided
+
+
org.mockito
@@ -121,13 +129,13 @@
com.puppycrawl.tools
checkstyle
- 8.31
+ 10.3.2
validate
- validate
+ verify
check
@@ -138,7 +146,9 @@
org.apache.maven.plugins
maven-pmd-plugin
- 3.13.0
+
+ ${basedir}/target/generated-sources/
+
run-pmd
@@ -223,21 +233,24 @@
3.4.0
true
+ dev.openfeature.flagd.grpc
- vet-javadoc
- validate
+ attach-javadocs
+ compile
jar
- attach-javadocs
+ vet-javadoc
+ verify
jar
+
@@ -250,7 +263,7 @@
sign-artifacts
- verify
+ install
sign
diff --git a/providers/flagd/pom.xml b/providers/flagd/pom.xml
index 136d80795..0698c3ecd 100644
--- a/providers/flagd/pom.xml
+++ b/providers/flagd/pom.xml
@@ -31,6 +31,61 @@
+
+
+ io.grpc
+ grpc-netty-shaded
+ 1.48.1
+ runtime
+
+
+ io.grpc
+ grpc-protobuf
+ 1.48.1
+
+
+ io.grpc
+ grpc-stub
+ 1.48.1
+
+
+
+ org.apache.tomcat
+ annotations-api
+ 6.0.53
+ provided
+
+
+
+
+ kr.motd.maven
+ os-maven-plugin
+ 1.6.2
+
+
+
+
+
+ org.xolstice.maven.plugins
+ protobuf-maven-plugin
+ 0.6.1
+
+ com.google.protobuf:protoc:3.21.1:exe:${os.detected.classifier}
+ grpc-java
+ io.grpc:protoc-gen-grpc-java:1.48.1:exe:${os.detected.classifier}
+
+
+
+
+ compile
+ compile-custom
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/FlagdProvider.java b/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/FlagdProvider.java
index 8c81a3cc2..53e307a86 100644
--- a/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/FlagdProvider.java
+++ b/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/FlagdProvider.java
@@ -1,29 +1,185 @@
package dev.openfeature.contrib.providers.flagd;
-import dev.openfeature.javasdk.Client;
-import dev.openfeature.javasdk.NoOpProvider;
-import dev.openfeature.javasdk.OpenFeatureAPI;
+import java.util.HashMap;
+import java.util.Map;
-/**
- * A placeholder.
+import org.apache.commons.lang3.EnumUtils;
+import org.apache.commons.lang3.NotImplementedException;
+
+import com.google.protobuf.Struct;
+import com.google.protobuf.Value;
+
+import dev.openfeature.javasdk.EvaluationContext;
+import dev.openfeature.javasdk.FeatureProvider;
+import dev.openfeature.javasdk.FlagEvaluationOptions;
+import dev.openfeature.javasdk.Metadata;
+import dev.openfeature.javasdk.ProviderEvaluation;
+import dev.openfeature.javasdk.Reason;
+import io.grpc.ManagedChannelBuilder;
+import lombok.extern.slf4j.Slf4j;
+import dev.openfeature.flagd.grpc.Schema.ResolveBooleanRequest;
+import dev.openfeature.flagd.grpc.Schema.ResolveBooleanResponse;
+import dev.openfeature.flagd.grpc.Schema.ResolveFloatRequest;
+import dev.openfeature.flagd.grpc.Schema.ResolveFloatResponse;
+import dev.openfeature.flagd.grpc.Schema.ResolveIntRequest;
+import dev.openfeature.flagd.grpc.Schema.ResolveIntResponse;
+import dev.openfeature.flagd.grpc.Schema.ResolveStringRequest;
+import dev.openfeature.flagd.grpc.Schema.ResolveStringResponse;
+import dev.openfeature.flagd.grpc.ServiceGrpc;
+import dev.openfeature.flagd.grpc.ServiceGrpc.ServiceBlockingStub;
+
+/**
+ * OpenFeature provider for flagd.
*/
-public class FlagdProvider {
+@Slf4j
+public class FlagdProvider implements FeatureProvider {
+
+ private ServiceBlockingStub serviceStub;
+ static final String PROVIDER_NAME = "flagD Provider";
- /**
+ /**
+ * Create a new FlagdProvider instance.
+ *
+ * @param protocol transport protocol, "http" or "https"
+ * @param host flagd host, defaults to localhost
+ * @param port flagd port, defaults to 8013
+ */
+ public FlagdProvider(String protocol, String host, int port) {
+
+ this("https".equalsIgnoreCase(protocol)
+ ? ServiceGrpc.newBlockingStub(ManagedChannelBuilder.forAddress(host, port)
+ .useTransportSecurity()
+ .build()) :
+ ServiceGrpc.newBlockingStub(ManagedChannelBuilder.forAddress(host, port)
+ .usePlaintext()
+ .build()));
+ }
+
+ /**
* Create a new FlagdProvider instance.
*/
public FlagdProvider() {
+ this("http", "localhost", 8013);
}
- /**
- * A test method...
- *
- * @return {boolean}
+ /**
+ * Create a new FlagdProvider instance.
+ *
+ * @param serviceStub service stub instance to use
*/
- public static boolean test() {
- OpenFeatureAPI.getInstance().setProvider(new NoOpProvider());
- Client client = OpenFeatureAPI.getInstance().getClient();
- return client.getBooleanValue("test", true);
+ public FlagdProvider(ServiceBlockingStub serviceStub) {
+ this.serviceStub = serviceStub;
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return new Metadata() {
+ @Override
+ public String getName() {
+ return PROVIDER_NAME;
+ }
+ };
+ }
+
+ @Override
+ public ProviderEvaluation getBooleanEvaluation(String key, Boolean defaultValue,
+ EvaluationContext ctx, FlagEvaluationOptions options) {
+
+ ResolveBooleanRequest request = ResolveBooleanRequest.newBuilder()
+ .setFlagKey(key)
+ .setContext(this.convertContext(ctx))
+ .build();
+ ResolveBooleanResponse r = this.serviceStub.resolveBoolean(request);
+ return ProviderEvaluation.builder()
+ .value(r.getValue())
+ .variant(r.getVariant())
+ .reason(this.mapReason(r.getReason()))
+ .build();
+ }
+
+ @Override
+ public ProviderEvaluation getStringEvaluation(String key, String defaultValue,
+ EvaluationContext ctx, FlagEvaluationOptions options) {
+ ResolveStringRequest request = ResolveStringRequest.newBuilder()
+ .setFlagKey(key)
+ .setContext(this.convertContext(ctx)).build();
+ ResolveStringResponse r = this.serviceStub.resolveString(request);
+ return ProviderEvaluation.builder().value(r.getValue())
+ .variant(r.getVariant())
+ .reason(this.mapReason(r.getReason()))
+ .build();
+ }
+
+ @Override
+ public ProviderEvaluation getDoubleEvaluation(String key, Double defaultValue,
+ EvaluationContext ctx, FlagEvaluationOptions options) {
+ ResolveFloatRequest request = ResolveFloatRequest.newBuilder()
+ .setFlagKey(key)
+ .setContext(this.convertContext(ctx))
+ .build();
+ ResolveFloatResponse r = this.serviceStub.resolveFloat(request);
+ return ProviderEvaluation.builder()
+ .value(r.getValue())
+ .variant(r.getVariant())
+ .reason(this.mapReason(r.getReason()))
+ .build();
+ }
+
+ @Override
+ public ProviderEvaluation getIntegerEvaluation(String key, Integer defaultValue,
+ EvaluationContext ctx, FlagEvaluationOptions options) {
+ ResolveIntRequest request = ResolveIntRequest.newBuilder()
+ .setFlagKey(key)
+ .setContext(this.convertContext(ctx))
+ .build();
+ ResolveIntResponse r = this.serviceStub.resolveInt(request);
+ return ProviderEvaluation.builder()
+ .value((int) r.getValue())
+ .variant(r.getVariant())
+ .reason(this.mapReason(r.getReason()))
+ .build();
+ }
+
+ @Override
+ public ProviderEvaluation getObjectEvaluation(String key, T defaultValue,
+ EvaluationContext ctx, FlagEvaluationOptions options) {
+ throw new NotImplementedException();
+ }
+
+ // Map FlagD reasons to Java SDK reasons.
+ private Reason mapReason(String flagDreason) {
+ if (!EnumUtils.isValidEnum(Reason.class, flagDreason)) {
+ // until we have "STATIC" in the spec and SDK, we map STATIC to DEFAULT
+ if ("STATIC".equals(flagDreason)) {
+ return Reason.DEFAULT;
+ } else {
+ return Reason.UNKNOWN;
+ }
+ } else {
+ return Reason.valueOf(flagDreason);
+ }
+ }
+
+ private Struct convertContext(EvaluationContext ctx) {
+ // TODO: structure attributes?
+ Map booleanAttributes = ctx.getBooleanAttributes();
+ Map stringAttributes = ctx.getStringAttributes();
+ Map intAttributes = ctx.getIntegerAttributes();
+ Map values = new HashMap<>();
+ booleanAttributes.keySet().stream().forEach((String key) -> values.put(key, Value
+ .newBuilder()
+ .setBoolValue(booleanAttributes.get(key))
+ .build()));
+ stringAttributes.keySet().stream().forEach((String key) -> values.put(key,
+ Value.newBuilder().setStringValue(stringAttributes
+ .get(key))
+ .build()));
+ intAttributes.keySet().stream().forEach((String key) -> values.put(key, Value
+ .newBuilder().setNumberValue(intAttributes.get(key))
+ .build()));
+ return Struct.newBuilder()
+ .putAllFields(values)
+ .build();
}
}
diff --git a/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/Service.java b/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/Service.java
new file mode 100644
index 000000000..6efe5357d
--- /dev/null
+++ b/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/Service.java
@@ -0,0 +1,9 @@
+package dev.openfeature.contrib.providers.flagd;
+
+/**
+ * The commication style to yus.
+ */
+enum Service {
+ HTTP,
+ GRPC
+}
diff --git a/providers/flagd/src/main/proto/schema.proto b/providers/flagd/src/main/proto/schema.proto
new file mode 100644
index 000000000..fe460aed3
--- /dev/null
+++ b/providers/flagd/src/main/proto/schema.proto
@@ -0,0 +1,97 @@
+syntax = "proto3";
+
+package schema.v1;
+
+option go_package = "schema/service/v1";
+option java_package = "dev.openfeature.flagd.grpc";
+
+import "google/protobuf/struct.proto";
+import "google/api/annotations.proto";
+
+message ErrorResponse {
+ string error_code = 1;
+ string reason = 2;
+}
+
+message ResolveBooleanRequest {
+ string flag_key = 1;
+ google.protobuf.Struct context = 2;
+}
+message ResolveBooleanResponse {
+ bool value = 1;
+ string reason = 2;
+ string variant = 3;
+}
+
+message ResolveStringRequest {
+ string flag_key = 1;
+ google.protobuf.Struct context = 2;
+}
+message ResolveStringResponse {
+ string value = 1;
+ string reason = 2;
+ string variant = 3;
+}
+
+message ResolveFloatRequest {
+ string flag_key = 1;
+ google.protobuf.Struct context = 2;
+}
+message ResolveFloatResponse {
+ double value = 1;
+ string reason = 2;
+ string variant = 3;
+}
+
+message ResolveIntRequest {
+ string flag_key = 1;
+ google.protobuf.Struct context = 2;
+}
+message ResolveIntResponse {
+ int64 value = 1;
+ string reason = 2;
+ string variant = 3;
+}
+
+message ResolveObjectRequest {
+ string flag_key = 1;
+ google.protobuf.Struct context = 2;
+}
+message ResolveObjectResponse {
+ google.protobuf.Struct value = 1;
+ string reason = 2;
+ string variant = 3;
+}
+
+service Service {
+ rpc ResolveBoolean(ResolveBooleanRequest) returns (ResolveBooleanResponse) {
+ option (google.api.http) = {
+ post: "/flags/{flag_key}/resolve/boolean"
+ body: "context"
+ };
+ }
+ rpc ResolveString(ResolveStringRequest) returns (ResolveStringResponse) {
+ option (google.api.http) = {
+ post: "/flags/{flag_key}/resolve/string"
+ body: "context"
+ };
+ }
+ rpc ResolveFloat(ResolveFloatRequest) returns (ResolveFloatResponse) {
+ option (google.api.http) = {
+ post: "/flags/{flag_key}/resolve/float"
+ body: "context"
+ };
+ }
+ rpc ResolveInt(ResolveIntRequest) returns (ResolveIntResponse) {
+ option (google.api.http) = {
+ post: "/flags/{flag_key}/resolve/int"
+ body: "context"
+ };
+ }
+ rpc ResolveObject(ResolveObjectRequest) returns (ResolveObjectResponse) {
+ option (google.api.http) = {
+ post: "/flags/{flag_key}/resolve/object"
+ body: "context"
+ };
+ }
+}
\ No newline at end of file
diff --git a/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/FlagdProviderTest.java b/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/FlagdProviderTest.java
index f7f45fa17..114a40986 100644
--- a/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/FlagdProviderTest.java
+++ b/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/FlagdProviderTest.java
@@ -1,15 +1,132 @@
package dev.openfeature.contrib.providers.flagd;
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
-import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import dev.openfeature.flagd.grpc.Schema.ResolveBooleanResponse;
+import dev.openfeature.flagd.grpc.Schema.ResolveFloatResponse;
+import dev.openfeature.flagd.grpc.Schema.ResolveIntResponse;
+import dev.openfeature.flagd.grpc.Schema.ResolveStringResponse;
+import dev.openfeature.flagd.grpc.ServiceGrpc.ServiceBlockingStub;
+import dev.openfeature.javasdk.EvaluationContext;
+import dev.openfeature.javasdk.FlagEvaluationDetails;
+import dev.openfeature.javasdk.OpenFeatureAPI;
+import dev.openfeature.javasdk.Reason;
+
class FlagdProviderTest {
+ static final String FLAG_KEY = "some-key";
+ static final String BOOL_VARIANT = "on";
+ static final String DOUBLE_VARIANT = "half";
+ static final String INT_VARIANT = "one-hundred";
+ static final String STRING_VARIANT = "greeting";
+ static final Reason DEFAULT = Reason.DEFAULT;
+ static final Integer INT_VALUE = 100;
+ static final Double DOUBLE_VALUE = .5d;
+ static final String STRING_VALUE = "hi!";
+
+ static OpenFeatureAPI api;
+
+ @BeforeAll
+ public static void init() {
+ api = OpenFeatureAPI.getInstance();
+ }
+
@Test
- @DisplayName("a simple test")
- void test() {
- assertThat(FlagdProvider.test()).isEqualTo(true);
+ void resolvers_call_grpc_service_and_return_details() {
+ ResolveBooleanResponse booleanResponse = ResolveBooleanResponse.newBuilder()
+ .setValue(true)
+ .setVariant(BOOL_VARIANT)
+ .setReason(DEFAULT.toString())
+ .build();
+
+ ResolveStringResponse stringResponse = ResolveStringResponse.newBuilder()
+ .setValue(STRING_VALUE)
+ .setVariant(STRING_VARIANT)
+ .setReason(DEFAULT.toString())
+ .build();
+
+ ResolveIntResponse intResponse = ResolveIntResponse.newBuilder()
+ .setValue(INT_VALUE)
+ .setVariant(INT_VARIANT)
+ .setReason(DEFAULT.toString())
+ .build();
+
+ ResolveFloatResponse floatResponse = ResolveFloatResponse.newBuilder()
+ .setValue(DOUBLE_VALUE)
+ .setVariant(DOUBLE_VARIANT)
+ .setReason(DEFAULT.toString())
+ .build();
+
+ ServiceBlockingStub serviceBlockingStubMock = mock(ServiceBlockingStub.class);
+ when(serviceBlockingStubMock.resolveBoolean(argThat(x -> FLAG_KEY.equals(x.getFlagKey())))).thenReturn(booleanResponse);
+ when(serviceBlockingStubMock.resolveFloat(argThat(x -> FLAG_KEY.equals(x.getFlagKey())))).thenReturn(floatResponse);
+ when(serviceBlockingStubMock.resolveInt(argThat(x -> FLAG_KEY.equals(x.getFlagKey())))).thenReturn(intResponse);
+ when(serviceBlockingStubMock.resolveString(argThat(x -> FLAG_KEY.equals(x.getFlagKey())))).thenReturn(stringResponse);
+
+ OpenFeatureAPI.getInstance().setProvider(new FlagdProvider(serviceBlockingStubMock));
+
+ FlagEvaluationDetails booleanDetails = api.getClient().getBooleanDetails(FLAG_KEY, false);
+ assertTrue(booleanDetails.getValue());
+ assertEquals(BOOL_VARIANT, booleanDetails.getVariant());
+ assertEquals(DEFAULT, booleanDetails.getReason());
+
+ FlagEvaluationDetails stringDetails = api.getClient().getStringDetails(FLAG_KEY, "wrong");
+ assertEquals(STRING_VALUE, stringDetails.getValue());
+ assertEquals(STRING_VARIANT, stringDetails.getVariant());
+ assertEquals(DEFAULT, stringDetails.getReason());
+
+ FlagEvaluationDetails intDetails = api.getClient().getIntegerDetails(FLAG_KEY, 0);
+ assertEquals(INT_VALUE, intDetails.getValue());
+ assertEquals(INT_VARIANT, intDetails.getVariant());
+ assertEquals(DEFAULT, intDetails.getReason());
+
+ FlagEvaluationDetails floatDetails = api.getClient().getDoubleDetails(FLAG_KEY, 0.1);
+ assertEquals(DOUBLE_VALUE, floatDetails.getValue());
+ assertEquals(DOUBLE_VARIANT, floatDetails.getVariant());
+ assertEquals(DEFAULT, floatDetails.getReason());
+ }
+
+ @Test
+ void context_is_passed_to_grpc_service() {
+
+ final String BOOLEAN_ATTR_KEY = "bool-attr";
+ final String NUM_ATTR_KEY = "int-attr";
+ final String STRING_ATTR_KEY = "string-attr";
+
+ final Boolean BOOLEAN_ATTR_VALUE = true;
+ final Integer NUM_ATTR_VALUE = 1;
+ final String STRING_ATTR_VALUE = "str";
+
+ ResolveBooleanResponse booleanResponse = ResolveBooleanResponse.newBuilder()
+ .setValue(true)
+ .setVariant(BOOL_VARIANT)
+ .setReason(DEFAULT.toString())
+ .build();
+
+ ServiceBlockingStub serviceBlockingStubMock = mock(ServiceBlockingStub.class);
+ when(serviceBlockingStubMock.resolveBoolean(argThat(x ->
+ STRING_ATTR_VALUE.equals(x.getContext().getFieldsMap().get(STRING_ATTR_KEY).getStringValue()) &&
+ NUM_ATTR_VALUE == x.getContext().getFieldsMap().get(NUM_ATTR_KEY).getNumberValue() &&
+ x.getContext().getFieldsMap().get(BOOLEAN_ATTR_KEY).getBoolValue()
+ ))).thenReturn(booleanResponse);
+
+ OpenFeatureAPI.getInstance().setProvider(new FlagdProvider(serviceBlockingStubMock));
+
+ EvaluationContext context = new EvaluationContext();
+ context.addBooleanAttribute(BOOLEAN_ATTR_KEY, BOOLEAN_ATTR_VALUE);
+ context.addIntegerAttribute(NUM_ATTR_KEY, NUM_ATTR_VALUE);
+ context.addStringAttribute(STRING_ATTR_KEY, STRING_ATTR_VALUE);
+
+ FlagEvaluationDetails booleanDetails = api.getClient().getBooleanDetails(FLAG_KEY, false, context);
+ assertTrue(booleanDetails.getValue());
+ assertEquals(BOOL_VARIANT, booleanDetails.getVariant());
+ assertEquals(DEFAULT, booleanDetails.getReason());
}
-}
+}
\ No newline at end of file
diff --git a/providers/flagd/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/providers/flagd/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 000000000..ca6ee9cea
--- /dev/null
+++ b/providers/flagd/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
\ No newline at end of file
diff --git a/spotbugs-exclusions.xml b/spotbugs-exclusions.xml
index 59e92ca80..0aad72fd8 100644
--- a/spotbugs-exclusions.xml
+++ b/spotbugs-exclusions.xml
@@ -1,24 +1,11 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+