From 7c98857aa812c9bf230fb287a500fef6ece965d1 Mon Sep 17 00:00:00 2001 From: Fabrizio Demaria Date: Wed, 19 Jun 2024 15:32:21 +0200 Subject: [PATCH] refactor: Add ConfidenceWrapper for OF --- .../confidence/ConfidenceFeatureProvider.java | 57 ++----------------- .../ConfidenceFeatureProviderTest.java | 9 +-- .../confidence/FeatureProviderTest.java | 7 ++- .../confidence/FlagResolverContextTest.java | 6 +- .../confidence/ResolverClientTestUtils.java | 2 +- .../com/spotify/confidence/Confidence.java | 44 ++++++++++---- .../confidence/ConfidenceInstance.java | 3 + .../com/spotify/confidence/EventSender.java | 3 +- .../confidence/EventSenderEngineImpl.java | 7 ++- .../com/spotify/confidence/FlagReader.java | 10 ++++ .../confidence/FlagReaderForProvider.java | 16 ++++++ .../com/spotify/confidence/FlagResolver.java | 2 +- .../confidence/FlagResolverClient.java | 7 ++- .../confidence/FlagResolverClientImpl.java | 4 +- .../spotify/confidence/GrpcEventUploader.java | 27 ++++++--- .../spotify/confidence/GrpcFlagResolver.java | 25 +++++--- .../confidence/ConfidenceContextTest.java | 14 ++--- .../ConfidenceResourceManagementTest.java | 33 +---------- .../spotify/confidence/ConfidenceTest.java | 7 ++- .../confidence/GrpcEventUploaderTest.java | 4 +- .../confidence/ResolverClientTestUtils.java | 2 +- 21 files changed, 148 insertions(+), 141 deletions(-) create mode 100644 sdk-java/src/main/java/com/spotify/confidence/ConfidenceInstance.java create mode 100644 sdk-java/src/main/java/com/spotify/confidence/FlagReader.java create mode 100644 sdk-java/src/main/java/com/spotify/confidence/FlagReaderForProvider.java diff --git a/openfeature-provider/src/main/java/com/spotify/confidence/ConfidenceFeatureProvider.java b/openfeature-provider/src/main/java/com/spotify/confidence/ConfidenceFeatureProvider.java index ce8fc84f..9b6dcde7 100644 --- a/openfeature-provider/src/main/java/com/spotify/confidence/ConfidenceFeatureProvider.java +++ b/openfeature-provider/src/main/java/com/spotify/confidence/ConfidenceFeatureProvider.java @@ -15,8 +15,6 @@ import dev.openfeature.sdk.exceptions.FlagNotFoundError; import dev.openfeature.sdk.exceptions.GeneralError; import dev.openfeature.sdk.exceptions.TypeMismatchError; -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.Status.Code; import io.grpc.StatusRuntimeException; import java.util.Map; @@ -27,63 +25,18 @@ /** OpenFeature Provider for feature flagging with the Confidence platform */ public class ConfidenceFeatureProvider implements FeatureProvider { - private final Confidence confidence; - - /** - * ConfidenceFeatureProvider constructor - * - * @param confidence an instance of the Confidence - */ - public ConfidenceFeatureProvider(Confidence confidence) { - this.confidence = confidence; - } + private final FlagReaderForProvider confidence; private static final Logger log = org.slf4j.LoggerFactory.getLogger(ConfidenceFeatureProvider.class); - /** - * ConfidenceFeatureProvider constructor - * - * @param clientSecret generated from the Confidence portal - * @param managedChannel gRPC channel - * @deprecated This constructor is deprecated. Please use {@link - * #ConfidenceFeatureProvider(Confidence)} instead. - */ - @Deprecated() - public ConfidenceFeatureProvider(String clientSecret, ManagedChannel managedChannel) { - this(Confidence.builder(clientSecret).flagResolverManagedChannel(managedChannel).build()); - } - - /** - * ConfidenceFeatureProvider constructor - * - * @param clientSecret generated from the Confidence portal - * @deprecated This constructor is deprecated. Please use {@link - * #ConfidenceFeatureProvider(Confidence)} instead. - */ - @Deprecated() - public ConfidenceFeatureProvider(String clientSecret) { - this(clientSecret, ManagedChannelBuilder.forAddress("edge-grpc.spotify.com", 443).build()); - } - - /** - * ConfidenceFeatureProvider constructor that allows you to override the default gRPC host and - * port, used for local resolver. - * - * @param clientSecret generated from the Confidence portal - * @param host gRPC host you want to connect to. - * @param port port of the gRPC host that you want to use. - * @deprecated This constructor is deprecated. Please use {@link - * #ConfidenceFeatureProvider(Confidence)} instead. - */ - @Deprecated() - public ConfidenceFeatureProvider(String clientSecret, String host, int port) { - this(clientSecret, ManagedChannelBuilder.forAddress(host, port).usePlaintext().build()); + public ConfidenceFeatureProvider(FlagReaderForProvider confidence) { + this.confidence = confidence; } @Override public Metadata getMetadata() { - return () -> "com.spotify.confidence.flags.resolver.v1.FlagResolverService"; + return () -> "ConfidenceProvider"; } @Override @@ -163,7 +116,7 @@ public ProviderEvaluation getObjectEvaluation( Map.of( OPEN_FEATURE_RESOLVE_CONTEXT_KEY, ConfidenceValue.Struct.fromProto(evaluationContext))) - .resolveFlags(requestFlagName, true) + .resolveFlags(requestFlagName, "SDK_ID_JAVA_PROVIDER") .get(); if (resolveFlagResponse.getResolvedFlagsList().isEmpty()) { diff --git a/openfeature-provider/src/test/java/com/spotify/confidence/ConfidenceFeatureProviderTest.java b/openfeature-provider/src/test/java/com/spotify/confidence/ConfidenceFeatureProviderTest.java index 0b3a9597..62b2b911 100644 --- a/openfeature-provider/src/test/java/com/spotify/confidence/ConfidenceFeatureProviderTest.java +++ b/openfeature-provider/src/test/java/com/spotify/confidence/ConfidenceFeatureProviderTest.java @@ -1,6 +1,6 @@ package com.spotify.confidence; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.*; import dev.openfeature.sdk.ErrorCode; @@ -16,7 +16,7 @@ class ConfidenceFeatureProviderTest { - private Confidence root; + private FlagReaderForProvider root; private FakeEventSenderEngine fakeEngine; private ResolverClientTestUtils.FakeFlagResolverClient fakeFlagResolverClient; @@ -24,12 +24,13 @@ class ConfidenceFeatureProviderTest { public void setup() { fakeEngine = new FakeEventSenderEngine(new FakeClock()); fakeFlagResolverClient = new ResolverClientTestUtils.FakeFlagResolverClient(); - root = Confidence.create(fakeEngine, fakeFlagResolverClient); + root = Confidence.createForProvider(fakeEngine, fakeFlagResolverClient); } @Test public void testCloseChildShouldReturnDefaultsFromOpenFeatureApi() throws IOException { - final Confidence child = root.withContext(Map.of("child-key", ConfidenceValue.of("child"))); + final FlagReaderForProvider child = + root.withContext(Map.of("child-key", ConfidenceValue.of("child"))); OpenFeatureAPI.getInstance().setProvider(new ConfidenceFeatureProvider(child)); child.close(); final boolean defaultValue = false; diff --git a/openfeature-provider/src/test/java/com/spotify/confidence/FeatureProviderTest.java b/openfeature-provider/src/test/java/com/spotify/confidence/FeatureProviderTest.java index af7b2646..94bd2ff4 100644 --- a/openfeature-provider/src/test/java/com/spotify/confidence/FeatureProviderTest.java +++ b/openfeature-provider/src/test/java/com/spotify/confidence/FeatureProviderTest.java @@ -9,6 +9,7 @@ import com.google.protobuf.util.Structs; import com.google.protobuf.util.Values; +import com.spotify.confidence.Confidence.ConfidenceMetadata; import com.spotify.confidence.ResolverClientTestUtils.ValueSchemaHolder; import com.spotify.confidence.shaded.flags.resolver.v1.FlagResolverServiceGrpc.FlagResolverServiceImplBase; import com.spotify.confidence.shaded.flags.resolver.v1.ResolveFlagsRequest; @@ -70,8 +71,10 @@ void beforeEach() { final FakeEventSenderEngine fakeEventSender = new FakeEventSenderEngine(new FakeClock()); channel = InProcessChannelBuilder.forName(serverName).directExecutor().build(); final FlagResolverClientImpl flagResolver = - new FlagResolverClientImpl(new GrpcFlagResolver("fake-secret", channel)); - final Confidence confidence = Confidence.create(fakeEventSender, flagResolver); + new FlagResolverClientImpl( + new GrpcFlagResolver("fake-secret", channel, new ConfidenceMetadata(""))); + final FlagReaderForProvider confidence = + Confidence.createForProvider(fakeEventSender, flagResolver); final FeatureProvider featureProvider = new ConfidenceFeatureProvider(confidence); openFeatureAPI = OpenFeatureAPI.getInstance(); diff --git a/openfeature-provider/src/test/java/com/spotify/confidence/FlagResolverContextTest.java b/openfeature-provider/src/test/java/com/spotify/confidence/FlagResolverContextTest.java index 5cf2267b..4d070f2e 100644 --- a/openfeature-provider/src/test/java/com/spotify/confidence/FlagResolverContextTest.java +++ b/openfeature-provider/src/test/java/com/spotify/confidence/FlagResolverContextTest.java @@ -13,14 +13,14 @@ public class FlagResolverContextTest { private FakeFlagResolver fakeFlagResolver; private Client client; - private Confidence confidence; + private FlagReaderForProvider confidence; @BeforeEach void beforeEach() { final FakeEventSenderEngine fakeEventSender = new FakeEventSenderEngine(new FakeClock()); this.fakeFlagResolver = new FakeFlagResolver(); final FlagResolverClientImpl flagResolver = new FlagResolverClientImpl(fakeFlagResolver); - this.confidence = Confidence.create(fakeEventSender, flagResolver); + this.confidence = Confidence.createForProvider(fakeEventSender, flagResolver); final FeatureProvider featureProvider = new ConfidenceFeatureProvider(confidence); final OpenFeatureAPI openFeatureAPI = OpenFeatureAPI.getInstance(); @@ -50,7 +50,7 @@ public void close() {} @Override public CompletableFuture resolve( - String flag, Struct context, Boolean isProvider) { + String flag, Struct context, String providerId) { this.context = context; return null; } diff --git a/openfeature-provider/src/test/java/com/spotify/confidence/ResolverClientTestUtils.java b/openfeature-provider/src/test/java/com/spotify/confidence/ResolverClientTestUtils.java index 672a15fb..5ed39ce4 100644 --- a/openfeature-provider/src/test/java/com/spotify/confidence/ResolverClientTestUtils.java +++ b/openfeature-provider/src/test/java/com/spotify/confidence/ResolverClientTestUtils.java @@ -24,7 +24,7 @@ public static class FakeFlagResolverClient implements FlagResolverClient { @Override public CompletableFuture resolveFlags( - String flag, ConfidenceValue.Struct context, Boolean isProvider) { + String flag, ConfidenceValue.Struct context, String providerId) { resolves.put(flag, context); return CompletableFuture.completedFuture(response); } diff --git a/sdk-java/src/main/java/com/spotify/confidence/Confidence.java b/sdk-java/src/main/java/com/spotify/confidence/Confidence.java index 541580f8..26d86227 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/Confidence.java +++ b/sdk-java/src/main/java/com/spotify/confidence/Confidence.java @@ -10,6 +10,7 @@ import com.google.common.collect.Maps; import com.google.common.io.Closer; import com.spotify.confidence.ConfidenceUtils.FlagPath; +import com.spotify.confidence.ConfidenceValue.Struct; import com.spotify.confidence.Exceptions.IllegalValuePath; import com.spotify.confidence.Exceptions.IllegalValueType; import com.spotify.confidence.Exceptions.IncompatibleValueType; @@ -34,8 +35,7 @@ import org.slf4j.Logger; @Beta -public abstract class Confidence implements EventSender, Closeable { - +public abstract class Confidence implements ConfidenceInstance, FlagReaderForProvider { protected Map context = Maps.newHashMap(); private static final Logger log = org.slf4j.LoggerFactory.getLogger(Confidence.class); @@ -120,7 +120,8 @@ public FlagEvaluation getEvaluation(String key, T defaultValue) { try { final FlagPath flagPath = getPath(key); final String requestFlagName = "flags/" + flagPath.getFlag(); - final ResolveFlagsResponse response = resolveFlags(requestFlagName, false).get(); + final ResolveFlagsResponse response = + resolveFlags(requestFlagName, "SDK_ID_JAVA_CONFIDENCE").get(); if (response.getResolvedFlagsList().isEmpty()) { final String errorMessage = String.format("No active flag '%s' was found", flagPath.getFlag()); @@ -176,12 +177,12 @@ public FlagEvaluation getEvaluation(String key, T defaultValue) { } } - CompletableFuture resolveFlags(String flagName, Boolean isProvider) { - return client().resolveFlags(flagName, getContext(), isProvider); + public CompletableFuture resolveFlags(String flagName, String providerId) { + return client().resolveFlags(flagName, getContext(), providerId); } @VisibleForTesting - static Confidence create( + protected static ConfidenceInstance create( EventSenderEngine eventSenderEngine, FlagResolverClient flagResolverClient) { final Closer closer = Closer.create(); closer.register(eventSenderEngine); @@ -189,6 +190,12 @@ static Confidence create( return new RootInstance(new ClientDelegate(closer, flagResolverClient, eventSenderEngine)); } + @VisibleForTesting + protected static FlagReaderForProvider createForProvider( + EventSenderEngine eventSenderEngine, FlagResolverClient flagResolverClient) { + return (FlagReaderForProvider) create(eventSenderEngine, flagResolverClient); + } + public static Confidence.Builder builder(String clientSecret) { return new Confidence.Builder(clientSecret); } @@ -220,8 +227,8 @@ public void flush() { @Override public CompletableFuture resolveFlags( - String flag, ConfidenceValue.Struct context, Boolean isProvider) { - return flagResolverClient.resolveFlags(flag, context, isProvider); + String flag, Struct context, String providerId) { + return flagResolverClient.resolveFlags(flag, context, providerId); } @Override @@ -301,6 +308,7 @@ public static class Builder { .keepAliveTime(Duration.ofMinutes(5).getSeconds(), TimeUnit.SECONDS) .build(); private ManagedChannel flagResolverManagedChannel = DEFAULT_CHANNEL; + private ConfidenceMetadata metadata = new ConfidenceMetadata("SDK_ID_JAVA_CONFIDENCE"); public Builder(@Nonnull String clientSecret) { this.clientSecret = clientSecret; @@ -319,17 +327,21 @@ public Builder flagResolverManagedChannel(ManagedChannel managedChannel) { return this; } - public Confidence build() { + public ConfidenceInstance build() { final FlagResolverClient flagResolverClient = new FlagResolverClientImpl( - new GrpcFlagResolver(clientSecret, flagResolverManagedChannel)); + new GrpcFlagResolver(clientSecret, flagResolverManagedChannel, metadata)); final EventSenderEngine eventSenderEngine = - new EventSenderEngineImpl(clientSecret, DEFAULT_CHANNEL, Instant::now); + new EventSenderEngineImpl(clientSecret, DEFAULT_CHANNEL, Instant::now, metadata); closer.register(flagResolverClient); closer.register(eventSenderEngine); return new RootInstance(new ClientDelegate(closer, flagResolverClient, eventSenderEngine)); } + public FlagReaderForProvider buildForProvider() { + return (FlagReaderForProvider) build(); + } + private void registerChannelForShutdown(ManagedChannel channel) { this.closer.register( () -> { @@ -343,4 +355,14 @@ private void registerChannelForShutdown(ManagedChannel channel) { }); } } + + public static class ConfidenceMetadata { + String sdkId; + String sdkVersion; + + public ConfidenceMetadata(String sdkId) { + this.sdkId = sdkId; + this.sdkVersion = ConfidenceUtils.getSdkVersion(); + } + } } diff --git a/sdk-java/src/main/java/com/spotify/confidence/ConfidenceInstance.java b/sdk-java/src/main/java/com/spotify/confidence/ConfidenceInstance.java new file mode 100644 index 00000000..43b3b73a --- /dev/null +++ b/sdk-java/src/main/java/com/spotify/confidence/ConfidenceInstance.java @@ -0,0 +1,3 @@ +package com.spotify.confidence; + +public interface ConfidenceInstance extends FlagReader, EventSender {} diff --git a/sdk-java/src/main/java/com/spotify/confidence/EventSender.java b/sdk-java/src/main/java/com/spotify/confidence/EventSender.java index c7e217ba..b59e3562 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/EventSender.java +++ b/sdk-java/src/main/java/com/spotify/confidence/EventSender.java @@ -1,10 +1,11 @@ package com.spotify.confidence; import com.google.common.annotations.Beta; +import java.io.Closeable; import java.util.Map; @Beta -public interface EventSender extends Contextual { +public interface EventSender extends Contextual, Closeable { public void track(String eventName, ConfidenceValue.Struct data); public void track(String eventName); diff --git a/sdk-java/src/main/java/com/spotify/confidence/EventSenderEngineImpl.java b/sdk-java/src/main/java/com/spotify/confidence/EventSenderEngineImpl.java index 949c3bf9..130b812a 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/EventSenderEngineImpl.java +++ b/sdk-java/src/main/java/com/spotify/confidence/EventSenderEngineImpl.java @@ -1,6 +1,7 @@ package com.spotify.confidence; import com.google.common.annotations.VisibleForTesting; +import com.spotify.confidence.Confidence.ConfidenceMetadata; import com.spotify.confidence.events.v1.Event; import dev.failsafe.Failsafe; import dev.failsafe.FailsafeExecutor; @@ -17,7 +18,6 @@ import org.slf4j.Logger; class EventSenderEngineImpl implements EventSenderEngine { - static final String EVENT_NAME_PREFIX = "eventDefinitions/"; static final int DEFAULT_BATCH_SIZE = 25; static final Duration DEFAULT_MAX_FLUSH_INTERVAL = Duration.ofSeconds(60); @@ -64,10 +64,11 @@ class EventSenderEngineImpl implements EventSenderEngine { pollingThread.start(); } - EventSenderEngineImpl(String clientSecret, ManagedChannel channel, Clock clock) { + EventSenderEngineImpl( + String clientSecret, ManagedChannel channel, Clock clock, ConfidenceMetadata metadata) { this( DEFAULT_BATCH_SIZE, - new GrpcEventUploader(clientSecret, clock, channel), + new GrpcEventUploader(clientSecret, clock, channel, metadata), clock, DEFAULT_MAX_FLUSH_INTERVAL, DEFAULT_MAX_MEMORY_CONSUMPTION); diff --git a/sdk-java/src/main/java/com/spotify/confidence/FlagReader.java b/sdk-java/src/main/java/com/spotify/confidence/FlagReader.java new file mode 100644 index 00000000..67c39239 --- /dev/null +++ b/sdk-java/src/main/java/com/spotify/confidence/FlagReader.java @@ -0,0 +1,10 @@ +package com.spotify.confidence; + +import java.io.Closeable; + +public interface FlagReader extends Closeable { + + T getValue(String key, T defaultValue); + + FlagEvaluation getEvaluation(String key, T defaultValue); +} diff --git a/sdk-java/src/main/java/com/spotify/confidence/FlagReaderForProvider.java b/sdk-java/src/main/java/com/spotify/confidence/FlagReaderForProvider.java new file mode 100644 index 00000000..e81fc4b2 --- /dev/null +++ b/sdk-java/src/main/java/com/spotify/confidence/FlagReaderForProvider.java @@ -0,0 +1,16 @@ +package com.spotify.confidence; + +import com.spotify.confidence.shaded.flags.resolver.v1.ResolveFlagsResponse; +import java.io.Closeable; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +public interface FlagReaderForProvider extends Contextual, Closeable { + CompletableFuture resolveFlags(String flagName, String providerId); + + FlagReaderForProvider withContext(ConfidenceValue.Struct context); + + default FlagReaderForProvider withContext(Map context) { + return withContext(ConfidenceValue.Struct.of(context)); + } +} diff --git a/sdk-java/src/main/java/com/spotify/confidence/FlagResolver.java b/sdk-java/src/main/java/com/spotify/confidence/FlagResolver.java index 72be63af..9ecb7377 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/FlagResolver.java +++ b/sdk-java/src/main/java/com/spotify/confidence/FlagResolver.java @@ -8,5 +8,5 @@ interface FlagResolver { void close(); public CompletableFuture resolve( - String flag, Struct context, Boolean isProvider); + String flag, Struct context, String providerId); } diff --git a/sdk-java/src/main/java/com/spotify/confidence/FlagResolverClient.java b/sdk-java/src/main/java/com/spotify/confidence/FlagResolverClient.java index 0c60efec..4984679a 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/FlagResolverClient.java +++ b/sdk-java/src/main/java/com/spotify/confidence/FlagResolverClient.java @@ -1,10 +1,15 @@ package com.spotify.confidence; +import com.spotify.confidence.ConfidenceValue.Struct; import com.spotify.confidence.shaded.flags.resolver.v1.ResolveFlagsResponse; import java.io.Closeable; import java.util.concurrent.CompletableFuture; interface FlagResolverClient extends Closeable { CompletableFuture resolveFlags( - String flag, ConfidenceValue.Struct context, Boolean isProvider); + String flag, Struct context, String providerId); + + default CompletableFuture resolveFlags(String flag, String providerId) { + return resolveFlags(flag, ConfidenceValue.Struct.builder().build(), providerId); + } } diff --git a/sdk-java/src/main/java/com/spotify/confidence/FlagResolverClientImpl.java b/sdk-java/src/main/java/com/spotify/confidence/FlagResolverClientImpl.java index 5cc01821..3d7f6758 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/FlagResolverClientImpl.java +++ b/sdk-java/src/main/java/com/spotify/confidence/FlagResolverClientImpl.java @@ -14,7 +14,7 @@ public FlagResolverClientImpl(FlagResolver grpcFlagResolver) { } public CompletableFuture resolveFlags( - String flagName, ConfidenceValue.Struct context, Boolean isProvider) { + String flagName, ConfidenceValue.Struct context, String providerId) { final Struct.Builder evaluationContextBuilder = context.toProto().getStructValue().toBuilder(); if (context.asMap().containsKey(OPEN_FEATURE_RESOLVE_CONTEXT_KEY)) { final Value openFeatureEvaluationContext = @@ -25,7 +25,7 @@ public CompletableFuture resolveFlags( evaluationContextBuilder.removeFields(OPEN_FEATURE_RESOLVE_CONTEXT_KEY); } - return this.grpcFlagResolver.resolve(flagName, evaluationContextBuilder.build(), isProvider); + return this.grpcFlagResolver.resolve(flagName, evaluationContextBuilder.build(), providerId); } @Override diff --git a/sdk-java/src/main/java/com/spotify/confidence/GrpcEventUploader.java b/sdk-java/src/main/java/com/spotify/confidence/GrpcEventUploader.java index a5867561..df3fc4c9 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/GrpcEventUploader.java +++ b/sdk-java/src/main/java/com/spotify/confidence/GrpcEventUploader.java @@ -1,6 +1,7 @@ package com.spotify.confidence; import com.google.common.collect.ImmutableSet; +import com.spotify.confidence.Confidence.ConfidenceMetadata; import com.spotify.confidence.events.v1.Event; import com.spotify.confidence.events.v1.EventsServiceGrpc; import com.spotify.confidence.events.v1.PublishEventsRequest; @@ -16,7 +17,6 @@ import org.slf4j.Logger; class GrpcEventUploader implements EventUploader { - private final Set RETRYABLE_STATUS_CODES = ImmutableSet.of( Status.Code.UNKNOWN, @@ -26,24 +26,33 @@ class GrpcEventUploader implements EventUploader { Status.Code.ABORTED, Status.Code.INTERNAL, Status.Code.DATA_LOSS); + private final Sdk.Builder sdkBuilder = + Sdk.newBuilder().setVersion(ConfidenceUtils.getSdkVersion()); private final String clientSecret; private final Sdk sdk; - private final ManagedChannel managedChannel; private final EventsServiceGrpc.EventsServiceFutureStub stub; private final Clock clock; private static final Logger log = org.slf4j.LoggerFactory.getLogger(GrpcEventUploader.class); - GrpcEventUploader(String clientSecret, Clock clock, ManagedChannel managedChannel) { + GrpcEventUploader( + String clientSecret, + Clock clock, + ManagedChannel managedChannel, + ConfidenceMetadata metadata) { this.clientSecret = clientSecret; - this.managedChannel = managedChannel; this.stub = EventsServiceGrpc.newFutureStub(managedChannel); this.clock = clock; - this.sdk = - Sdk.newBuilder() - .setId(SdkId.SDK_ID_JAVA_CONFIDENCE) - .setVersion(ConfidenceUtils.getSdkVersion()) - .build(); + this.sdk = getSdkId(metadata); + } + + private Sdk getSdkId(ConfidenceMetadata metadata) { + try { + sdkBuilder.setId(SdkId.SDK_ID_JAVA_CONFIDENCE); + } catch (IllegalArgumentException e) { + sdkBuilder.setCustomId(metadata.sdkId); + } + return sdkBuilder.build(); } @Override diff --git a/sdk-java/src/main/java/com/spotify/confidence/GrpcFlagResolver.java b/sdk-java/src/main/java/com/spotify/confidence/GrpcFlagResolver.java index 41f70d17..1c76e809 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/GrpcFlagResolver.java +++ b/sdk-java/src/main/java/com/spotify/confidence/GrpcFlagResolver.java @@ -2,6 +2,7 @@ import com.google.common.base.Strings; import com.google.protobuf.Struct; +import com.spotify.confidence.Confidence.ConfidenceMetadata; import com.spotify.confidence.shaded.flags.resolver.v1.*; import com.spotify.confidence.shaded.flags.resolver.v1.Sdk.Builder; import io.grpc.ManagedChannel; @@ -13,20 +14,23 @@ public class GrpcFlagResolver implements FlagResolver { private final ManagedChannel managedChannel; private final String clientSecret; private final Builder sdkBuilder = Sdk.newBuilder().setVersion(ConfidenceUtils.getSdkVersion()); + private final ConfidenceMetadata metadata; private final FlagResolverServiceGrpc.FlagResolverServiceFutureStub stub; - public GrpcFlagResolver(String clientSecret, ManagedChannel managedChannel) { + public GrpcFlagResolver( + String clientSecret, ManagedChannel managedChannel, ConfidenceMetadata metadata) { if (Strings.isNullOrEmpty(clientSecret)) { throw new IllegalArgumentException("clientSecret must be a non-empty string."); } this.clientSecret = clientSecret; this.managedChannel = managedChannel; + this.metadata = metadata; this.stub = FlagResolverServiceGrpc.newFutureStub(managedChannel); } public CompletableFuture resolve( - String flag, Struct context, Boolean isProvider) { + String flag, Struct context, String providerId) { return GrpcUtil.toCompletableFuture( stub.withDeadlineAfter(10, TimeUnit.SECONDS) .resolveFlags( @@ -34,17 +38,20 @@ public CompletableFuture resolve( .setClientSecret(this.clientSecret) .addAllFlags(List.of(flag)) .setEvaluationContext(context) - .setSdk( - sdkBuilder - .setId( - isProvider - ? SdkId.SDK_ID_JAVA_PROVIDER - : SdkId.SDK_ID_JAVA_CONFIDENCE) - .build()) + .setSdk(getSdkId(metadata, providerId)) .setApply(true) .build())); } + private Sdk getSdkId(ConfidenceMetadata metadata, String providerId) { + try { + sdkBuilder.setId(SdkId.valueOf(providerId)); + } catch (IllegalArgumentException e) { + sdkBuilder.setCustomId(providerId); + } + return sdkBuilder.build(); + } + public void close() { managedChannel.shutdownNow(); } diff --git a/sdk-java/src/test/java/com/spotify/confidence/ConfidenceContextTest.java b/sdk-java/src/test/java/com/spotify/confidence/ConfidenceContextTest.java index e36447bd..a27e4d52 100644 --- a/sdk-java/src/test/java/com/spotify/confidence/ConfidenceContextTest.java +++ b/sdk-java/src/test/java/com/spotify/confidence/ConfidenceContextTest.java @@ -15,7 +15,7 @@ public class ConfidenceContextTest { @Test public void testThrowInvalidContextInMessage() { - final Confidence root = Confidence.create(fakeEngine, fakeFlagResolverClient); + final ConfidenceInstance root = Confidence.create(fakeEngine, fakeFlagResolverClient); assertThrows( Exceptions.InvalidContextInMessaageError.class, () -> @@ -24,7 +24,7 @@ public void testThrowInvalidContextInMessage() { @Test public void getContextContainsParentContextValues() { - final Confidence root = Confidence.create(fakeEngine, fakeFlagResolverClient); + final ConfidenceInstance root = Confidence.create(fakeEngine, fakeFlagResolverClient); root.updateContextEntry("page", ConfidenceValue.of("http://..")); final EventSender confidence = root.withContext(ImmutableMap.of("pants", ConfidenceValue.of("yellow"))); @@ -41,7 +41,7 @@ public void getContextContainsParentContextValues() { @Test public void setContextOverwritesContext() { - final Confidence root = Confidence.create(fakeEngine, fakeFlagResolverClient); + final ConfidenceInstance root = Confidence.create(fakeEngine, fakeFlagResolverClient); root.updateContextEntry("page", ConfidenceValue.of("http://..")); final EventSender confidence = root.withContext(ImmutableMap.of("pants", ConfidenceValue.of("yellow"))); @@ -65,7 +65,7 @@ public void setContextOverwritesContext() { @Test public void parentContextFieldCanBeOverridden() { - final Confidence root = Confidence.create(fakeEngine, fakeFlagResolverClient); + final ConfidenceInstance root = Confidence.create(fakeEngine, fakeFlagResolverClient); root.updateContextEntry("pants-color", ConfidenceValue.of("yellow")); final EventSender confidence = root.withContext(ImmutableMap.of("pants-color", ConfidenceValue.of("blue"))); @@ -83,7 +83,7 @@ public void parentContextFieldCanBeOverridden() { @Test public void parentContextFieldCanBeOverriddenOrRemoved() { - final Confidence root = Confidence.create(fakeEngine, fakeFlagResolverClient); + final ConfidenceInstance root = Confidence.create(fakeEngine, fakeFlagResolverClient); root.updateContextEntry("pants-color", ConfidenceValue.of("yellow")); final EventSender confidence = root.withContext(ImmutableMap.of("shirt-color", ConfidenceValue.of("blue"))); @@ -98,9 +98,9 @@ public void parentContextFieldCanBeOverriddenOrRemoved() { @Test public void multiLevelContexts() { - final Confidence root = Confidence.create(fakeEngine, fakeFlagResolverClient); + final ConfidenceInstance root = Confidence.create(fakeEngine, fakeFlagResolverClient); final int numberOfLevels = 9; - Confidence last = root; + EventSender last = root; for (int i = 0; i < numberOfLevels; i++) { last = last.withContext( diff --git a/sdk-java/src/test/java/com/spotify/confidence/ConfidenceResourceManagementTest.java b/sdk-java/src/test/java/com/spotify/confidence/ConfidenceResourceManagementTest.java index 8c4d0449..0412efa9 100644 --- a/sdk-java/src/test/java/com/spotify/confidence/ConfidenceResourceManagementTest.java +++ b/sdk-java/src/test/java/com/spotify/confidence/ConfidenceResourceManagementTest.java @@ -4,13 +4,12 @@ import java.io.IOException; import java.util.Map; -import java.util.concurrent.ExecutionException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class ConfidenceResourceManagementTest { - private Confidence root; + private ConfidenceInstance root; private FakeEventSenderEngine fakeEngine; private ResolverClientTestUtils.FakeFlagResolverClient fakeFlagResolverClient; @@ -21,16 +20,9 @@ public void setup() { root = Confidence.create(fakeEngine, fakeFlagResolverClient); } - @Test - public void testCloseChildShouldThrowFromResolveFlags() throws IOException { - final Confidence child = root.withContext(Map.of("child-key", ConfidenceValue.of("child"))); - child.close(); - assertThrows(IllegalStateException.class, () -> child.resolveFlags("test", false).get()); - } - @Test public void testCloseChildShouldNotCloseParentEngine() throws IOException { - final Confidence child = root.withContext(Map.of("child-key", ConfidenceValue.of("child"))); + final EventSender child = root.withContext(Map.of("child-key", ConfidenceValue.of("child"))); child.close(); assertFalse(fakeEngine.closed); assertFalse(fakeFlagResolverClient.closed); @@ -38,27 +30,8 @@ public void testCloseChildShouldNotCloseParentEngine() throws IOException { @Test public void testCloseChildShouldNotThrowFromSend() throws IOException { - final Confidence child = root.withContext(Map.of("child-key", ConfidenceValue.of("child"))); + final EventSender child = root.withContext(Map.of("child-key", ConfidenceValue.of("child"))); child.close(); child.track("Test"); } - - @Test - public void testCloseChildShouldNotAffectParent() - throws IOException, ExecutionException, InterruptedException { - final Confidence child = root.withContext(Map.of("child-key", ConfidenceValue.of("child"))); - child.close(); - root.resolveFlags("test", false).get(); - root.track("test", ConfidenceValue.of(Map.of("messageKey", ConfidenceValue.of("parent")))); - } - - @Test - public void testCloseParentShouldAffectChild() throws IOException { - final Confidence child = root.withContext(Map.of("child-key", ConfidenceValue.of("child"))); - root.close(); - assertThrows(IllegalStateException.class, () -> child.resolveFlags("test", false).get()); - assertThrows(IllegalStateException.class, () -> root.resolveFlags("test", false).get()); - assertTrue(fakeEngine.closed); - assertTrue(fakeFlagResolverClient.closed); - } } diff --git a/sdk-java/src/test/java/com/spotify/confidence/ConfidenceTest.java b/sdk-java/src/test/java/com/spotify/confidence/ConfidenceTest.java index 2894b75e..0e5c3bab 100644 --- a/sdk-java/src/test/java/com/spotify/confidence/ConfidenceTest.java +++ b/sdk-java/src/test/java/com/spotify/confidence/ConfidenceTest.java @@ -22,7 +22,7 @@ final class ConfidenceTest { private final FakeEventSenderEngine fakeEngine = new FakeEventSenderEngine(new FakeClock()); private final ResolverClientTestUtils.FakeFlagResolverClient fakeFlagResolverClient = new ResolverClientTestUtils.FakeFlagResolverClient(); - private static Confidence confidence; + private static ConfidenceInstance confidence; @BeforeEach void beforeEach() { @@ -244,7 +244,8 @@ void flagWithErroneousSchema() { @Test void internalError() { - final Confidence confidence = Confidence.create(fakeEngine, new FailingFlagResolverClient()); + final ConfidenceInstance confidence = + Confidence.create(fakeEngine, new FailingFlagResolverClient()); final Integer value = confidence.getValue("no-match-flag", 20); assertEquals(20, value); @@ -262,7 +263,7 @@ public static class FailingFlagResolverClient implements FlagResolverClient { @Override public CompletableFuture resolveFlags( - String flag, Struct context, Boolean isProvider) { + String flag, Struct context, String providerId) { throw new RuntimeException("Crashing while performing network call"); } diff --git a/sdk-java/src/test/java/com/spotify/confidence/GrpcEventUploaderTest.java b/sdk-java/src/test/java/com/spotify/confidence/GrpcEventUploaderTest.java index 31f9e480..e3d2102c 100644 --- a/sdk-java/src/test/java/com/spotify/confidence/GrpcEventUploaderTest.java +++ b/sdk-java/src/test/java/com/spotify/confidence/GrpcEventUploaderTest.java @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableMap; import com.google.protobuf.Timestamp; +import com.spotify.confidence.Confidence.ConfidenceMetadata; import com.spotify.confidence.events.v1.EventError; import com.spotify.confidence.events.v1.EventError.Reason; import com.spotify.confidence.events.v1.EventsServiceGrpc; @@ -54,7 +55,8 @@ public void setUp() throws IOException { fakeClock.setCurrentTimeSeconds(1337); // Create a client that uses the channel - uploader = new GrpcEventUploader("my-client-secret", fakeClock, channel); + uploader = + new GrpcEventUploader("my-client-secret", fakeClock, channel, new ConfidenceMetadata("")); } @AfterEach diff --git a/sdk-java/src/test/java/com/spotify/confidence/ResolverClientTestUtils.java b/sdk-java/src/test/java/com/spotify/confidence/ResolverClientTestUtils.java index 0f8fe3fd..4e7d046d 100644 --- a/sdk-java/src/test/java/com/spotify/confidence/ResolverClientTestUtils.java +++ b/sdk-java/src/test/java/com/spotify/confidence/ResolverClientTestUtils.java @@ -24,7 +24,7 @@ public static class FakeFlagResolverClient implements FlagResolverClient { @Override public CompletableFuture resolveFlags( - String flag, ConfidenceValue.Struct context, Boolean isProvider) { + String flag, ConfidenceValue.Struct context, String providerId) { resolves.put(flag, context); return CompletableFuture.completedFuture(response); }