Skip to content

Commit e221402

Browse files
authored
fix(flipt): set variant attachment as value for object evaluation (#956)
Signed-off-by: Mark Phelps <[email protected]>
1 parent 3e9b967 commit e221402

File tree

5 files changed

+80
-16
lines changed

5 files changed

+80
-16
lines changed

Diff for: providers/flipt/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
## Concepts
2020

2121
* Boolean evaluation gets feature boolean evaluation / enabled status.
22-
* Non-boolean evaluation gets feature variant key.
22+
* Object evaluation gets variant attachment.
23+
* Other evaluations gets feature variant key.
2324

2425
## Usage
2526

Diff for: providers/flipt/pom.xml

+15
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@
2020
<javadoc.failOnWarnings>false</javadoc.failOnWarnings>
2121
</properties>
2222

23+
<developers>
24+
<developer>
25+
<id>markphelps</id>
26+
<name>Mark Phelps</name>
27+
<organization>Flipt Software</organization>
28+
<url>https://flipt.io/</url>
29+
</developer>
30+
</developers>
31+
2332
<dependencies>
2433
<dependency>
2534
<groupId>io.flipt</groupId>
@@ -33,6 +42,12 @@
3342
<version>2.0.16</version>
3443
</dependency>
3544

45+
<dependency>
46+
<groupId>com.fasterxml.jackson.core</groupId>
47+
<artifactId>jackson-databind</artifactId>
48+
<version>2.17.2</version>
49+
</dependency>
50+
3651
<dependency>
3752
<groupId>com.github.tomakehurst</groupId>
3853
<artifactId>wiremock-jre8</artifactId>

Diff for: providers/flipt/src/main/java/dev/openfeature/contrib/providers/flipt/FliptProvider.java

+34-10
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ public class FliptProvider extends EventProvider {
4040
@Getter
4141
private FliptClient fliptClient;
4242

43-
private AtomicBoolean isInitialized = new AtomicBoolean(false);
43+
@Setter(AccessLevel.PROTECTED)
44+
@Getter
45+
private ProviderState state = ProviderState.NOT_READY;
46+
47+
private final AtomicBoolean isInitialized = new AtomicBoolean(false);
4448

4549
/**
4650
* Constructor.
@@ -96,7 +100,8 @@ public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defa
96100

97101
@Override
98102
public ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx) {
99-
ProviderEvaluation<Value> valueProviderEvaluation = getObjectEvaluation(key, new Value(defaultValue), ctx);
103+
ProviderEvaluation<Value> valueProviderEvaluation =
104+
evaluateVariant(String.class, key, new Value(defaultValue), ctx);
100105
return ProviderEvaluation.<String>builder()
101106
.value(valueProviderEvaluation.getValue().asString())
102107
.variant(valueProviderEvaluation.getVariant())
@@ -108,7 +113,8 @@ public ProviderEvaluation<String> getStringEvaluation(String key, String default
108113

109114
@Override
110115
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx) {
111-
ProviderEvaluation<Value> valueProviderEvaluation = getObjectEvaluation(key, new Value(defaultValue), ctx);
116+
ProviderEvaluation<Value> valueProviderEvaluation =
117+
evaluateVariant(Integer.class, key, new Value(defaultValue), ctx);
112118
Integer value = getIntegerValue(valueProviderEvaluation, defaultValue);
113119
return ProviderEvaluation.<Integer>builder()
114120
.value(value)
@@ -130,7 +136,8 @@ private static Integer getIntegerValue(ProviderEvaluation<Value> valueProviderEv
130136

131137
@Override
132138
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue, EvaluationContext ctx) {
133-
ProviderEvaluation<Value> valueProviderEvaluation = getObjectEvaluation(key, new Value(defaultValue), ctx);
139+
ProviderEvaluation<Value> valueProviderEvaluation =
140+
evaluateVariant(Double.class, key, new Value(defaultValue), ctx);
134141
Double value = getDoubleValue(valueProviderEvaluation, defaultValue);
135142
return ProviderEvaluation.<Double>builder()
136143
.value(value)
@@ -152,6 +159,18 @@ private static Double getDoubleValue(ProviderEvaluation<Value> valueProviderEval
152159

153160
@Override
154161
public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultValue, EvaluationContext ctx) {
162+
return evaluateVariant(Value.class, key, defaultValue, ctx);
163+
}
164+
165+
private <T> ProviderEvaluation<Value> evaluateVariant(Class<T> clazz, String key, Value defaultValue,
166+
EvaluationContext ctx) {
167+
if (!ProviderState.READY.equals(state)) {
168+
if (ProviderState.NOT_READY.equals(state)) {
169+
throw new ProviderNotReadyError(PROVIDER_NOT_YET_INITIALIZED);
170+
}
171+
throw new GeneralError(UNKNOWN_ERROR);
172+
}
173+
155174
Map<String, String> contextMap = ContextTransformer.transform(ctx);
156175
EvaluationRequest request = EvaluationRequest.builder().namespaceKey(fliptProviderConfig.getNamespace())
157176
.flagKey(key).entityId(ctx.getTargetingKey()).context(contextMap).build();
@@ -172,17 +191,22 @@ public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultVa
172191
.build();
173192
}
174193

194+
Value value = new Value(response.getVariantKey());
175195
ImmutableMetadata.ImmutableMetadataBuilder flagMetadataBuilder = ImmutableMetadata.builder();
176-
if (response.getVariantAttachment() != null) {
196+
if (response.getVariantAttachment() != null && !response.getVariantAttachment().isEmpty()) {
177197
flagMetadataBuilder.addString("variant-attachment", response.getVariantAttachment());
198+
199+
if (clazz.isAssignableFrom(Value.class)) {
200+
value = new Value(response.getVariantAttachment());
201+
}
178202
}
179203

180204
return ProviderEvaluation.<Value>builder()
181-
.value(new Value(response.getVariantKey()))
182-
.variant(response.getVariantKey())
183-
.reason(TARGETING_MATCH.name())
184-
.flagMetadata(flagMetadataBuilder.build())
185-
.build();
205+
.value(value)
206+
.variant(response.getVariantKey())
207+
.reason(TARGETING_MATCH.name())
208+
.flagMetadata(flagMetadataBuilder.build())
209+
.build();
186210
}
187211

188212
@Override

Diff for: providers/flipt/src/test/java/dev/openfeature/contrib/providers/flipt/FliptProviderTest.java

+23-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import dev.openfeature.sdk.ProviderEvaluation;
1515
import dev.openfeature.sdk.ProviderEventDetails;
1616
import dev.openfeature.sdk.ProviderState;
17+
import dev.openfeature.sdk.Value;
1718
import dev.openfeature.sdk.exceptions.GeneralError;
1819
import dev.openfeature.sdk.exceptions.ProviderNotReadyError;
1920
import lombok.SneakyThrows;
@@ -31,8 +32,7 @@
3132
import static com.github.tomakehurst.wiremock.client.WireMock.post;
3233
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
3334
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
34-
import static org.junit.jupiter.api.Assertions.assertEquals;
35-
import static org.junit.jupiter.api.Assertions.assertThrows;
35+
import static org.junit.jupiter.api.Assertions.*;
3636

3737
/**
3838
* FliptProvider test, based on APIs mocking.
@@ -50,9 +50,10 @@ class FliptProviderTest {
5050
public static final Double DOUBLE_FLAG_VALUE = 1.23;
5151
public static final String USERS_FLAG_NAME = "users-flag";
5252
public static final String TARGETING_KEY = "targeting_key";
53+
public static final String OBJECT_FLAG_NAME = "object-flag";
54+
5355
private static FliptProvider fliptProvider;
5456
private static Client client;
55-
5657
private String apiUrl;
5758

5859
@BeforeAll
@@ -101,7 +102,6 @@ void getBooleanEvaluation() {
101102
mockFliptAPI("/evaluate/v1/boolean", "boolean.json", FLAG_NAME);
102103
MutableContext evaluationContext = new MutableContext();
103104
evaluationContext.setTargetingKey(TARGETING_KEY);
104-
assertEquals(true, fliptProvider.getBooleanEvaluation(FLAG_NAME, false, evaluationContext).getValue());
105105
assertEquals(true, client.getBooleanValue(FLAG_NAME, false, evaluationContext));
106106
assertEquals(false, client.getBooleanValue("non-existing", false, evaluationContext));
107107
}
@@ -171,6 +171,24 @@ void getEvaluationMetadataTest() {
171171
assertEquals("attachment-1", flagMetadata.getString("variant-attachment"));
172172
FlagEvaluationDetails<String> nonExistingFlagEvaluation = client.getStringDetails("non-existing", "",
173173
evaluationContext);
174-
assertEquals(null, nonExistingFlagEvaluation.getFlagMetadata().getBoolean("variant-attachment"));
174+
assertNull(nonExistingFlagEvaluation.getFlagMetadata().getBoolean("variant-attachment"));
175+
}
176+
177+
@SneakyThrows
178+
@Test
179+
void getObjectEvaluationTest() {
180+
mockFliptAPI("/evaluate/v1/variant", "variant-object.json", OBJECT_FLAG_NAME);
181+
MutableContext evaluationContext = new MutableContext();
182+
evaluationContext.setTargetingKey(TARGETING_KEY);
183+
evaluationContext.add("userId", "object");
184+
185+
Value expectedValue = new Value("{\"key1\":\"value1\",\"key2\":42,\"key3\":true}");
186+
Value emptyValue = new Value();
187+
188+
assertEquals(expectedValue, client.getObjectValue(OBJECT_FLAG_NAME, emptyValue, evaluationContext));
189+
assertEquals(emptyValue, client.getObjectValue("non-existing", emptyValue, evaluationContext));
190+
191+
// non-object flag value
192+
assertEquals(emptyValue, client.getObjectValue(VARIANT_FLAG_NAME, emptyValue, evaluationContext));
175193
}
176194
}
+6
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)