Skip to content

Commit

Permalink
refactor!: Re-packaging
Browse files Browse the repository at this point in the history
  • Loading branch information
fabriziodemaria committed Jun 4, 2024
1 parent 051b2d6 commit 9da6eb9
Show file tree
Hide file tree
Showing 56 changed files with 447 additions and 168 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
# specific files), please put them in your ~/.global-gitignore and not here!
.*
!.git*
/target/
**/target/
*.iml
**dependency-reduced-pom.xml
File renamed without changes.
34 changes: 34 additions & 0 deletions openfeature-provider/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.spotify.confidence</groupId>
<artifactId>confidence-sdk-java</artifactId>
<version>0.0.16-SNAPSHOT</version>
</parent>

<artifactId>openfeature-provider</artifactId>

<dependencies>
<dependency>
<groupId>com.spotify.confidence</groupId>
<artifactId>sdk-java</artifactId>
<version>0.0.16-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>${protobuf.version}</version>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.spotify.confidence;

import static com.spotify.confidence.ConfidenceUtils.FlagPath.getPath;
import static com.spotify.confidence.OpenFeatureUtils.getValueForPath;
import static com.spotify.confidence.FlagResolverClientImpl.OPEN_FEATURE_RESOLVE_CONTEXT_KEY;

import com.google.protobuf.Struct;
import com.spotify.confidence.ConfidenceUtils.FlagPath;
Expand All @@ -28,7 +27,6 @@
/** OpenFeature Provider for feature flagging with the Confidence platform */
public class ConfidenceFeatureProvider implements FeatureProvider {

public static final String OPEN_FEATURE_RESOLVE_CONTEXT_KEY = "open-feature";
private final Confidence confidence;

/**
Expand Down Expand Up @@ -147,7 +145,7 @@ public ProviderEvaluation<Value> getObjectEvaluation(

final FlagPath flagPath;
try {
flagPath = getPath(key);
flagPath = FlagPath.getPath(key);
} catch (IllegalValuePath e) {
log.warn(e.getMessage());
throw new RuntimeException(e);
Expand Down Expand Up @@ -201,7 +199,7 @@ public ProviderEvaluation<Value> getObjectEvaluation(
OpenFeatureTypeMapper.from(resolvedFlag.getValue(), resolvedFlag.getFlagSchema());

// if a path is given, extract expected portion from the structured value
Value value = getValueForPath(flagPath.getPath(), fullValue);
Value value = OpenFeatureUtils.getValueForPath(flagPath.getPath(), fullValue);

if (value.isNull()) {
value = defaultValue;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.spotify.confidence;

import com.google.protobuf.ListValue;
import com.google.protobuf.NullValue;
import com.google.protobuf.Struct;
import com.google.protobuf.util.Values;
import com.spotify.confidence.shaded.flags.types.v1.FlagSchema;
import com.spotify.confidence.shaded.flags.types.v1.FlagSchema.SchemaTypeCase;
import com.spotify.confidence.shaded.flags.types.v1.FlagSchema.StructFlagSchema;
Expand Down Expand Up @@ -103,25 +104,33 @@ public static Value from(Struct struct, StructFlagSchema schema) {

public static com.google.protobuf.Value from(Value val) {
if (val.isNumber()) {
return Values.of(val.asDouble());
return com.google.protobuf.Value.newBuilder().setNumberValue(val.asDouble()).build();
} else if (val.isBoolean()) {
return Values.of(val.asBoolean());
return com.google.protobuf.Value.newBuilder().setBoolValue(val.asBoolean()).build();
} else if (val.isNull()) {
return Values.ofNull();
return com.google.protobuf.Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build();
} else if (val.isInstant()) {
throw new ValueNotConvertableError("Converting Instant Value is currently not supported");
} else if (val.isString()) {
return Values.of(val.asString());
return com.google.protobuf.Value.newBuilder().setStringValue(val.asString()).build();
} else if (val.isList()) {
final List<Value> values = val.asList();
return Values.of(
values.stream().map(OpenFeatureTypeMapper::from).collect(Collectors.toList()));
return com.google.protobuf.Value.newBuilder()
.setListValue(
ListValue.newBuilder()
.addAllValues(
val.asList().stream()
.map(OpenFeatureTypeMapper::from)
.collect(Collectors.toList()))
.build())
.build();
} else if (val.isStructure()) {
final Structure structure = val.asStructure();
final Map<String, com.google.protobuf.Value> protoMap =
structure.asMap().keySet().stream()
.collect(Collectors.toMap(key -> key, key -> from(structure.getValue(key))));
return Values.of(Struct.newBuilder().putAllFields(protoMap).build());
return com.google.protobuf.Value.newBuilder()
.setStructValue(Struct.newBuilder().putAllFields(protoMap).build())
.build();
}
throw new ValueNotConvertableError("Unknown Value type");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@

import com.google.common.annotations.Beta;
import com.google.protobuf.Struct;
import com.google.protobuf.util.Values;
import dev.openfeature.sdk.EvaluationContext;
import dev.openfeature.sdk.Structure;
import dev.openfeature.sdk.Value;
import dev.openfeature.sdk.exceptions.TypeMismatchError;
import io.grpc.netty.shaded.io.netty.util.internal.StringUtil;
import java.util.List;
import org.slf4j.Logger;

Expand Down Expand Up @@ -36,9 +34,13 @@ static Struct convertToProto(EvaluationContext evaluationContext) {
protoEvaluationContext.putFields(mapKey, OpenFeatureTypeMapper.from(mapValue));
});
// add targeting key as a regular value to proto struct
if (!StringUtil.isNullOrEmpty(evaluationContext.getTargetingKey())) {
if (evaluationContext.getTargetingKey() != null
&& !evaluationContext.getTargetingKey().isEmpty()) {
protoEvaluationContext.putFields(
TARGETING_KEY, Values.of(evaluationContext.getTargetingKey()));
TARGETING_KEY,
com.google.protobuf.Value.newBuilder()
.setStringValue(evaluationContext.getTargetingKey())
.build());
}
return protoEvaluationContext.build();
}
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.spotify.confidence;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

import dev.openfeature.sdk.ErrorCode;
import dev.openfeature.sdk.FlagEvaluationDetails;
import dev.openfeature.sdk.ImmutableContext;
import dev.openfeature.sdk.OpenFeatureAPI;
import dev.openfeature.sdk.Reason;
import dev.openfeature.sdk.Value;
import java.io.IOException;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class ConfidenceFeatureProviderTest {

private Confidence root;
private FakeEventSenderEngine fakeEngine;
private ResolverClientTestUtils.FakeFlagResolverClient fakeFlagResolverClient;

@BeforeEach
public void setup() {
fakeEngine = new FakeEventSenderEngine(new FakeClock());
fakeFlagResolverClient = new ResolverClientTestUtils.FakeFlagResolverClient();
root = Confidence.create(fakeEngine, fakeFlagResolverClient);
}

@Test
public void testCloseChildShouldReturnDefaultsFromOpenFeatureApi() throws IOException {
final Confidence child = root.withContext(Map.of("child-key", ConfidenceValue.of("child")));
OpenFeatureAPI.getInstance().setProvider(new ConfidenceFeatureProvider(child));
child.close();
final boolean defaultValue = false;
final FlagEvaluationDetails<Boolean> booleanDetails =
OpenFeatureAPI.getInstance()
.getClient()
.getBooleanDetails(
"some-flag",
defaultValue,
new ImmutableContext("some-key", Map.of("some", new Value("value"))));
assertThat(booleanDetails.getValue()).isEqualTo(defaultValue);
assertThat(booleanDetails.getReason()).isEqualTo(Reason.ERROR.name());
assertThat(booleanDetails.getErrorCode()).isEqualTo(ErrorCode.GENERAL);
assertThat(booleanDetails.getErrorMessage()).isEqualTo("Resource closed");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package com.spotify.confidence;

import com.google.protobuf.Struct;
import com.google.protobuf.util.Structs;
import com.google.protobuf.util.Values;
import com.spotify.confidence.shaded.flags.resolver.v1.ResolveFlagsResponse;
import com.spotify.confidence.shaded.flags.resolver.v1.ResolveReason;
import com.spotify.confidence.shaded.flags.resolver.v1.ResolvedFlag;
import com.spotify.confidence.shaded.flags.types.v1.FlagSchema;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

public class ResolverClientTestUtils {

public static class FakeFlagResolverClient implements FlagResolverClient {

public boolean closed = false;
private Map<String, ConfidenceValue.Struct> resolves = new HashMap<>();

public ResolveFlagsResponse response = generateSampleResponse(Collections.emptyList());

@Override
public CompletableFuture<ResolveFlagsResponse> resolveFlags(
String flag, ConfidenceValue.Struct context, Boolean isProvider) {
resolves.put(flag, context);
return CompletableFuture.completedFuture(response);
}

@Override
public void close() {
closed = true;
}
}

static ResolveFlagsResponse generateSampleResponse(List<ValueSchemaHolder> additionalProps) {
return ResolveFlagsResponse.newBuilder()
.addResolvedFlags(generateResolvedFlag(additionalProps))
.build();
}

static class ValueSchemaHolder {
public ValueSchemaHolder(
String prop, com.google.protobuf.Value value, FlagSchema.SchemaTypeCase schemaTypeCase) {
this.prop = prop;
this.value = value;
this.schemaTypeCase = schemaTypeCase;
}

String prop;
com.google.protobuf.Value value;
FlagSchema.SchemaTypeCase schemaTypeCase;
}

private static ResolvedFlag generateResolvedFlag(List<ValueSchemaHolder> additionalProps) {
final Struct.Builder valueBuilder =
Struct.newBuilder()
.putAllFields(
Map.of(
"prop-A",
Values.of(false),
"prop-B",
Values.of(
Structs.of(
"prop-C", Values.of("str-val"),
"prop-D", Values.of(5.3))),
"prop-E",
Values.of(50),
"prop-F",
Values.of(List.of(Values.of("a"), Values.of("b"))),
"prop-G",
Values.of(
Structs.of(
"prop-H", Values.ofNull(),
"prop-I", Values.ofNull()))));

final FlagSchema.StructFlagSchema.Builder schemaBuilder =
FlagSchema.StructFlagSchema.newBuilder()
.putAllSchema(
Map.of(
"prop-A",
FlagSchema.newBuilder()
.setBoolSchema(FlagSchema.BoolFlagSchema.getDefaultInstance())
.build(),
"prop-B",
FlagSchema.newBuilder()
.setStructSchema(
FlagSchema.StructFlagSchema.newBuilder()
.putAllSchema(
Map.of(
"prop-C",
FlagSchema.newBuilder()
.setStringSchema(
FlagSchema.StringFlagSchema.getDefaultInstance())
.build(),
"prop-D",
FlagSchema.newBuilder()
.setDoubleSchema(
FlagSchema.DoubleFlagSchema.getDefaultInstance())
.build()))
.build())
.build(),
"prop-E",
FlagSchema.newBuilder()
.setIntSchema(FlagSchema.IntFlagSchema.getDefaultInstance())
.build(),
"prop-F",
FlagSchema.newBuilder()
.setListSchema(
FlagSchema.ListFlagSchema.newBuilder()
.setElementSchema(
FlagSchema.newBuilder()
.setStringSchema(
FlagSchema.StringFlagSchema.getDefaultInstance())
.build())
.build())
.build(),
"prop-G",
FlagSchema.newBuilder()
.setStructSchema(
FlagSchema.StructFlagSchema.newBuilder()
.putAllSchema(
Map.of(
"prop-H",
FlagSchema.newBuilder()
.setStringSchema(
FlagSchema.StringFlagSchema.getDefaultInstance())
.build(),
"prop-I",
FlagSchema.newBuilder()
.setIntSchema(
FlagSchema.IntFlagSchema.getDefaultInstance())
.build()))
.build())
.build()));

additionalProps.forEach(
(valueSchemaHolder) -> {
valueBuilder.putFields(valueSchemaHolder.prop, valueSchemaHolder.value);
final FlagSchema.Builder builder = getSchemaBuilder(valueSchemaHolder);
schemaBuilder.putSchema(valueSchemaHolder.prop, builder.build());
});

return ResolvedFlag.newBuilder()
.setFlag("flags/flag")
.setVariant("flags/flag/variants/var-A")
.setReason(ResolveReason.RESOLVE_REASON_MATCH)
.setValue(valueBuilder)
.setFlagSchema(schemaBuilder)
.build();
}

private static FlagSchema.Builder getSchemaBuilder(ValueSchemaHolder valueSchemaHolder) {
final FlagSchema.Builder builder = FlagSchema.newBuilder();
switch (valueSchemaHolder.schemaTypeCase) {
case STRUCT_SCHEMA:
builder.setStructSchema(FlagSchema.StructFlagSchema.getDefaultInstance());
break;
case LIST_SCHEMA:
builder.setListSchema(FlagSchema.ListFlagSchema.getDefaultInstance());
break;
case INT_SCHEMA:
builder.setIntSchema(FlagSchema.IntFlagSchema.getDefaultInstance());
break;
case DOUBLE_SCHEMA:
builder.setDoubleSchema(FlagSchema.DoubleFlagSchema.getDefaultInstance());
break;
case STRING_SCHEMA:
builder.setStringSchema(FlagSchema.StringFlagSchema.getDefaultInstance());
break;
case BOOL_SCHEMA:
builder.setBoolSchema(FlagSchema.BoolFlagSchema.getDefaultInstance());
break;
case SCHEMATYPE_NOT_SET:
break;
}
return builder;
}
}
Loading

0 comments on commit 9da6eb9

Please sign in to comment.