Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public DevCycleCloudClient(String sdkKey, DevCycleCloudOptions options) {
OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);

this.openFeatureProvider = new DevCycleProvider(this);
this.evalHooksRunner = new EvalHooksRunner();
this.evalHooksRunner = new EvalHooksRunner(dvcOptions.getHooks());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

import com.devcycle.sdk.server.common.api.IRestOptions;
import com.devcycle.sdk.server.common.logging.IDevCycleLogger;
import com.devcycle.sdk.server.common.model.EvalHook;
import com.devcycle.sdk.server.common.model.IDevCycleOptions;
import lombok.Builder;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
@Builder
public class DevCycleCloudOptions {
Expand All @@ -21,6 +25,9 @@ public class DevCycleCloudOptions {
@Builder.Default
private IRestOptions restOptions = null;

@Builder.Default
private List<EvalHook> hooks = new ArrayList<>();

public static class DevCycleCloudOptionsBuilder implements IDevCycleOptions {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ public class EvalHooksRunner<T> {
/**
* Default constructor initializes an empty list of hooks.
*/
public EvalHooksRunner(List<EvalHook<T>> hooks) {
if (hooks == null) {
this.hooks = new ArrayList<>();
} else {
this.hooks = hooks;
}
}

public EvalHooksRunner() {
this.hooks = new ArrayList<>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public DevCycleLocalClient(String sdkKey, DevCycleLocalOptions dvcOptions) {
} catch (Exception e) {
DevCycleLogger.error("Error creating event queue due to error: " + e.getMessage());
}
this.evalHooksRunner = new EvalHooksRunner();
this.evalHooksRunner = new EvalHooksRunner(dvcOptions.getHooks());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
import com.devcycle.sdk.server.common.api.IRestOptions;
import com.devcycle.sdk.server.common.logging.DevCycleLogger;
import com.devcycle.sdk.server.common.logging.IDevCycleLogger;
import com.devcycle.sdk.server.common.model.EvalHook;
import com.devcycle.sdk.server.common.model.IDevCycleOptions;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Builder;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
public class DevCycleLocalOptions implements IDevCycleOptions {
private int configRequestTimeoutMs = 10000;
Expand Down Expand Up @@ -41,6 +45,8 @@ public class DevCycleLocalOptions implements IDevCycleOptions {
private boolean disableCustomEventLogging = false;
@JsonIgnore
private IRestOptions restOptions = null;
@JsonIgnore
private List<EvalHook> hooks = new ArrayList<>();

@Builder()
public DevCycleLocalOptions(
Expand All @@ -60,7 +66,8 @@ public DevCycleLocalOptions(
IRestOptions restOptions,
@Deprecated
boolean enableBetaRealtimeUpdates,
boolean disableRealtimeUpdates
boolean disableRealtimeUpdates,
List<EvalHook> hooks
) {
this.configRequestTimeoutMs = configRequestTimeoutMs > 0 ? configRequestTimeoutMs : this.configRequestTimeoutMs;
this.configPollingIntervalMS = getConfigPollingIntervalMS(configPollingIntervalMs, configPollingIntervalMS);
Expand All @@ -76,6 +83,7 @@ public DevCycleLocalOptions(
this.restOptions = restOptions;
this.enableBetaRealtimeUpdates = enableBetaRealtimeUpdates;
this.disableRealtimeUpdates = disableRealtimeUpdates;
this.hooks = hooks;

if (this.flushEventQueueSize >= this.maxEventQueueSize) {
DevCycleLogger.warning("flushEventQueueSize: " + this.flushEventQueueSize + " must be smaller than maxEventQueueSize: " + this.maxEventQueueSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.devcycle.sdk.server.common.model.*;
import com.devcycle.sdk.server.helpers.WhiteBox;
import dev.openfeature.sdk.Hook;
import net.bytebuddy.implementation.bytecode.Throw;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -23,6 +24,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.*;

import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -747,6 +749,96 @@ public void onFinally(HookContext<String> ctx, Optional<Variable<String>> variab
Assert.assertTrue(finallyCalled[0]);
}

@Test
public void client_withHooksInOptions_addsHooksToEvalRunner() {
DevCycleUser user = DevCycleUser.builder()
.userId("j_test")
.build();

final boolean[] beforeCalled = {false, false};
final boolean[] afterCalled = {false, false};
final boolean[] finallyCalled = {false, false};
final boolean[] errorCalled = {false, false};

List<EvalHook> hooks = new ArrayList<>();
hooks.add(new EvalHook<String>() {
@Override
public Optional<HookContext<String>> before(HookContext<String> ctx) {
beforeCalled[0] = true;
return Optional.empty();
}

@Override
public void after(HookContext<String> ctx, Variable<String> variable) {
afterCalled[0] = true;
}

@Override
public void onFinally(HookContext<String> ctx, Optional<Variable<String>> variable) {
finallyCalled[0] = true;
}

@Override
public void error(HookContext<String> ctx, Throwable e) {
errorCalled[0] = true;
}
});
hooks.add(new EvalHook<String>() {
@Override
public Optional<HookContext<String>> before(HookContext<String> ctx) {
beforeCalled[1] = true;
return Optional.empty();
}

@Override
public void after(HookContext<String> ctx, Variable<String> variable) {
afterCalled[1] = true;
}

@Override
public void onFinally(HookContext<String> ctx, Optional<Variable<String>> variable) {
finallyCalled[1] = true;
}

@Override
public void error(HookContext<String> ctx, Throwable e) {
errorCalled[1] = true;
}
});

DevCycleCloudOptions options = DevCycleCloudOptions.builder()
.hooks(hooks)
.build();

final String apiKey = String.format("server-%s", UUID.randomUUID());
DevCycleCloudClient client = new DevCycleCloudClient(apiKey, options);
WhiteBox.setInternalState(client, "api", apiInterface);

Variable<String> expected = Variable.<String>builder()
.key("test-string")
.value("test value")
.type(Variable.TypeEnum.STRING)
.isDefaulted(false)
.defaultValue("default string")
.build();

when(apiInterface.getVariableByKey(user, "test-string", false)).thenReturn(Calls.response(expected));

Variable<String> result = client.variable(user, "test-string", "default string");

Assert.assertEquals(expected, result);

Assert.assertTrue(beforeCalled[0]);
Assert.assertTrue(afterCalled[0]);
Assert.assertTrue(finallyCalled[0]);
Assert.assertFalse(errorCalled[0]);

Assert.assertTrue(beforeCalled[1]);
Assert.assertTrue(afterCalled[1]);
Assert.assertTrue(finallyCalled[1]);
Assert.assertFalse(errorCalled[1]);
}

private void assertUserDefaultsCorrect(DevCycleUser user) {
Assert.assertEquals("Java", user.getPlatform());
Assert.assertEquals(PlatformData.SdkTypeEnum.SERVER, user.getSdkType());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.devcycle.sdk.server.local;

import com.devcycle.sdk.server.cloud.api.DevCycleCloudClient;
import com.devcycle.sdk.server.cloud.model.DevCycleCloudOptions;
import com.devcycle.sdk.server.common.api.IRestOptions;
import com.devcycle.sdk.server.common.exception.DevCycleException;
import com.devcycle.sdk.server.common.logging.IDevCycleLogger;
import com.devcycle.sdk.server.common.model.*;
import com.devcycle.sdk.server.helpers.LocalConfigServer;
import com.devcycle.sdk.server.helpers.TestDataFixtures;
import com.devcycle.sdk.server.helpers.WhiteBox;
import com.devcycle.sdk.server.local.api.DevCycleLocalClient;
import com.devcycle.sdk.server.local.model.DevCycleLocalOptions;
import org.junit.AfterClass;
Expand All @@ -15,6 +18,7 @@
import org.junit.After;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import retrofit2.mock.Calls;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSocketFactory;
Expand All @@ -24,6 +28,9 @@
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.*;

import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class DevCycleLocalClientTest {
Expand Down Expand Up @@ -90,17 +97,7 @@ public static void setup() throws Exception {
client = createClient(TestDataFixtures.SmallConfig());
}

private static DevCycleLocalClient createClient(String config) {
localConfigServer.setConfigData(config);

DevCycleLocalOptions options = DevCycleLocalOptions.builder()
.configCdnBaseUrl(localConfigServer.getHostRootURL())
.configPollingIntervalMS(60000)
.customLogger(testLoggingWrapper)
.restOptions(restOptions)
.build();

DevCycleLocalClient client = new DevCycleLocalClient(apiKey, options);
private static void waitForClient(DevCycleLocalClient client) {
try {
int loops = 0;
while (!client.isInitialized()) {
Expand All @@ -115,6 +112,21 @@ private static DevCycleLocalClient createClient(String config) {
} catch (InterruptedException e) {
// no-op
}
}

private static DevCycleLocalClient createClient(String config) {
localConfigServer.setConfigData(config);

DevCycleLocalOptions options = DevCycleLocalOptions.builder()
.configCdnBaseUrl(localConfigServer.getHostRootURL())
.configPollingIntervalMS(60000)
.customLogger(testLoggingWrapper)
.restOptions(restOptions)
.build();

DevCycleLocalClient client = new DevCycleLocalClient(apiKey, options);

waitForClient(client);
return client;
}

Expand Down Expand Up @@ -844,6 +856,98 @@ public void onFinally(HookContext<String> ctx, Optional<Variable<String>> variab
Assert.assertTrue(finallyCalled[0]);
}

@Test
public void client_withHooksInOptions_addsHooksToEvalRunner() {
DevCycleUser user = DevCycleUser.builder()
.userId("j_test")
.build();

final boolean[] beforeCalled = {false, false};
final boolean[] afterCalled = {false, false};
final boolean[] finallyCalled = {false, false};
final boolean[] errorCalled = {false, false};

List<EvalHook> hooks = new ArrayList<>();
hooks.add(new EvalHook<String>() {
@Override
public Optional<HookContext<String>> before(HookContext<String> ctx) {
beforeCalled[0] = true;
return Optional.empty();
}

@Override
public void after(HookContext<String> ctx, Variable<String> variable) {
afterCalled[0] = true;
}

@Override
public void onFinally(HookContext<String> ctx, Optional<Variable<String>> variable) {
finallyCalled[0] = true;
}

@Override
public void error(HookContext<String> ctx, Throwable e) {
errorCalled[0] = true;
}
});
hooks.add(new EvalHook<String>() {
@Override
public Optional<HookContext<String>> before(HookContext<String> ctx) {
beforeCalled[1] = true;
return Optional.empty();
}

@Override
public void after(HookContext<String> ctx, Variable<String> variable) {
afterCalled[1] = true;
}

@Override
public void onFinally(HookContext<String> ctx, Optional<Variable<String>> variable) {
finallyCalled[1] = true;
}

@Override
public void error(HookContext<String> ctx, Throwable e) {
errorCalled[1] = true;
}
});

DevCycleLocalOptions options = DevCycleLocalOptions.builder()
.configCdnBaseUrl(localConfigServer.getHostRootURL())
.configPollingIntervalMS(60000)
.customLogger(testLoggingWrapper)
.restOptions(restOptions)
.hooks(hooks)
.build();
localConfigServer.setConfigData(TestDataFixtures.SmallConfig());

DevCycleLocalClient client = new DevCycleLocalClient(apiKey, options);
waitForClient(client);

Variable<String> expected = Variable.<String>builder()
.key("string-var")
.value("variationOn")
.type(Variable.TypeEnum.STRING)
.isDefaulted(false)
.defaultValue("default string")
.build();

Variable<String> result = client.variable(user, "string-var", "default string");

Assert.assertEquals(expected, result);

Assert.assertTrue(beforeCalled[0]);
Assert.assertTrue(afterCalled[0]);
Assert.assertTrue(finallyCalled[0]);
Assert.assertFalse(errorCalled[0]);

Assert.assertTrue(beforeCalled[1]);
Assert.assertTrue(afterCalled[1]);
Assert.assertTrue(finallyCalled[1]);
Assert.assertFalse(errorCalled[1]);
}

@After
public void clearHooks() {
client.clearHooks();
Expand Down
Loading