Skip to content

Commit 7de7ec9

Browse files
committed
fix(flipt): set variant attachment as value for object evaluation
Signed-off-by: Mark Phelps <[email protected]>
1 parent 4f6c150 commit 7de7ec9

File tree

5 files changed

+71
-48
lines changed

5 files changed

+71
-48
lines changed

providers/flipt/pom.xml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,20 @@
1616
<description>Flipt provider for Java</description>
1717
<url>https://www.flipt.io/</url>
1818

19+
<developers>
20+
<developer>
21+
<id>markphelps</id>
22+
<name>Mark Phelps</name>
23+
<organization>Flipt Software</organization>
24+
<url>https://flipt.io/</url>
25+
</developer>
26+
</developers>
27+
1928
<dependencies>
2029
<dependency>
2130
<groupId>io.flipt</groupId>
2231
<artifactId>flipt-java</artifactId>
23-
<version>0.2.15</version>
32+
<version>1.1.1</version>
2433
</dependency>
2534

2635
<dependency>
@@ -29,6 +38,12 @@
2938
<version>2.0.11</version>
3039
</dependency>
3140

41+
<dependency>
42+
<groupId>com.fasterxml.jackson.core</groupId>
43+
<artifactId>jackson-databind</artifactId>
44+
<version>2.17.2</version>
45+
</dependency>
46+
3247
<dependency>
3348
<groupId>com.github.tomakehurst</groupId>
3449
<artifactId>wiremock-jre8</artifactId>

providers/flipt/src/main/java/dev/openfeature/contrib/providers/flipt/FliptProvider.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package dev.openfeature.contrib.providers.flipt;
22

3-
import com.flipt.api.FliptApiClient;
4-
import com.flipt.api.resources.evaluation.types.BooleanEvaluationResponse;
5-
import com.flipt.api.resources.evaluation.types.EvaluationRequest;
6-
import com.flipt.api.resources.evaluation.types.VariantEvaluationResponse;
3+
import io.flipt.api.FliptClient;
4+
import io.flipt.api.evaluation.models.*;
75
import dev.openfeature.sdk.EvaluationContext;
86
import dev.openfeature.sdk.EventProvider;
97
import dev.openfeature.sdk.ImmutableMetadata;
@@ -41,13 +39,13 @@ public class FliptProvider extends EventProvider {
4139

4240
@Setter(AccessLevel.PROTECTED)
4341
@Getter
44-
private FliptApiClient fliptApiClient;
42+
private FliptClient fliptClient;
4543

4644
@Setter(AccessLevel.PROTECTED)
4745
@Getter
4846
private ProviderState state = ProviderState.NOT_READY;
4947

50-
private AtomicBoolean isInitialized = new AtomicBoolean(false);
48+
private final AtomicBoolean isInitialized = new AtomicBoolean(false);
5149

5250
/**
5351
* Constructor.
@@ -69,7 +67,7 @@ public void initialize(EvaluationContext evaluationContext) throws Exception {
6967
throw new GeneralError("already initialized");
7068
}
7169
super.initialize(evaluationContext);
72-
fliptApiClient = fliptProviderConfig.getFliptApiClientBuilder().build();
70+
fliptClient = fliptProviderConfig.getFliptClientBuilder().build();
7371

7472
state = ProviderState.READY;
7573
log.info("finished initializing provider, state: {}", state);
@@ -107,14 +105,14 @@ public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defa
107105

108106
BooleanEvaluationResponse response = null;
109107
try {
110-
response = fliptApiClient.evaluation().boolean_(request);
108+
response = fliptClient.evaluation().evaluateBoolean(request);
111109
} catch (Exception e) {
112110
log.error("Error evaluating boolean", e);
113111
throw new GeneralError(e.getMessage());
114112
}
115113

116114
return ProviderEvaluation.<Boolean>builder()
117-
.value(response.getEnabled())
115+
.value(response.isEnabled())
118116
.reason(response.getReason().toString())
119117
.build();
120118
}
@@ -189,27 +187,29 @@ public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultVa
189187

190188
VariantEvaluationResponse response;
191189
try {
192-
response = fliptApiClient.evaluation().variant(request);
190+
response = fliptClient.evaluation().evaluateVariant(request);
193191
} catch (Exception e) {
194192
log.error("Error evaluating variant", e);
195193
throw new GeneralError(e.getMessage());
196194
}
197195

198-
if (!response.getMatch()) {
196+
if (!response.isMatch()) {
199197
log.debug("non matching variant for {} : {}", key, response.getReason());
200198
return ProviderEvaluation.<Value>builder()
201199
.value(defaultValue)
202200
.reason(DEFAULT.name())
203201
.build();
204202
}
205203

204+
Value value = new Value(response.getVariantKey());
206205
ImmutableMetadata.ImmutableMetadataBuilder flagMetadataBuilder = ImmutableMetadata.builder();
207-
if (response.getVariantAttachment() != null) {
206+
if (response.getVariantAttachment() != null && !response.getVariantAttachment().isEmpty()) {
208207
flagMetadataBuilder.addString("variant-attachment", response.getVariantAttachment());
208+
value = new Value(response.getVariantAttachment());
209209
}
210210

211211
return ProviderEvaluation.<Value>builder()
212-
.value(new Value(response.getVariantKey()))
212+
.value(value)
213213
.variant(response.getVariantKey())
214214
.reason(TARGETING_MATCH.name())
215215
.flagMetadata(flagMetadataBuilder.build())

providers/flipt/src/main/java/dev/openfeature/contrib/providers/flipt/FliptProviderConfig.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package dev.openfeature.contrib.providers.flipt;
22

3-
import com.flipt.api.FliptApiClientBuilder;
3+
import io.flipt.api.FliptClient.FliptClientBuilder;
44
import lombok.Builder;
55
import lombok.Getter;
66

@@ -11,7 +11,7 @@
1111
@Getter
1212
@Builder
1313
public class FliptProviderConfig {
14-
private FliptApiClientBuilder fliptApiClientBuilder;
14+
private FliptClientBuilder fliptClientBuilder;
1515

1616
@Builder.Default
1717
private String namespace = "default";

providers/flipt/src/test/java/dev/openfeature/contrib/providers/flipt/FliptProviderTest.java

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
package dev.openfeature.contrib.providers.flipt;
22

3-
import com.flipt.api.FliptApiClient;
4-
import com.flipt.api.FliptApiClientBuilder;
5-
import com.flipt.api.core.Environment;
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import dev.openfeature.sdk.*;
6+
import io.flipt.api.FliptClient;
7+
import io.flipt.api.FliptClient.FliptClientBuilder;
68
import com.github.tomakehurst.wiremock.client.WireMock;
79
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
810
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
9-
import dev.openfeature.sdk.Client;
10-
import dev.openfeature.sdk.FlagEvaluationDetails;
11-
import dev.openfeature.sdk.ImmutableContext;
12-
import dev.openfeature.sdk.ImmutableMetadata;
13-
import dev.openfeature.sdk.MutableContext;
14-
import dev.openfeature.sdk.OpenFeatureAPI;
15-
import dev.openfeature.sdk.ProviderEvaluation;
16-
import dev.openfeature.sdk.ProviderEventDetails;
17-
import dev.openfeature.sdk.ProviderState;
1811
import dev.openfeature.sdk.exceptions.GeneralError;
1912
import dev.openfeature.sdk.exceptions.ProviderNotReadyError;
2013
import lombok.SneakyThrows;
@@ -26,14 +19,15 @@
2619
import java.net.URL;
2720
import java.nio.file.Files;
2821
import java.nio.file.Paths;
22+
import java.util.HashMap;
23+
import java.util.Map;
2924

3025
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
3126
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
3227
import static com.github.tomakehurst.wiremock.client.WireMock.post;
3328
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
3429
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
35-
import static org.junit.jupiter.api.Assertions.assertEquals;
36-
import static org.junit.jupiter.api.Assertions.assertThrows;
30+
import static org.junit.jupiter.api.Assertions.*;
3731

3832
/**
3933
* FliptProvider test, based on APIs mocking.
@@ -51,14 +45,16 @@ class FliptProviderTest {
5145
public static final Double DOUBLE_FLAG_VALUE = 1.23;
5246
public static final String USERS_FLAG_NAME = "users-flag";
5347
public static final String TARGETING_KEY = "targeting_key";
48+
public static final String OBJECT_FLAG_NAME = "object-flag";
49+
5450
private static FliptProvider fliptProvider;
5551
private static Client client;
5652

5753
private String apiUrl;
5854

5955
@BeforeAll
6056
void setUp(WireMockRuntimeInfo wmRuntimeInfo) {
61-
apiUrl = "http://localhost:" + wmRuntimeInfo.getHttpPort() + "/";
57+
apiUrl = "http://localhost:" + wmRuntimeInfo.getHttpPort();
6258
fliptProvider = buildFliptProvider();
6359
OpenFeatureAPI.getInstance().setProviderAndWait("sync", fliptProvider);
6460
client = OpenFeatureAPI.getInstance().getClient("sync");
@@ -72,20 +68,20 @@ public void shutdown() {
7268
private void mockFliptAPI(String url, String resourceName, String flagKey) {
7369
stubFor(
7470
post(urlEqualTo(url))
75-
.withHeader("Content-Type", equalTo("application/json"))
71+
.withHeader("Content-Type", equalTo("application/json; charset=UTF-8"))
7672
.withRequestBody(WireMock.containing(flagKey))
7773
.willReturn(
7874
aResponse()
7975
.withStatus(200)
80-
.withHeader("Content-Type", "application/json")
76+
.withHeader("Content-Type", "application/json; charset=UTF-8")
8177
.withBody(readResourceFileContent(resourceName))));
8278
}
8379

8480
@SneakyThrows
8581
private FliptProvider buildFliptProvider() {
86-
FliptApiClientBuilder fliptApiClientBuilder = FliptApiClient.builder().url(apiUrl).environment(Environment.custom(apiUrl));
82+
FliptClientBuilder fliptClientBuilder = FliptClient.builder().url(apiUrl);
8783
FliptProviderConfig fliptProviderConfig = FliptProviderConfig.builder()
88-
.fliptApiClientBuilder(fliptApiClientBuilder)
84+
.fliptClientBuilder(fliptClientBuilder)
8985
.build();
9086
return new FliptProvider(fliptProviderConfig);
9187
}
@@ -101,7 +97,6 @@ void getBooleanEvaluation() {
10197
mockFliptAPI("/evaluate/v1/boolean", "boolean.json", FLAG_NAME);
10298
MutableContext evaluationContext = new MutableContext();
10399
evaluationContext.setTargetingKey(TARGETING_KEY);
104-
assertEquals(true, fliptProvider.getBooleanEvaluation(FLAG_NAME, false, evaluationContext).getValue());
105100
assertEquals(true, client.getBooleanValue(FLAG_NAME, false, evaluationContext));
106101
assertEquals(false, client.getBooleanValue("non-existing", false, evaluationContext));
107102
}
@@ -111,8 +106,6 @@ void getStringVariantEvaluation() {
111106
mockFliptAPI("/evaluate/v1/variant", "variant.json", VARIANT_FLAG_NAME);
112107
MutableContext evaluationContext = new MutableContext();
113108
evaluationContext.setTargetingKey(TARGETING_KEY);
114-
assertEquals(VARIANT_FLAG_VALUE, fliptProvider.getStringEvaluation(VARIANT_FLAG_NAME, "",
115-
evaluationContext).getValue());
116109
assertEquals(VARIANT_FLAG_VALUE, client.getStringValue(VARIANT_FLAG_NAME, "", evaluationContext));
117110
assertEquals("fallback_str", client.getStringValue("non-existing", "fallback_str", evaluationContext));
118111
}
@@ -123,8 +116,6 @@ void getIntegerEvaluation() {
123116
MutableContext evaluationContext = new MutableContext();
124117
evaluationContext.setTargetingKey(TARGETING_KEY);
125118
evaluationContext.add("userId", "int");
126-
assertEquals(INT_FLAG_VALUE, fliptProvider.getIntegerEvaluation(INT_FLAG_NAME, 1,
127-
evaluationContext).getValue());
128119
assertEquals(INT_FLAG_VALUE, client.getIntegerValue(INT_FLAG_NAME, 1, evaluationContext));
129120
assertEquals(1, client.getIntegerValue("non-existing", 1, evaluationContext));
130121

@@ -138,8 +129,6 @@ void getDoubleEvaluation() {
138129
MutableContext evaluationContext = new MutableContext();
139130
evaluationContext.setTargetingKey(TARGETING_KEY);
140131
evaluationContext.add("userId", "double");
141-
assertEquals(DOUBLE_FLAG_VALUE, fliptProvider.getDoubleEvaluation(DOUBLE_FLAG_NAME, 1.1,
142-
evaluationContext).getValue());
143132
assertEquals(DOUBLE_FLAG_VALUE, client.getDoubleValue(DOUBLE_FLAG_NAME, 1.1, evaluationContext));
144133
assertEquals(1.1, client.getDoubleValue("non-existing", 1.1, evaluationContext));
145134

@@ -153,7 +142,6 @@ void getStringEvaluationByUser() {
153142
MutableContext evaluationContext = new MutableContext();
154143
evaluationContext.setTargetingKey(TARGETING_KEY);
155144
evaluationContext.add("userId", "111");
156-
assertEquals(VARIANT_FLAG_VALUE, fliptProvider.getStringEvaluation(USERS_FLAG_NAME, "", evaluationContext).getValue());
157145
assertEquals(VARIANT_FLAG_VALUE, client.getStringValue(USERS_FLAG_NAME, "", evaluationContext));
158146
evaluationContext.add("userId", "2");
159147
assertEquals("", client.getStringValue(USERS_FLAG_NAME, "", evaluationContext));
@@ -164,12 +152,26 @@ void getEvaluationMetadataTest() {
164152
mockFliptAPI("/evaluate/v1/variant", "variant.json", VARIANT_FLAG_NAME);
165153
MutableContext evaluationContext = new MutableContext();
166154
evaluationContext.setTargetingKey(TARGETING_KEY);
167-
ProviderEvaluation<String> stringEvaluation = fliptProvider.getStringEvaluation(VARIANT_FLAG_NAME, "",
168-
evaluationContext);
169-
ImmutableMetadata flagMetadata = stringEvaluation.getFlagMetadata();
170-
assertEquals("attachment-1", flagMetadata.getString("variant-attachment"));
171155
FlagEvaluationDetails<String> nonExistingFlagEvaluation = client.getStringDetails("non-existing", "", evaluationContext);
172-
assertEquals(null, nonExistingFlagEvaluation.getFlagMetadata().getBoolean("variant-attachment"));
156+
assertNull(nonExistingFlagEvaluation.getFlagMetadata().getBoolean("variant-attachment"));
157+
}
158+
159+
@SneakyThrows
160+
@Test
161+
void getObjectEvaluationTest() {
162+
mockFliptAPI("/evaluate/v1/variant", "variant-object.json", OBJECT_FLAG_NAME);
163+
MutableContext evaluationContext = new MutableContext();
164+
evaluationContext.setTargetingKey(TARGETING_KEY);
165+
evaluationContext.add("userId", "object");
166+
167+
Value expectedValue = new Value("{\"key1\":\"value1\",\"key2\":42,\"key3\":true}");
168+
Value emptyValue = new Value();
169+
170+
assertEquals(expectedValue, client.getObjectValue(OBJECT_FLAG_NAME, emptyValue, evaluationContext));
171+
assertEquals(emptyValue, client.getObjectValue("non-existing", emptyValue, evaluationContext));
172+
173+
// non-object flag value
174+
assertEquals(emptyValue, client.getObjectValue(VARIANT_FLAG_NAME, emptyValue, evaluationContext));
173175
}
174176

175177
@SneakyThrows
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"flagKey": "object-flag",
3+
"match": true,
4+
"variantKey": "object-variant",
5+
"variantAttachment": "{\"key1\":\"value1\",\"key2\":42,\"key3\":true}"
6+
}

0 commit comments

Comments
 (0)