From 6644f746702dc63181dc500789fedd105f7261d4 Mon Sep 17 00:00:00 2001 From: Lucas Echeverz Date: Tue, 9 Feb 2021 15:42:37 -0300 Subject: [PATCH 1/4] LocalhostSplitClient updated LocalhostSplitManager bug fixed Typo on SSEClient Fixed --- .../io/split/client/LocalhostSplitClient.java | 171 ++++++++---------- .../split/client/LocalhostSplitFactory.java | 10 +- .../split/client/LocalhostSplitManager.java | 2 +- .../java/io/split/client/SplitClientImpl.java | 9 +- .../io/split/client/SplitFactoryBuilder.java | 4 +- .../io/split/engine/sse/client/SSEClient.java | 2 +- .../client/LocalhostSplitClientTest.java | 28 ++- .../client/LocalhostSplitFactoryTest.java | 3 +- ...hostSplitFactoryYamlCompactSampleTest.java | 3 +- .../LocalhostSplitFactoryYamlSampleTest.java | 3 +- .../client/LocalhostSplitFactoryYamlTest.java | 3 +- 11 files changed, 120 insertions(+), 118 deletions(-) diff --git a/client/src/main/java/io/split/client/LocalhostSplitClient.java b/client/src/main/java/io/split/client/LocalhostSplitClient.java index 2c5c191d5..02862edba 100644 --- a/client/src/main/java/io/split/client/LocalhostSplitClient.java +++ b/client/src/main/java/io/split/client/LocalhostSplitClient.java @@ -1,16 +1,32 @@ package io.split.client; -import io.split.client.api.Key; -import io.split.client.api.SplitResult; +import com.google.common.collect.Lists; +import io.split.cache.SplitCache; +import io.split.client.dtos.ConditionType; +import io.split.client.dtos.MatcherCombiner; +import io.split.client.dtos.Partition; +import io.split.client.impressions.ImpressionsManager; +import io.split.engine.SDKReadinessGates; +import io.split.engine.evaluator.EvaluatorImp; +import io.split.engine.experiments.ParsedCondition; +import io.split.engine.experiments.ParsedSplit; +import io.split.engine.matchers.AllKeysMatcher; +import io.split.engine.matchers.AttributeMatcher; +import io.split.engine.matchers.CombiningMatcher; +import io.split.engine.matchers.strings.WhitelistMatcher; +import io.split.engine.metrics.Metrics; import io.split.grammar.Treatments; -import io.split.inputValidation.KeyValidator; -import io.split.inputValidation.SplitNameValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.Optional; +import java.util.Comparator; import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -22,70 +38,22 @@ * * @author adil */ -public final class LocalhostSplitClient implements SplitClient { +public final class LocalhostSplitClient extends SplitClientImpl { private static final Logger _log = LoggerFactory.getLogger(LocalhostSplitClient.class); - private static SplitResult SPLIT_RESULT_CONTROL = new SplitResult(Treatments.CONTROL, null); + private static String LOCALHOST = "localhost"; - private Map _map; + public LocalhostSplitClient(Map map, SplitCache splitCache) throws URISyntaxException { + super(new SplitFactoryImpl(LOCALHOST, SplitClientConfig.builder().build()), splitCache, + new ImpressionsManager.NoOpImpressionsManager(), new Metrics.NoopMetrics(), new NoopEventClient(), + SplitClientConfig.builder().build(), new SDKReadinessGates(), new EvaluatorImp(splitCache)); - public LocalhostSplitClient(Map map) { checkNotNull(map, "map must not be null"); - _map = map; - } - - @Override - public String getTreatment(String key, String split) { - return getTreatmentAndConfigInternal(key, split).treatment(); - } - - @Override - public String getTreatment(String key, String split, Map attributes) { - return getTreatmentAndConfigInternal(key, split).treatment(); - } - - @Override - public String getTreatment(Key key, String split, Map attributes) { - return getTreatmentAndConfigInternal(key.matchingKey(), split, attributes).treatment(); - } - - @Override - public SplitResult getTreatmentWithConfig(String key, String split) { - return getTreatmentAndConfigInternal(key, split); - } - - @Override - public SplitResult getTreatmentWithConfig(String key, String split, Map attributes) { - return getTreatmentAndConfigInternal(key, split, attributes); - } - - @Override - public SplitResult getTreatmentWithConfig(Key key, String split, Map attributes) { - return getTreatmentAndConfigInternal(key.matchingKey(), split, attributes); + updateCache(map); } @Override public void destroy() { - _map.clear(); - } - - @Override - public boolean track(String key, String trafficType, String eventType) { - return false; - } - - @Override - public boolean track(String key, String trafficType, String eventType, double value) { - return false; - } - - @Override - public boolean track(String key, String trafficType, String eventType, Map properties) { - return false; - } - - @Override - public boolean track(String key, String trafficType, String eventType, double value, Map properties) { - return false; + _splitCache.clear(); } @Override @@ -98,45 +66,64 @@ public void updateFeatureToTreatmentMap(Map map) { _log.warn("A null map was passed as an update. Ignoring this update."); return; } - _map = map; - } - - private SplitResult getTreatmentAndConfigInternal(String key, String split, Map attributes) { - boolean keyIsValid = KeyValidator.isValid(key, "matchingKey", "getTreatment"); - - if (!keyIsValid) { - return SPLIT_RESULT_CONTROL; - } - - Optional splitName = SplitNameValidator.isValid(split, "getTreatment"); - - if (!splitName.isPresent()) { - return SPLIT_RESULT_CONTROL; + updateCache(map); + } + + private void updateCache(Map map) { + _splitCache.clear(); + for (Map.Entry entrySplit : map.entrySet()) { + SplitAndKey splitAndKey = entrySplit.getKey(); + String splitName = splitAndKey.split(); + String splitKey = splitAndKey.key(); + LocalhostSplit localhostSplit = entrySplit.getValue(); + ParsedSplit split = _splitCache.get(splitName); + List conditions = getConditions(splitKey, split, localhostSplit.treatment); + String treatment = conditions.size() > 0 ? Treatments.CONTROL : localhostSplit.treatment; + Map configurations = new HashMap<>(); + if(split != null && split.configurations().size() > 0) { + configurations = split.configurations(); + } + configurations.put(localhostSplit.treatment, localhostSplit.config); + + split = new ParsedSplit(splitName, 0, false, treatment,conditions, LOCALHOST, 0, 100, 0, 0, configurations); + _splitCache.put(split); } + } - split = splitName.get(); + private List getConditions(String splitKey, ParsedSplit split, String treatment){ + List conditions = split == null ? new ArrayList<>() : split.parsedConditions().stream().collect(Collectors.toList()); + Partition partition = new Partition(); + partition.treatment = treatment; + partition.size = 100; - SplitAndKey override = SplitAndKey.of(split, key); - if (_map.containsKey(override)) { - return toSplitResult(_map.get(override)); + if(splitKey != null) { + conditions.add(createWhitelistCondition(splitKey, partition)); } - - SplitAndKey splitDefaultTreatment = SplitAndKey.of(split); - - LocalhostSplit localhostSplit = _map.get(splitDefaultTreatment); - - if (localhostSplit == null) { - return SPLIT_RESULT_CONTROL; + else { + conditions = conditions.stream().filter(pc -> ConditionType.WHITELIST.equals(pc.conditionType())).collect(Collectors.toList()); + conditions.add(createRolloutCondition(partition)); } - - return toSplitResult(localhostSplit); + conditions.sort(Comparator.comparing(ParsedCondition::conditionType)); + return conditions; } - private SplitResult toSplitResult(LocalhostSplit localhostSplit) { - return new SplitResult(localhostSplit.treatment,localhostSplit.config); + private ParsedCondition createWhitelistCondition(String splitKey, Partition partition) { + ParsedCondition parsedCondition = new ParsedCondition(ConditionType.WHITELIST, + new CombiningMatcher(MatcherCombiner.AND, + Lists.newArrayList(new AttributeMatcher(null, new WhitelistMatcher(Lists.newArrayList(splitKey)), false))), + Lists.newArrayList(partition), splitKey); + return parsedCondition; } - private SplitResult getTreatmentAndConfigInternal(String key, String split) { - return getTreatmentAndConfigInternal(key, split, null); + private ParsedCondition createRolloutCondition(Partition partition) { + Partition rolloutPartition = new Partition(); + rolloutPartition.treatment = "-"; + rolloutPartition.size = 0; + ParsedCondition parsedCondition = new ParsedCondition(ConditionType.ROLLOUT, + new CombiningMatcher(MatcherCombiner.AND, + Lists.newArrayList(new AttributeMatcher(null, new AllKeysMatcher(), false))), + Lists.newArrayList(partition, rolloutPartition), "LOCAL"); + + return parsedCondition; } } diff --git a/client/src/main/java/io/split/client/LocalhostSplitFactory.java b/client/src/main/java/io/split/client/LocalhostSplitFactory.java index 940fd2fbe..73a55c6ed 100644 --- a/client/src/main/java/io/split/client/LocalhostSplitFactory.java +++ b/client/src/main/java/io/split/client/LocalhostSplitFactory.java @@ -1,9 +1,12 @@ package io.split.client; +import io.split.cache.InMemoryCacheImp; +import io.split.cache.SplitCache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.net.URISyntaxException; import java.util.Map; /** @@ -27,12 +30,12 @@ public final class LocalhostSplitFactory implements SplitFactory { private final LocalhostSplitManager _manager; private final AbstractLocalhostSplitFile _splitFile; - public static LocalhostSplitFactory createLocalhostSplitFactory(SplitClientConfig config) throws IOException { + public static LocalhostSplitFactory createLocalhostSplitFactory(SplitClientConfig config) throws IOException, URISyntaxException { String directory = System.getProperty("user.home"); return new LocalhostSplitFactory(directory, config.splitFile()); } - public LocalhostSplitFactory(String directory, String file) throws IOException { + public LocalhostSplitFactory(String directory, String file) throws IOException, URISyntaxException { if (file != null && !file.isEmpty() && (file.endsWith(".yaml") || file.endsWith(".yml"))) { _splitFile = new YamlLocalhostSplitFile(this, "", file); @@ -44,7 +47,8 @@ public LocalhostSplitFactory(String directory, String file) throws IOException { } Map splitAndKeyToTreatment = _splitFile.readOnSplits(); - _client = new LocalhostSplitClientAndFactory(this, new LocalhostSplitClient(splitAndKeyToTreatment)); + SplitCache splitCache = new InMemoryCacheImp(); + _client = new LocalhostSplitClientAndFactory(this, new LocalhostSplitClient(splitAndKeyToTreatment, splitCache)); _manager = LocalhostSplitManager.of(splitAndKeyToTreatment); _splitFile.registerWatcher(); diff --git a/client/src/main/java/io/split/client/LocalhostSplitManager.java b/client/src/main/java/io/split/client/LocalhostSplitManager.java index 26a8118fc..dc72ea4d1 100644 --- a/client/src/main/java/io/split/client/LocalhostSplitManager.java +++ b/client/src/main/java/io/split/client/LocalhostSplitManager.java @@ -77,7 +77,7 @@ public void blockUntilReady() throws TimeoutException, InterruptedException { @Override public SplitView split(String featureName) { - if (!_splitAndKeyToTreatmentMap.containsKey(featureName)) { + if (!_splitToTreatmentsMap.containsKey(featureName)) { return null; } diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java index 120ec00d4..549cfc9a7 100644 --- a/client/src/main/java/io/split/client/SplitClientImpl.java +++ b/client/src/main/java/io/split/client/SplitClientImpl.java @@ -1,16 +1,15 @@ package io.split.client; +import io.split.cache.SplitCache; import io.split.client.api.Key; import io.split.client.api.SplitResult; import io.split.client.dtos.Event; import io.split.client.impressions.Impression; import io.split.client.impressions.ImpressionsManager; -import io.split.cache.SplitCache; -import io.split.engine.evaluator.Evaluator; import io.split.engine.SDKReadinessGates; +import io.split.engine.evaluator.Evaluator; import io.split.engine.evaluator.EvaluatorImp; import io.split.engine.evaluator.Labels; - import io.split.engine.metrics.Metrics; import io.split.grammar.Treatments; import io.split.inputValidation.EventsValidator; @@ -33,7 +32,7 @@ * * @author adil */ -public final class SplitClientImpl implements SplitClient { +public class SplitClientImpl implements SplitClient { public static final SplitResult SPLIT_RESULT_CONTROL = new SplitResult(Treatments.CONTROL, null); private static final String GET_TREATMENT = "getTreatment"; @@ -42,7 +41,7 @@ public final class SplitClientImpl implements SplitClient { private static final Logger _log = LoggerFactory.getLogger(SplitClientImpl.class); private final SplitFactory _container; - private final SplitCache _splitCache; + protected final SplitCache _splitCache; private final ImpressionsManager _impressionManager; private final Metrics _metrics; private final SplitClientConfig _config; diff --git a/client/src/main/java/io/split/client/SplitFactoryBuilder.java b/client/src/main/java/io/split/client/SplitFactoryBuilder.java index 4a95228b4..f18032416 100644 --- a/client/src/main/java/io/split/client/SplitFactoryBuilder.java +++ b/client/src/main/java/io/split/client/SplitFactoryBuilder.java @@ -52,7 +52,7 @@ public static synchronized SplitFactory build(String apiToken, SplitClientConfig * * @throws IOException if there were problems reading the override file from disk. */ - public static SplitFactory local() throws IOException { + public static SplitFactory local() throws IOException, URISyntaxException { return LocalhostSplitFactory.createLocalhostSplitFactory(SplitClientConfig.builder().build()); } @@ -62,7 +62,7 @@ public static SplitFactory local() throws IOException { * @return config Split config file * @throws IOException if there were problems reading the override file from disk. */ - public static SplitFactory local(SplitClientConfig config) throws IOException { + public static SplitFactory local(SplitClientConfig config) throws IOException, URISyntaxException { return LocalhostSplitFactory.createLocalhostSplitFactory(config); } diff --git a/client/src/main/java/io/split/engine/sse/client/SSEClient.java b/client/src/main/java/io/split/engine/sse/client/SSEClient.java index 00507a6d2..26d2ea934 100644 --- a/client/src/main/java/io/split/engine/sse/client/SSEClient.java +++ b/client/src/main/java/io/split/engine/sse/client/SSEClient.java @@ -127,7 +127,7 @@ private void connectAndLoop(URI uri, CountDownLatch signal) { _statusCallback.apply(StatusMessage.RETRYABLE_ERROR); return; } catch (IOException exc) { // Other type of connection error - _log.info(String.format("SSE connection ended abruptly: %s. Retying", exc.getMessage())); + _log.info(String.format("SSE connection ended abruptly: %s. Retrying", exc.getMessage())); _statusCallback.apply(StatusMessage.RETRYABLE_ERROR); return; } diff --git a/client/src/test/java/io/split/client/LocalhostSplitClientTest.java b/client/src/test/java/io/split/client/LocalhostSplitClientTest.java index b34af8000..278ac6efe 100644 --- a/client/src/test/java/io/split/client/LocalhostSplitClientTest.java +++ b/client/src/test/java/io/split/client/LocalhostSplitClientTest.java @@ -1,9 +1,12 @@ package io.split.client; import com.google.common.collect.Maps; +import io.split.cache.InMemoryCacheImp; +import io.split.cache.SplitCache; import io.split.grammar.Treatments; import org.junit.Test; +import java.net.URISyntaxException; import java.util.Map; import static org.hamcrest.Matchers.equalTo; @@ -19,13 +22,14 @@ public class LocalhostSplitClientTest { @Test - public void defaultsWork() { + public void defaultsWork() throws URISyntaxException { Map map = Maps.newHashMap(); map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("on")); map.put(SplitAndKey.of("test"), LocalhostSplit.of("a")); map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("off")); // overwrite - LocalhostSplitClient client = new LocalhostSplitClient(map); + SplitCache splitCache = new InMemoryCacheImp(); + LocalhostSplitClient client = new LocalhostSplitClient(map, splitCache); assertThat(client.getTreatment(null, "foo"), is(equalTo(Treatments.CONTROL))); assertThat(client.getTreatment("user1", "foo"), is(equalTo(Treatments.CONTROL))); @@ -38,13 +42,14 @@ public void defaultsWork() { } @Test - public void overrides_work() { + public void overrides_work() throws URISyntaxException { Map map = Maps.newHashMap(); map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("on")); map.put(SplitAndKey.of("onboarding", "user1"), LocalhostSplit.of("off")); map.put(SplitAndKey.of("onboarding", "user2"), LocalhostSplit.of("off")); - LocalhostSplitClient client = new LocalhostSplitClient(map); + SplitCache splitCache = new InMemoryCacheImp(); + LocalhostSplitClient client = new LocalhostSplitClient(map, splitCache); assertThat(client.getTreatment("user1", "onboarding"), is(equalTo("off"))); assertThat(client.getTreatment("user2", "onboarding"), is(equalTo("off"))); @@ -54,12 +59,13 @@ public void overrides_work() { } @Test - public void if_only_overrides_exist() { + public void if_only_overrides_exist() throws URISyntaxException { Map map = Maps.newHashMap(); map.put(SplitAndKey.of("onboarding", "user1"), LocalhostSplit.of("off")); map.put(SplitAndKey.of("onboarding", "user2"), LocalhostSplit.of("off")); - LocalhostSplitClient client = new LocalhostSplitClient(map); + SplitCache splitCache = new InMemoryCacheImp(); + LocalhostSplitClient client = new LocalhostSplitClient(map, splitCache); assertThat(client.getTreatment("user1", "onboarding"), is(equalTo("off"))); assertThat(client.getTreatment("user2", "onboarding"), is(equalTo("off"))); @@ -67,13 +73,14 @@ public void if_only_overrides_exist() { } @Test - public void attributes_work() { + public void attributes_work() throws URISyntaxException { Map map = Maps.newHashMap(); map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("on")); map.put(SplitAndKey.of("onboarding", "user1"), LocalhostSplit.of("off")); map.put(SplitAndKey.of("onboarding", "user2"), LocalhostSplit.of("off")); - LocalhostSplitClient client = new LocalhostSplitClient(map); + SplitCache splitCache = new InMemoryCacheImp(); + LocalhostSplitClient client = new LocalhostSplitClient(map, splitCache); Map attributes = Maps.newHashMap(); attributes.put("age", 24); @@ -84,13 +91,14 @@ public void attributes_work() { } @Test - public void update_works() { + public void update_works() throws URISyntaxException { Map map = Maps.newHashMap(); map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("on")); map.put(SplitAndKey.of("onboarding", "user1"), LocalhostSplit.of("off")); map.put(SplitAndKey.of("onboarding", "user2"), LocalhostSplit.of("off")); - LocalhostSplitClient client = new LocalhostSplitClient(map); + SplitCache splitCache = new InMemoryCacheImp(); + LocalhostSplitClient client = new LocalhostSplitClient(map, splitCache); assertThat(client.getTreatment("user1", "onboarding"), is(equalTo("off"))); assertThat(client.getTreatment("user2", "onboarding"), is(equalTo("off"))); diff --git a/client/src/test/java/io/split/client/LocalhostSplitFactoryTest.java b/client/src/test/java/io/split/client/LocalhostSplitFactoryTest.java index 63684e8f3..2728c7366 100644 --- a/client/src/test/java/io/split/client/LocalhostSplitFactoryTest.java +++ b/client/src/test/java/io/split/client/LocalhostSplitFactoryTest.java @@ -10,6 +10,7 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.net.URISyntaxException; import java.util.Map; import static org.hamcrest.Matchers.equalTo; @@ -27,7 +28,7 @@ public class LocalhostSplitFactoryTest { public TemporaryFolder folder = new TemporaryFolder(); @Test - public void works() throws IOException { + public void works() throws IOException, URISyntaxException { File file = folder.newFile(LocalhostSplitFactory.FILENAME); Map map = Maps.newHashMap(); diff --git a/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlCompactSampleTest.java b/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlCompactSampleTest.java index 2319594ce..b54e7f489 100644 --- a/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlCompactSampleTest.java +++ b/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlCompactSampleTest.java @@ -5,6 +5,7 @@ import org.junit.Test; import java.io.IOException; +import java.net.URISyntaxException; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; @@ -20,7 +21,7 @@ public class LocalhostSplitFactoryYamlCompactSampleTest { @Test - public void works() throws IOException { + public void works() throws IOException, URISyntaxException { String file = getClass().getClassLoader().getResource("split_compact.yaml").getFile(); diff --git a/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlSampleTest.java b/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlSampleTest.java index 390a0b052..933d19039 100644 --- a/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlSampleTest.java +++ b/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlSampleTest.java @@ -5,6 +5,7 @@ import org.junit.Test; import java.io.IOException; +import java.net.URISyntaxException; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; @@ -20,7 +21,7 @@ public class LocalhostSplitFactoryYamlSampleTest { @Test - public void works() throws IOException { + public void works() throws IOException, URISyntaxException { String file = getClass().getClassLoader().getResource(SplitClientConfig.LOCALHOST_DEFAULT_FILE).getFile(); diff --git a/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlTest.java b/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlTest.java index 4d68cb030..c0be15838 100644 --- a/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlTest.java +++ b/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlTest.java @@ -12,6 +12,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -43,7 +44,7 @@ public class LocalhostSplitFactoryYamlTest { public TemporaryFolder folder = new TemporaryFolder(); @Test - public void works() throws IOException { + public void works() throws IOException, URISyntaxException { File file = folder.newFile(SplitClientConfig.LOCALHOST_DEFAULT_FILE); List> allSplits = new ArrayList(); From de128d19f3b06b270a735a7390e9e55839af0f0b Mon Sep 17 00:00:00 2001 From: Lucas Echeverz Date: Tue, 23 Feb 2021 15:36:51 -0300 Subject: [PATCH 2/4] Using SplitClientImpl instead LocalhostSplitClient in LocalhostFactory --- ...itClient.java => CacheUpdaterService.java} | 51 +------- .../LocalhostSplitClientAndFactory.java | 101 --------------- .../split/client/LocalhostSplitFactory.java | 23 +++- .../java/io/split/client/SplitClientImpl.java | 2 +- .../split/client/CacheUpdaterServiceTest.java | 45 +++++++ .../client/LocalhostSplitClientTest.java | 117 ------------------ 6 files changed, 69 insertions(+), 270 deletions(-) rename client/src/main/java/io/split/client/{LocalhostSplitClient.java => CacheUpdaterService.java} (66%) delete mode 100644 client/src/main/java/io/split/client/LocalhostSplitClientAndFactory.java create mode 100644 client/src/test/java/io/split/client/CacheUpdaterServiceTest.java delete mode 100644 client/src/test/java/io/split/client/LocalhostSplitClientTest.java diff --git a/client/src/main/java/io/split/client/LocalhostSplitClient.java b/client/src/main/java/io/split/client/CacheUpdaterService.java similarity index 66% rename from client/src/main/java/io/split/client/LocalhostSplitClient.java rename to client/src/main/java/io/split/client/CacheUpdaterService.java index 02862edba..eb8d8d904 100644 --- a/client/src/main/java/io/split/client/LocalhostSplitClient.java +++ b/client/src/main/java/io/split/client/CacheUpdaterService.java @@ -5,71 +5,31 @@ import io.split.client.dtos.ConditionType; import io.split.client.dtos.MatcherCombiner; import io.split.client.dtos.Partition; -import io.split.client.impressions.ImpressionsManager; -import io.split.engine.SDKReadinessGates; -import io.split.engine.evaluator.EvaluatorImp; import io.split.engine.experiments.ParsedCondition; import io.split.engine.experiments.ParsedSplit; import io.split.engine.matchers.AllKeysMatcher; import io.split.engine.matchers.AttributeMatcher; import io.split.engine.matchers.CombiningMatcher; import io.split.engine.matchers.strings.WhitelistMatcher; -import io.split.engine.metrics.Metrics; import io.split.grammar.Treatments; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Comparator; -import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; -import static com.google.common.base.Preconditions.checkNotNull; +public final class CacheUpdaterService { -/** - * An implementation of SplitClient that considers all partitions - * passed in the constructor to be 100% on for all users, and - * any other split to be 100% off for all users. This implementation - * is useful for using Codigo in localhost environment. - * - * @author adil - */ -public final class LocalhostSplitClient extends SplitClientImpl { - private static final Logger _log = LoggerFactory.getLogger(LocalhostSplitClient.class); private static String LOCALHOST = "localhost"; + private SplitCache _splitCache; - public LocalhostSplitClient(Map map, SplitCache splitCache) throws URISyntaxException { - super(new SplitFactoryImpl(LOCALHOST, SplitClientConfig.builder().build()), splitCache, - new ImpressionsManager.NoOpImpressionsManager(), new Metrics.NoopMetrics(), new NoopEventClient(), - SplitClientConfig.builder().build(), new SDKReadinessGates(), new EvaluatorImp(splitCache)); - - checkNotNull(map, "map must not be null"); - updateCache(map); - } - - @Override - public void destroy() { - _splitCache.clear(); - } - - @Override - public void blockUntilReady() throws TimeoutException, InterruptedException { - // LocalhostSplitClient is always ready + public CacheUpdaterService(SplitCache splitCache) { + _splitCache = splitCache; } - public void updateFeatureToTreatmentMap(Map map) { - if (map == null) { - _log.warn("A null map was passed as an update. Ignoring this update."); - return; - } - updateCache(map); - } - - private void updateCache(Map map) { + public void updateCache(Map map) { _splitCache.clear(); for (Map.Entry entrySplit : map.entrySet()) { SplitAndKey splitAndKey = entrySplit.getKey(); @@ -126,4 +86,5 @@ private ParsedCondition createRolloutCondition(Partition partition) { return parsedCondition; } + } diff --git a/client/src/main/java/io/split/client/LocalhostSplitClientAndFactory.java b/client/src/main/java/io/split/client/LocalhostSplitClientAndFactory.java deleted file mode 100644 index 15b5341e3..000000000 --- a/client/src/main/java/io/split/client/LocalhostSplitClientAndFactory.java +++ /dev/null @@ -1,101 +0,0 @@ -package io.split.client; - -import io.split.client.api.Key; -import io.split.client.api.SplitResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Map; -import java.util.concurrent.TimeoutException; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * An implementation of SplitClient that considers all partitions - * passed in the constructor to be 100% on for all users, and - * any other split to be 100% off for all users. This implementation - * is useful for using Split in localhost environment. - * - * @author adil - */ -public final class LocalhostSplitClientAndFactory implements SplitClient { - private static final Logger _log = LoggerFactory.getLogger(LocalhostSplitClientAndFactory.class); - - private LocalhostSplitFactory _factory; - private LocalhostSplitClient _splitClient; - - public LocalhostSplitClientAndFactory(LocalhostSplitFactory container, LocalhostSplitClient client) { - _factory = checkNotNull(container); - _splitClient = checkNotNull(client); - } - - @Override - public String getTreatment(String key, String split) { - return _splitClient.getTreatment(key, split); - } - - @Override - public String getTreatment(String key, String split, Map attributes) { - return _splitClient.getTreatment(key, split, attributes); - } - - @Override - public String getTreatment(Key key, String split, Map attributes) { - return _splitClient.getTreatment(key.matchingKey(), split, attributes); - } - - @Override - public SplitResult getTreatmentWithConfig(String key, String split) { - return _splitClient.getTreatmentWithConfig(key, split); - } - - @Override - public SplitResult getTreatmentWithConfig(String key, String split, Map attributes) { - return _splitClient.getTreatmentWithConfig(key, split, attributes); - } - - @Override - public SplitResult getTreatmentWithConfig(Key key, String split, Map attributes) { - return _splitClient.getTreatmentWithConfig(key, split, attributes); - } - - public void updateFeatureToTreatmentMap(Map map) { - if (map == null) { - _log.warn("A null map was passed as an update. Ignoring this update."); - return; - } - _splitClient.updateFeatureToTreatmentMap(map); - } - - @Override - public void destroy() { - _factory.destroy(); - _splitClient.destroy(); - } - - @Override - public boolean track(String key, String trafficType, String eventType) { - return _splitClient.track(key, trafficType, eventType); - } - - @Override - public boolean track(String key, String trafficType, String eventType, double value) { - return _splitClient.track(key, trafficType, eventType, value); - } - - @Override - public boolean track(String key, String trafficType, String eventType, Map properties) { - return _splitClient.track(key, trafficType, eventType, properties); - } - - @Override - public boolean track(String key, String trafficType, String eventType, double value, Map properties) { - return _splitClient.track(key, trafficType, eventType, value, properties); - } - - @Override - public void blockUntilReady() throws TimeoutException, InterruptedException { - _splitClient.blockUntilReady(); - } - -} diff --git a/client/src/main/java/io/split/client/LocalhostSplitFactory.java b/client/src/main/java/io/split/client/LocalhostSplitFactory.java index 73a55c6ed..c2548586c 100644 --- a/client/src/main/java/io/split/client/LocalhostSplitFactory.java +++ b/client/src/main/java/io/split/client/LocalhostSplitFactory.java @@ -2,11 +2,14 @@ import io.split.cache.InMemoryCacheImp; import io.split.cache.SplitCache; +import io.split.client.impressions.ImpressionsManager; +import io.split.engine.SDKReadinessGates; +import io.split.engine.evaluator.EvaluatorImp; +import io.split.engine.metrics.Metrics; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -import java.net.URISyntaxException; import java.util.Map; /** @@ -26,16 +29,17 @@ public final class LocalhostSplitFactory implements SplitFactory { static final String FILENAME = ".split"; static final String LOCALHOST = "localhost"; - private final LocalhostSplitClientAndFactory _client; + private final SplitClient _client; private final LocalhostSplitManager _manager; private final AbstractLocalhostSplitFile _splitFile; + private final CacheUpdaterService _cachCacheUpdaterService; - public static LocalhostSplitFactory createLocalhostSplitFactory(SplitClientConfig config) throws IOException, URISyntaxException { + public static LocalhostSplitFactory createLocalhostSplitFactory(SplitClientConfig config) throws IOException { String directory = System.getProperty("user.home"); return new LocalhostSplitFactory(directory, config.splitFile()); } - public LocalhostSplitFactory(String directory, String file) throws IOException, URISyntaxException { + public LocalhostSplitFactory(String directory, String file) throws IOException { if (file != null && !file.isEmpty() && (file.endsWith(".yaml") || file.endsWith(".yml"))) { _splitFile = new YamlLocalhostSplitFile(this, "", file); @@ -48,7 +52,14 @@ public LocalhostSplitFactory(String directory, String file) throws IOException, Map splitAndKeyToTreatment = _splitFile.readOnSplits(); SplitCache splitCache = new InMemoryCacheImp(); - _client = new LocalhostSplitClientAndFactory(this, new LocalhostSplitClient(splitAndKeyToTreatment, splitCache)); + SDKReadinessGates sdkReadinessGates = new SDKReadinessGates(); + + sdkReadinessGates.splitsAreReady(); + _cachCacheUpdaterService = new CacheUpdaterService(splitCache); + _cachCacheUpdaterService.updateCache(splitAndKeyToTreatment); + _client = new SplitClientImpl(this, splitCache, + new ImpressionsManager.NoOpImpressionsManager(), new Metrics.NoopMetrics(), new NoopEventClient(), + SplitClientConfig.builder().setBlockUntilReadyTimeout(1).build(), sdkReadinessGates, new EvaluatorImp(splitCache)); _manager = LocalhostSplitManager.of(splitAndKeyToTreatment); _splitFile.registerWatcher(); @@ -77,7 +88,7 @@ public boolean isDestroyed() { } public void updateFeatureToTreatmentMap(Map featureToTreatmentMap) { - _client.updateFeatureToTreatmentMap(featureToTreatmentMap); + _cachCacheUpdaterService.updateCache(featureToTreatmentMap); _manager.updateFeatureToTreatmentMap(featureToTreatmentMap); } } diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java index 549cfc9a7..08d26d3a0 100644 --- a/client/src/main/java/io/split/client/SplitClientImpl.java +++ b/client/src/main/java/io/split/client/SplitClientImpl.java @@ -32,7 +32,7 @@ * * @author adil */ -public class SplitClientImpl implements SplitClient { +public final class SplitClientImpl implements SplitClient { public static final SplitResult SPLIT_RESULT_CONTROL = new SplitResult(Treatments.CONTROL, null); private static final String GET_TREATMENT = "getTreatment"; diff --git a/client/src/test/java/io/split/client/CacheUpdaterServiceTest.java b/client/src/test/java/io/split/client/CacheUpdaterServiceTest.java new file mode 100644 index 000000000..9d6d30140 --- /dev/null +++ b/client/src/test/java/io/split/client/CacheUpdaterServiceTest.java @@ -0,0 +1,45 @@ +package io.split.client; + +import io.split.cache.InMemoryCacheImp; +import io.split.cache.SplitCache; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +public class CacheUpdaterServiceTest { + + private static final String OFF_TREATMENT = "off"; + private static final String ON_TREATMENT = "on"; + private static final String MY_FEATURE = "my_feature"; + private SplitClientConfig config = SplitClientConfig.builder().setBlockUntilReadyTimeout(100).build(); + + @Test + public void testCacheUpdate() { + SplitCache splitCache = new InMemoryCacheImp(); + CacheUpdaterService cacheUpdaterService = new CacheUpdaterService(splitCache); + cacheUpdaterService.updateCache(getMap()); + Assert.assertNotNull(splitCache.get(MY_FEATURE)); + } + + public Map getMap() { + Map map = new HashMap<>(); + SplitAndKey splitAndKey = new SplitAndKey(MY_FEATURE, "onley_key"); + LocalhostSplit split = new LocalhostSplit(OFF_TREATMENT, "{\\\"desc\\\" : \\\"this applies only to OFF and only for only_key. The rest will receive ON\\\"}"); + map.put(splitAndKey, split); + splitAndKey = new SplitAndKey("other_feature_2", null); + split = new LocalhostSplit(ON_TREATMENT, null); + map.put(splitAndKey, split); + splitAndKey = new SplitAndKey("other_feature_3", null); + split = new LocalhostSplit(OFF_TREATMENT, null); + map.put(splitAndKey, split); + splitAndKey = new SplitAndKey(MY_FEATURE, "key"); + split = new LocalhostSplit(ON_TREATMENT, "{\\\"desc\\\" : \\\"this applies only to ON treatment\\\"}"); + map.put(splitAndKey, split); + splitAndKey = new SplitAndKey("other_feature_3", "key_whitelist"); + split = new LocalhostSplit(ON_TREATMENT, null); + map.put(splitAndKey, split); + return map; + } +} \ No newline at end of file diff --git a/client/src/test/java/io/split/client/LocalhostSplitClientTest.java b/client/src/test/java/io/split/client/LocalhostSplitClientTest.java deleted file mode 100644 index 278ac6efe..000000000 --- a/client/src/test/java/io/split/client/LocalhostSplitClientTest.java +++ /dev/null @@ -1,117 +0,0 @@ -package io.split.client; - -import com.google.common.collect.Maps; -import io.split.cache.InMemoryCacheImp; -import io.split.cache.SplitCache; -import io.split.grammar.Treatments; -import org.junit.Test; - -import java.net.URISyntaxException; -import java.util.Map; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; - -/** - * Tests for LocalhostSplitClient - * - * @author adil - */ -public class LocalhostSplitClientTest { - - @Test - public void defaultsWork() throws URISyntaxException { - Map map = Maps.newHashMap(); - map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("on")); - map.put(SplitAndKey.of("test"), LocalhostSplit.of("a")); - map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("off")); // overwrite - - SplitCache splitCache = new InMemoryCacheImp(); - LocalhostSplitClient client = new LocalhostSplitClient(map, splitCache); - - assertThat(client.getTreatment(null, "foo"), is(equalTo(Treatments.CONTROL))); - assertThat(client.getTreatment("user1", "foo"), is(equalTo(Treatments.CONTROL))); - assertThat(client.getTreatment("user1", "onboarding"), is(equalTo("off"))); - assertThat(client.getTreatment("user2", "onboarding"), is(equalTo("off"))); - assertThat(client.getTreatment("user1", "test"), is(equalTo("a"))); - assertThat(client.getTreatment("user2", "test"), is(equalTo("a"))); - assertThat(client.getTreatmentWithConfig("user2", "test").config(), is(nullValue())); - assertThat(client.getTreatmentWithConfig("user2", "test").treatment(), is(equalTo("a"))); - } - - @Test - public void overrides_work() throws URISyntaxException { - Map map = Maps.newHashMap(); - map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("on")); - map.put(SplitAndKey.of("onboarding", "user1"), LocalhostSplit.of("off")); - map.put(SplitAndKey.of("onboarding", "user2"), LocalhostSplit.of("off")); - - SplitCache splitCache = new InMemoryCacheImp(); - LocalhostSplitClient client = new LocalhostSplitClient(map, splitCache); - - assertThat(client.getTreatment("user1", "onboarding"), is(equalTo("off"))); - assertThat(client.getTreatment("user2", "onboarding"), is(equalTo("off"))); - assertThat(client.getTreatment("user3", "onboarding"), is(equalTo("on"))); - assertThat(client.getTreatmentWithConfig("user3", "onboarding").config(), is(nullValue())); - assertThat(client.getTreatmentWithConfig("user3", "onboarding").treatment(), is(equalTo("on"))); - } - - @Test - public void if_only_overrides_exist() throws URISyntaxException { - Map map = Maps.newHashMap(); - map.put(SplitAndKey.of("onboarding", "user1"), LocalhostSplit.of("off")); - map.put(SplitAndKey.of("onboarding", "user2"), LocalhostSplit.of("off")); - - SplitCache splitCache = new InMemoryCacheImp(); - LocalhostSplitClient client = new LocalhostSplitClient(map, splitCache); - - assertThat(client.getTreatment("user1", "onboarding"), is(equalTo("off"))); - assertThat(client.getTreatment("user2", "onboarding"), is(equalTo("off"))); - assertThat(client.getTreatment("user3", "onboarding"), is(equalTo(Treatments.CONTROL))); - } - - @Test - public void attributes_work() throws URISyntaxException { - Map map = Maps.newHashMap(); - map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("on")); - map.put(SplitAndKey.of("onboarding", "user1"), LocalhostSplit.of("off")); - map.put(SplitAndKey.of("onboarding", "user2"), LocalhostSplit.of("off")); - - SplitCache splitCache = new InMemoryCacheImp(); - LocalhostSplitClient client = new LocalhostSplitClient(map, splitCache); - - Map attributes = Maps.newHashMap(); - attributes.put("age", 24); - - assertThat(client.getTreatment("user1", "onboarding", attributes), is(equalTo("off"))); - assertThat(client.getTreatment("user2", "onboarding", attributes), is(equalTo("off"))); - assertThat(client.getTreatment("user3", "onboarding", attributes), is(equalTo("on"))); - } - - @Test - public void update_works() throws URISyntaxException { - Map map = Maps.newHashMap(); - map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("on")); - map.put(SplitAndKey.of("onboarding", "user1"), LocalhostSplit.of("off")); - map.put(SplitAndKey.of("onboarding", "user2"), LocalhostSplit.of("off")); - - SplitCache splitCache = new InMemoryCacheImp(); - LocalhostSplitClient client = new LocalhostSplitClient(map, splitCache); - - assertThat(client.getTreatment("user1", "onboarding"), is(equalTo("off"))); - assertThat(client.getTreatment("user2", "onboarding"), is(equalTo("off"))); - assertThat(client.getTreatment("user3", "onboarding"), is(equalTo("on"))); - - map.clear(); - map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("on")); - map.put(SplitAndKey.of("onboarding", "user1"), LocalhostSplit.of("off")); - - client.updateFeatureToTreatmentMap(map); - - assertThat(client.getTreatment("user1", "onboarding"), is(equalTo("off"))); - assertThat(client.getTreatment("user2", "onboarding"), is(equalTo("on"))); - assertThat(client.getTreatment("user3", "onboarding"), is(equalTo("on"))); - } -} From 9201e2a2647fa8dea06c8059111769e8f14e69fe Mon Sep 17 00:00:00 2001 From: Lucas Echeverz Date: Tue, 23 Feb 2021 15:43:52 -0300 Subject: [PATCH 3/4] Forgot to change this previous change. SplitCache in SplitClientImpl remains private. --- client/src/main/java/io/split/client/SplitClientImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java index 08d26d3a0..7792f5a1f 100644 --- a/client/src/main/java/io/split/client/SplitClientImpl.java +++ b/client/src/main/java/io/split/client/SplitClientImpl.java @@ -41,7 +41,7 @@ public final class SplitClientImpl implements SplitClient { private static final Logger _log = LoggerFactory.getLogger(SplitClientImpl.class); private final SplitFactory _container; - protected final SplitCache _splitCache; + private final SplitCache _splitCache; private final ImpressionsManager _impressionManager; private final Metrics _metrics; private final SplitClientConfig _config; From efdc30d33cea826dba7efe4a5e8f6f22e62f7d4c Mon Sep 17 00:00:00 2001 From: Lucas Echeverz Date: Wed, 24 Feb 2021 12:17:11 -0300 Subject: [PATCH 4/4] Fixing typo --- .../main/java/io/split/client/CacheUpdaterService.java | 2 +- .../main/java/io/split/client/LocalhostSplitFactory.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/main/java/io/split/client/CacheUpdaterService.java b/client/src/main/java/io/split/client/CacheUpdaterService.java index eb8d8d904..6823fdefd 100644 --- a/client/src/main/java/io/split/client/CacheUpdaterService.java +++ b/client/src/main/java/io/split/client/CacheUpdaterService.java @@ -45,7 +45,7 @@ public void updateCache(Map map) { } configurations.put(localhostSplit.treatment, localhostSplit.config); - split = new ParsedSplit(splitName, 0, false, treatment,conditions, LOCALHOST, 0, 100, 0, 0, configurations); + split = new ParsedSplit(splitName, 0, false, treatment,conditions, LOCALHOST, 0, 100, 0, 0, configurations); _splitCache.put(split); } } diff --git a/client/src/main/java/io/split/client/LocalhostSplitFactory.java b/client/src/main/java/io/split/client/LocalhostSplitFactory.java index c2548586c..0ec01f8c9 100644 --- a/client/src/main/java/io/split/client/LocalhostSplitFactory.java +++ b/client/src/main/java/io/split/client/LocalhostSplitFactory.java @@ -32,7 +32,7 @@ public final class LocalhostSplitFactory implements SplitFactory { private final SplitClient _client; private final LocalhostSplitManager _manager; private final AbstractLocalhostSplitFile _splitFile; - private final CacheUpdaterService _cachCacheUpdaterService; + private final CacheUpdaterService _cacheUpdaterService; public static LocalhostSplitFactory createLocalhostSplitFactory(SplitClientConfig config) throws IOException { String directory = System.getProperty("user.home"); @@ -55,8 +55,8 @@ public LocalhostSplitFactory(String directory, String file) throws IOException { SDKReadinessGates sdkReadinessGates = new SDKReadinessGates(); sdkReadinessGates.splitsAreReady(); - _cachCacheUpdaterService = new CacheUpdaterService(splitCache); - _cachCacheUpdaterService.updateCache(splitAndKeyToTreatment); + _cacheUpdaterService = new CacheUpdaterService(splitCache); + _cacheUpdaterService.updateCache(splitAndKeyToTreatment); _client = new SplitClientImpl(this, splitCache, new ImpressionsManager.NoOpImpressionsManager(), new Metrics.NoopMetrics(), new NoopEventClient(), SplitClientConfig.builder().setBlockUntilReadyTimeout(1).build(), sdkReadinessGates, new EvaluatorImp(splitCache)); @@ -88,7 +88,7 @@ public boolean isDestroyed() { } public void updateFeatureToTreatmentMap(Map featureToTreatmentMap) { - _cachCacheUpdaterService.updateCache(featureToTreatmentMap); + _cacheUpdaterService.updateCache(featureToTreatmentMap); _manager.updateFeatureToTreatmentMap(featureToTreatmentMap); } }