From 6af0b811d686c018d0eaa77ef6d33544c3e0cf44 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Thu, 28 Sep 2023 13:42:53 -0300 Subject: [PATCH 1/3] [SDKS-7541] Add getTreatments for sets --- .../java/io/split/client/SplitClient.java | 66 +++ .../java/io/split/client/SplitClientImpl.java | 110 ++++ .../io/split/engine/evaluator/Evaluator.java | 2 +- .../split/engine/evaluator/EvaluatorImp.java | 18 +- .../telemetry/domain/enums/MethodEnum.java | 2 + .../io/split/client/SplitClientImplTest.java | 529 ++++++++++++------ .../split/engine/evaluator/EvaluatorTest.java | 8 +- .../client/testing/SplitClientForTest.java | 20 + 8 files changed, 549 insertions(+), 206 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitClient.java b/client/src/main/java/io/split/client/SplitClient.java index e4945c8ea..4592650e2 100644 --- a/client/src/main/java/io/split/client/SplitClient.java +++ b/client/src/main/java/io/split/client/SplitClient.java @@ -268,6 +268,72 @@ public interface SplitClient { */ Map getTreatmentsWithConfig(Key key, List featureFlagNames, Map attributes); + /** + * Same as {@link #getTreatments(String, List, Map)} but it returns for each feature flag the configuration associated to the + * matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null. + *

+ *

+ * Examples include showing a different treatment to users on trial plan + * vs. premium plan. Another example is to show a different treatment + * to users created after a certain date. + * + * @param key a unique key of your customer (e.g. user_id, user_email, account_id, etc.) MUST not be null or empty. + * @param flagSet the Flag Set name that you want to evaluate. MUST not be null or empty. + * @param attributes of the customer (user, account etc.) to use in evaluation. Can be null or empty. + * @return for each feature flag the evaluated treatment, the default treatment of this feature flag, or 'control'. + */ + Map getTreatmentsByFlagSet(String key, String flagSet, Map attributes); + + /** + * Same as {@link #getTreatments(String, List, Map)} but it returns for each feature flag the configuration associated to the + * matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null. + *

+ *

+ * Examples include showing a different treatment to users on trial plan + * vs. premium plan. Another example is to show a different treatment + * to users created after a certain date. + * + * @param key a unique key of your customer (e.g. user_id, user_email, account_id, etc.) MUST not be null or empty. + * @param flagSets the names of Flag Sets that you want to evaluate. MUST not be null or empty. + * @param attributes of the customer (user, account etc.) to use in evaluation. Can be null or empty. + * @return for each feature flag the evaluated treatment, the default treatment of this feature flag, or 'control'. + */ + Map getTreatmentsByFlagSets(String key, List flagSets, Map attributes); + + /** + * Same as {@link #getTreatments(String, List, Map)} but it returns for each feature flag the configuration associated to the + * matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null. + *

+ *

+ * Examples include showing a different treatment to users on trial plan + * vs. premium plan. Another example is to show a different treatment + * to users created after a certain date. + * + * @param key a unique key of your customer (e.g. user_id, user_email, account_id, etc.) MUST not be null or empty. + * @param flagSet the Flag Set name that you want to evaluate. MUST not be null or empty. + * @param attributes of the customer (user, account etc.) to use in evaluation. Can be null or empty. + * @return for each feature flag the evaluated treatment (the default treatment of this feature flag, or 'control') and a configuration + * associated to this treatment if set. + */ + Map getTreatmentsWithConfigByFlagSet(String key, String flagSet, Map attributes); + + /** + * Same as {@link #getTreatments(String, List, Map)} but it returns for each feature flag the configuration associated to the + * matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null. + *

+ *

+ * Examples include showing a different treatment to users on trial plan + * vs. premium plan. Another example is to show a different treatment + * to users created after a certain date. + * + * @param key a unique key of your customer (e.g. user_id, user_email, account_id, etc.) MUST not be null or empty. + * @param flagSets the names of Flag Sets that you want to evaluate. MUST not be null or empty. + * @param attributes of the customer (user, account etc.) to use in evaluation. Can be null or empty. + * @return for each feature flag the evaluated treatment (the default treatment of this feature flag, or 'control') and a configuration + * associated to this treatment if set. + */ + Map getTreatmentsWithConfigByFlagSets(String key, List flagSets, Map attributes); + /** * Destroys the background processes and clears the cache, releasing the resources used by * the any instances of SplitClient or SplitManager generated by the client's parent SplitFactory diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java index 35839cc2e..192df1f38 100644 --- a/client/src/main/java/io/split/client/SplitClientImpl.java +++ b/client/src/main/java/io/split/client/SplitClientImpl.java @@ -12,6 +12,8 @@ import io.split.engine.evaluator.Labels; import io.split.grammar.Treatments; import io.split.inputValidation.EventsValidator; +import io.split.inputValidation.FlagSetsValidResult; +import io.split.inputValidation.FlagSetsValidator; import io.split.inputValidation.KeyValidator; import io.split.inputValidation.SplitNameValidator; import io.split.inputValidation.TrafficTypeValidator; @@ -23,8 +25,10 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -140,6 +144,32 @@ public Map getTreatmentsWithConfig(Key key, List fe MethodEnum.TREATMENTS_WITH_CONFIG); } + @Override + public Map getTreatmentsByFlagSet(String key, String flagSet, Map attributes) { + return getTreatmentsWithSetsAndWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)), + attributes, MethodEnum.TREATMENTS_BY_FLAG_SETS).entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment())); + } + + @Override + public Map getTreatmentsByFlagSets(String key, List flagSets, Map attributes) { + return getTreatmentsWithSetsAndWithConfigInternal(key, null, flagSets, + attributes, MethodEnum.TREATMENTS_BY_FLAG_SETS).entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment())); + } + + @Override + public Map getTreatmentsWithConfigByFlagSet(String key, String flagSet, Map attributes) { + return getTreatmentsWithSetsAndWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)), + attributes, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SETS); + } + + @Override + public Map getTreatmentsWithConfigByFlagSets(String key, List flagSets, Map attributes) { + return getTreatmentsWithSetsAndWithConfigInternal(key, null, flagSets, + attributes, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SETS); + } + @Override public boolean track(String key, String trafficType, String eventType) { Event event = createEvent(key, trafficType, eventType); @@ -341,6 +371,86 @@ private Map getTreatmentsWithConfigInternal(String matching } } + private Map getTreatmentsWithSetsAndWithConfigInternal(String matchingKey, String bucketingKey, List sets, + Map attributes, MethodEnum methodEnum) { + long initTime = System.currentTimeMillis(); + if (sets == null || sets.isEmpty()) { + _log.warn(String.format("%s: sets must be a non-empty array", methodEnum.getMethod())); + return new HashMap<>(); + } + FlagSetsValidResult flagSetsValidResult = FlagSetsValidator.areValid(sets); + try { + if (!flagSetsValidResult.getValid()) { + _log.warn("The sets are invalid"); + return new HashMap<>(); + } + if (filterSetsAreInConfig(flagSetsValidResult.getFlagSets()).isEmpty()) { + _log.warn("The sets are not"); + return new HashMap<>(); + } + checkSDKReady(methodEnum); + if (_container.isDestroyed()) { + _log.error("Client has already been destroyed - no calls possible"); + return createMapControl(getAllFlags(flagSetsValidResult.getFlagSets())); + } + if (!KeyValidator.bucketingKeyIsValid(bucketingKey, _config.maxStringLength(), methodEnum.getMethod())) { + return createMapControl(getAllFlags(flagSetsValidResult.getFlagSets())); + } + Map evaluatorResult = _evaluator.evaluateFeaturesByFlagSets(matchingKey, + bucketingKey, new ArrayList<>(flagSetsValidResult.getFlagSets())); + List impressions = new ArrayList<>(); + Map result = new HashMap<>(); + evaluatorResult.keySet().forEach(t -> { + if (evaluatorResult.get(t).treatment.equals(Treatments.CONTROL) && evaluatorResult.get(t).label. + equals(Labels.DEFINITION_NOT_FOUND) && _gates.isSDKReady()) { + _log.warn(String.format("%s: you passed \"%s\" that does not exist in this environment please double check " + + "what feature flags exist in the Split user interface.", methodEnum.getMethod(), t)); + result.put(t, SPLIT_RESULT_CONTROL); + } else { + result.put(t, new SplitResult(evaluatorResult.get(t).treatment, evaluatorResult.get(t).configurations)); + impressions.add(new Impression(matchingKey, bucketingKey, t, evaluatorResult.get(t).treatment, System.currentTimeMillis(), + evaluatorResult.get(t).label, evaluatorResult.get(t).changeNumber, attributes)); + } + }); + _telemetryEvaluationProducer.recordLatency(methodEnum, System.currentTimeMillis() - initTime); + if (impressions.size() > 0) { + _impressionManager.track(impressions); + } + return result; + } catch (Exception e) { + try { + _telemetryEvaluationProducer.recordException(methodEnum); + _log.error("CatchAll Exception", e); + } catch (Exception e1) { + // ignore + } + return createMapControl(getAllFlags(flagSetsValidResult.getFlagSets())); + } + } + + private List filterSetsAreInConfig(HashSet sets) { + HashSet configSets = _config.getSetsFilter(); + List setsToReturn = new ArrayList<>(); + for (String set : sets) { + if (!configSets.contains(set)) { + _log.warn(String.format("GetTreatmentsByFlagSets: you passed %s which is not part of the configured FlagSetsFilter, " + + "ignoring Flag Set.", set)); + continue; + } + setsToReturn.add(set); + } + return setsToReturn; + } + + private List getAllFlags(HashSet sets) { + Map> namesBySets = _splitCacheConsumer.getNamesByFlagSets(new ArrayList<>(sets)); + HashSet flags = new HashSet<>(); + for (String set: namesBySets.keySet()) { + flags.addAll(namesBySets.get(set)); + } + return new ArrayList<>(flags); + } + private void recordStats(String matchingKey, String bucketingKey, String featureFlagName, long start, String result, String operation, String label, Long changeNumber, Map attributes) { try { diff --git a/client/src/main/java/io/split/engine/evaluator/Evaluator.java b/client/src/main/java/io/split/engine/evaluator/Evaluator.java index 925cc0e2c..cc1c1b3fd 100644 --- a/client/src/main/java/io/split/engine/evaluator/Evaluator.java +++ b/client/src/main/java/io/split/engine/evaluator/Evaluator.java @@ -8,5 +8,5 @@ EvaluatorImp.TreatmentLabelAndChangeNumber evaluateFeature(String matchingKey, S Map attributes); Map evaluateFeatures(String matchingKey, String bucketingKey, List featureFlags, Map attributes); - EvaluatorImp.ByFlagSetsResult evaluateFeaturesByFlagSets(String key, String bucketingKey, List flagSets); + Map evaluateFeaturesByFlagSets(String key, String bucketingKey, List flagSets); } \ No newline at end of file diff --git a/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java b/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java index 26e89e088..8a2be81e2 100644 --- a/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java +++ b/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java @@ -54,13 +54,11 @@ public Map evaluateFeatures(String matchi } @Override - public ByFlagSetsResult evaluateFeaturesByFlagSets(String key, String bucketingKey, List flagSets) { - Stopwatch stopwatch = Stopwatch.createStarted(); + public Map evaluateFeaturesByFlagSets(String key, String bucketingKey, + List flagSets) { List flagSetsWithNames = getFeatureFlagNamesByFlagSets(flagSets); Map evaluations = evaluateFeatures(key, bucketingKey, flagSetsWithNames, null); - stopwatch.stop(); - long millis = stopwatch.elapsed(TimeUnit.MILLISECONDS); - return new ByFlagSetsResult(evaluations, millis); + return evaluations; } private List getFeatureFlagNamesByFlagSets(List flagSets) { @@ -155,16 +153,6 @@ private TreatmentLabelAndChangeNumber evaluateParsedSplit(String matchingKey, St } } - public static class ByFlagSetsResult { - public final Map evaluations; - public final long elapsedMilliseconds; - - public ByFlagSetsResult(Map evaluations, long elapsed) { - this.evaluations = evaluations; - this.elapsedMilliseconds = elapsed; - } - } - public static final class TreatmentLabelAndChangeNumber { public final String treatment; public final String label; diff --git a/client/src/main/java/io/split/telemetry/domain/enums/MethodEnum.java b/client/src/main/java/io/split/telemetry/domain/enums/MethodEnum.java index 8f99527f2..6239357c6 100644 --- a/client/src/main/java/io/split/telemetry/domain/enums/MethodEnum.java +++ b/client/src/main/java/io/split/telemetry/domain/enums/MethodEnum.java @@ -5,6 +5,8 @@ public enum MethodEnum { TREATMENTS("getTreatments"), TREATMENT_WITH_CONFIG("getTreatmentWithConfig"), TREATMENTS_WITH_CONFIG("getTreatmentsWithConfig"), + TREATMENTS_BY_FLAG_SETS("getTreatmentsByFlagSet"), + TREATMENTS_WITH_CONFIG_BY_FLAG_SETS("getTreatmentsWithConfigByFlagSet"), TRACK("track"); private String _method; diff --git a/client/src/test/java/io/split/client/SplitClientImplTest.java b/client/src/test/java/io/split/client/SplitClientImplTest.java index 99e889969..964c8d563 100644 --- a/client/src/test/java/io/split/client/SplitClientImplTest.java +++ b/client/src/test/java/io/split/client/SplitClientImplTest.java @@ -47,10 +47,10 @@ import java.util.Set; import java.util.concurrent.TimeoutException; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyList; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; @@ -67,7 +67,8 @@ public class SplitClientImplTest { private static TelemetryStorage TELEMETRY_STORAGE = Mockito.mock(InMemoryTelemetryStorage.class); - private SplitClientConfig config = SplitClientConfig.builder().setBlockUntilReadyTimeout(100).build(); + private SplitClientConfig config = SplitClientConfig.builder().setBlockUntilReadyTimeout(100).flagSetsFilter(new ArrayList<>( + Arrays.asList("set1", "set2", "set3"))).build(); @Before public void updateTelemetryStorage() { @@ -97,8 +98,7 @@ public void null_key_results_in_control() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - - assertThat(client.getTreatment(null, "test1"), is(equalTo(Treatments.CONTROL))); + assertEquals(Treatments.CONTROL, client.getTreatment(null, "test1")); verifyZeroInteractions(splitCacheConsumer); } @@ -126,8 +126,7 @@ public void null_test_results_in_control() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - - assertThat(client.getTreatment("adil@relateiq.com", null), is(equalTo(Treatments.CONTROL))); + assertEquals(Treatments.CONTROL, client.getTreatment("adil@relateiq.com", null)); verifyZeroInteractions(splitCacheConsumer); } @@ -148,7 +147,7 @@ public void exceptions_result_in_control() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("adil@relateiq.com", "test1"), is(equalTo(Treatments.CONTROL))); + assertEquals(Treatments.CONTROL, client.getTreatment("adil@relateiq.com", "test1")); verify(splitCacheConsumer).get("test1"); } @@ -182,7 +181,7 @@ public void works() { int numKeys = 5; for (int i = 0; i < numKeys; i++) { String randomKey = RandomStringUtils.random(10); - assertThat(client.getTreatment(randomKey, test), is(equalTo("on"))); + Assert.assertEquals("on", client.getTreatment(randomKey, test)); } verify(splitCacheConsumer, times(numKeys)).get(test); @@ -214,13 +213,10 @@ public void works_null_config() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - - String randomKey = RandomStringUtils.random(10); SplitResult result = client.getTreatmentWithConfig(randomKey, test); - assertThat(result.treatment(), is(equalTo(Treatments.ON))); - assertThat(result.config(), is(nullValue())); - + assertEquals(Treatments.ON, result.treatment()); + assertNull(result.config()); verify(splitCacheConsumer).get(test); } @@ -256,8 +252,8 @@ public void worksAndHasConfig() { for (int i = 0; i < numKeys; i++) { Map attributes = new HashMap<>(); String randomKey = RandomStringUtils.random(10); - assertThat(client.getTreatment(randomKey, test), is(equalTo("on"))); - assertThat(client.getTreatmentWithConfig(randomKey, test, attributes).config(), is(equalTo(configurations.get("on")))); + assertEquals("on", client.getTreatment(randomKey, test)); + assertEquals(configurations.get("on"), client.getTreatmentWithConfig(randomKey, test, attributes).config()); } // Times 2 because we are calling getTreatment twice. Once for getTreatment and one for getTreatmentWithConfig @@ -287,7 +283,7 @@ public void last_condition_is_always_default() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("pato@codigo.com", test), is(equalTo(Treatments.OFF))); + assertEquals(Treatments.OFF, client.getTreatment("pato@codigo.com", test)); verify(splitCacheConsumer).get(test); } @@ -326,8 +322,8 @@ public void last_condition_is_always_default_but_with_treatment() { ); SplitResult result = client.getTreatmentWithConfig("pato@codigo.com", test); - assertThat(result.treatment(), is(equalTo(Treatments.OFF))); - assertThat(result.config(), is(equalTo("{\"size\" : 30}"))); + assertEquals(Treatments.OFF, result.treatment()); + assertEquals("{\"size\" : 30}", result.config()); verify(splitCacheConsumer).get(test); } @@ -359,9 +355,9 @@ public void multiple_conditions_work() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("adil@codigo.com", test), is(equalTo("on"))); - assertThat(client.getTreatment("pato@codigo.com", test), is(equalTo("off"))); - assertThat(client.getTreatment("trevor@codigo.com", test), is(equalTo("on"))); + assertEquals("on", client.getTreatment("adil@codigo.com", test)); + assertEquals("off", client.getTreatment("pato@codigo.com", test)); + assertEquals("on", client.getTreatment("adil@codigo.com", test)); verify(splitCacheConsumer, times(3)).get(test); verify(TELEMETRY_STORAGE, times(3)).recordNonReadyUsage(); @@ -391,7 +387,7 @@ public void killed_test_always_goes_to_default() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("adil@codigo.com", test), is(equalTo(Treatments.OFF))); + assertEquals(Treatments.OFF, client.getTreatment("adil@codigo.com", test)); verify(splitCacheConsumer).get(test); } @@ -430,8 +426,8 @@ public void killed_test_always_goes_to_default_has_config() { ); SplitResult result = client.getTreatmentWithConfig("adil@codigo.com", test); - assertThat(result.treatment(), is(equalTo(Treatments.OFF))); - assertThat(result.config(), is(equalTo("{\"size\" : 30}"))); + assertEquals(Treatments.OFF, result.treatment()); + assertEquals("{\"size\" : 30}", result.config()); verify(splitCacheConsumer).get(test); } @@ -465,8 +461,8 @@ public void dependency_matcher_on() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("key", parent), is(equalTo(Treatments.ON))); - assertThat(client.getTreatment("key", dependent), is(equalTo(Treatments.ON))); + assertEquals(Treatments.ON, client.getTreatment("key", parent)); + assertEquals(Treatments.ON, client.getTreatment("key", dependent)); } @Test @@ -498,8 +494,8 @@ public void dependency_matcher_off() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("key", parent), is(equalTo(Treatments.ON))); - assertThat(client.getTreatment("key", dependent), is(equalTo(Treatments.OFF))); + assertEquals(Treatments.ON, client.getTreatment("key", parent)); + assertEquals(Treatments.OFF, client.getTreatment("key", dependent)); } @Test @@ -525,7 +521,7 @@ public void dependency_matcher_control() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("key", dependent), is(equalTo(Treatments.ON))); + assertEquals(Treatments.ON, client.getTreatment("key", dependent)); } @Test @@ -553,12 +549,11 @@ public void attributes_work() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("adil@codigo.com", test), is(equalTo("on"))); - assertThat(client.getTreatment("adil@codigo.com", test, null), is(equalTo("on"))); - assertThat(client.getTreatment("adil@codigo.com", test, ImmutableMap.of()), is(equalTo("on"))); - - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 10)), is(equalTo("on"))); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 9)), is(equalTo("off"))); + assertEquals("on", client.getTreatment("adil@codigo.com", test)); + assertEquals("on", client.getTreatment("adil@codigo.com", test, null)); + assertEquals("on", client.getTreatment("adil@codigo.com", test, ImmutableMap.of())); + assertEquals("on", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 10))); + assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 9))); verify(splitCacheConsumer, times(5)).get(test); } @@ -587,12 +582,12 @@ public void attributes_work_2() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("adil@codigo.com", test), is(equalTo("off"))); - assertThat(client.getTreatment("adil@codigo.com", test, null), is(equalTo("off"))); - assertThat(client.getTreatment("adil@codigo.com", test, ImmutableMap.of()), is(equalTo("off"))); + assertEquals("off", client.getTreatment("adil@codigo.com", test)); + assertEquals("off", client.getTreatment("adil@codigo.com", test, null)); + assertEquals("off", client.getTreatment("adil@codigo.com", test, ImmutableMap.of())); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 10)), is(equalTo("off"))); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 0)), is(equalTo("on"))); + assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 10))); + assertEquals("on", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 0))); verify(splitCacheConsumer, times(5)).get(test); } @@ -621,14 +616,13 @@ public void attributes_greater_than_negative_number() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("adil@codigo.com", test), is(equalTo("off"))); - assertThat(client.getTreatment("adil@codigo.com", test, null), is(equalTo("off"))); - assertThat(client.getTreatment("adil@codigo.com", test, ImmutableMap.of()), is(equalTo("off"))); - - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 10)), is(equalTo("off"))); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", -20)), is(equalTo("on"))); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 20)), is(equalTo("off"))); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", -21)), is(equalTo("off"))); + assertEquals("off", client.getTreatment("adil@codigo.com", test)); + assertEquals("off", client.getTreatment("adil@codigo.com", test, null)); + assertEquals("off", client.getTreatment("adil@codigo.com", test, ImmutableMap.of())); + assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 10))); + assertEquals("on", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", -20))); + assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", 20))); + assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("age", -21))); verify(splitCacheConsumer, times(7)).get(test); } @@ -658,16 +652,16 @@ public void attributes_for_sets() { new EvaluatorImp(splitCacheConsumer ,segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("adil@codigo.com", test), is(equalTo("off"))); - assertThat(client.getTreatment("adil@codigo.com", test, null), is(equalTo("off"))); - assertThat(client.getTreatment("adil@codigo.com", test, ImmutableMap.of()), is(equalTo("off"))); + assertEquals("off", client.getTreatment("adil@codigo.com", test)); + assertEquals("off", client.getTreatment("adil@codigo.com", test, null)); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList())), is(equalTo("off"))); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList(""))), is(equalTo("off"))); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList("talk"))), is(equalTo("off"))); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList("sms"))), is(equalTo("on"))); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList("sms", "video"))), is(equalTo("on"))); - assertThat(client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList("video"))), is(equalTo("on"))); + assertEquals("off", client.getTreatment("adil@codigo.com", test, ImmutableMap.of())); + assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList()))); + assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList("")))); + assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList("talk")))); + assertEquals("on", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList("sms")))); + assertEquals("on", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList("sms", "video")))); + assertEquals("on", client.getTreatment("pato@codigo.com", test, ImmutableMap.of("products", Lists.newArrayList("video")))); verify(splitCacheConsumer, times(9)).get(test); } @@ -702,7 +696,7 @@ public void labels_are_populated() { ); Map attributes = ImmutableMap.of("age", -20, "acv", "1000000"); - assertThat(client.getTreatment("pato@codigo.com", test, attributes), is(equalTo("on"))); + assertEquals("on", client.getTreatment("pato@codigo.com", test, attributes)); ArgumentCaptor impressionCaptor = ArgumentCaptor.forClass(List.class); @@ -713,9 +707,9 @@ public void labels_are_populated() { assertEquals(1, impressions.size()); Impression impression = impressions.get(0); - assertThat(impression.appliedRule(), is(equalTo("foolabel"))); + assertEquals("foolabel", impression.appliedRule()); - assertThat(impression.attributes(), is(attributes)); + assertEquals(attributes, impression.attributes()); } @Test @@ -802,7 +796,7 @@ private void traffic_allocation(String key, int trafficAllocation, int trafficAl new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment(key, test), is(equalTo(expected_treatment_on_or_off))); + assertEquals(expected_treatment_on_or_off, client.getTreatment(key, test)); ArgumentCaptor impressionCaptor = ArgumentCaptor.forClass(List.class); @@ -810,7 +804,7 @@ private void traffic_allocation(String key, int trafficAllocation, int trafficAl assertNotNull(impressionCaptor.getValue()); assertEquals(1, impressionCaptor.getValue().size()); Impression impression = (Impression) impressionCaptor.getValue().get(0); - assertThat(impression.appliedRule(), is(equalTo(label))); + assertEquals(label, impression.appliedRule()); } /** @@ -854,11 +848,10 @@ public void notInTrafficAllocationDefaultConfig() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertThat(client.getTreatment("pato@split.io", test), is(equalTo(Treatments.OFF))); - + assertEquals(Treatments.OFF, client.getTreatment("pato@split.io", test)); SplitResult result = client.getTreatmentWithConfig("pato@split.io", test); - assertThat(result.treatment(), is(equalTo(Treatments.OFF))); - assertThat(result.config(), is(equalTo("{\"size\" : 30}"))); + assertEquals(Treatments.OFF, result.treatment()); + assertEquals("{\"size\" : 30}", result.config()); ArgumentCaptor impressionCaptor = ArgumentCaptor.forClass(List.class); verify(impressionsManager, times(2)).track(impressionCaptor.capture()); @@ -866,7 +859,7 @@ public void notInTrafficAllocationDefaultConfig() { assertNotNull(impressionCaptor.getValue()); assertEquals(1, impressionCaptor.getValue().size()); Impression impression = (Impression) impressionCaptor.getValue().get(0); - assertThat(impression.appliedRule(), is(equalTo("not in split"))); + assertEquals("not in split", impression.appliedRule()); } @@ -900,8 +893,8 @@ public void matching_bucketing_keys_work() { Key bad_key = new Key("adil", "aijaz"); Key good_key = new Key("aijaz", "adil"); - assertThat(client.getTreatment(bad_key, test, Collections.emptyMap()), is(equalTo("off"))); - assertThat(client.getTreatment(good_key, test, Collections.emptyMap()), is(equalTo("on"))); + assertEquals("off", client.getTreatment(bad_key, test, Collections.emptyMap())); + assertEquals("on", client.getTreatment(good_key, test, Collections.emptyMap())); verify(splitCacheConsumer, times(2)).get(test); } @@ -937,7 +930,7 @@ public void impression_metadata_is_propagated() { Map attributes = ImmutableMap.of("age", -20, "acv", "1000000"); - assertThat(client.getTreatment("pato@codigo.com", test, attributes), is(equalTo("on"))); + assertEquals("on", client.getTreatment("pato@codigo.com", test, attributes)); ArgumentCaptor impressionCaptor = ArgumentCaptor.forClass(List.class); @@ -948,8 +941,8 @@ public void impression_metadata_is_propagated() { assertEquals(1, impressionCaptor.getValue().size()); Impression impression = (Impression) impressionCaptor.getValue().get(0); - assertThat(impression.appliedRule(), is(equalTo("foolabel"))); - assertThat(impression.attributes(), is(equalTo(attributes))); + assertEquals("foolabel", impression.appliedRule()); + assertEquals(attributes, impression.attributes()); } private Partition partition(String treatment, int size) { @@ -1015,15 +1008,12 @@ public void track_with_valid_parameters() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - Assert.assertThat(client.track("validKey", "valid_traffic_type", "valid_event"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(true))); + assertTrue(client.track("validKey", "valid_traffic_type", "valid_event")); String validEventSize = new String(new char[80]).replace('\0', 'a'); String validKeySize = new String(new char[250]).replace('\0', 'a'); - Assert.assertThat(client.track(validKeySize, "valid_traffic_type", validEventSize, 10), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(true))); + assertTrue(client.track(validKeySize, "valid_traffic_type", validEventSize, 10)); verify(TELEMETRY_STORAGE, times(2)).recordLatency(Mockito.anyObject(), Mockito.anyLong()); - } @Test @@ -1041,20 +1031,12 @@ public void track_with_invalid_event_type_ids() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - - Assert.assertThat(client.track("validKey", "valid_traffic_type", ""), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(false))); - - Assert.assertThat(client.track("validKey", "valid_traffic_type", null), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(false))); - - Assert.assertThat(client.track("validKey", "valid_traffic_type", "invalid#char"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(false))); + Assert.assertFalse(client.track("validKey", "valid_traffic_type", "")); + Assert.assertFalse(client.track("validKey", "valid_traffic_type", null)); + Assert.assertFalse(client.track("validKey", "valid_traffic_type", "invalid#char")); String invalidEventSize = new String(new char[81]).replace('\0', 'a'); - Assert.assertThat(client.track("validKey", "valid_traffic_type", invalidEventSize), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(false))); - + Assert.assertFalse(client.track("validKey", "valid_traffic_type", invalidEventSize)); } @Test @@ -1073,11 +1055,8 @@ public void track_with_invalid_traffic_type_names() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - Assert.assertThat(client.track("validKey", "", "valid"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(false))); - - Assert.assertThat(client.track("validKey", null, "valid"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(false))); + Assert.assertFalse(client.track("validKey", "", "valid")); + Assert.assertFalse(client.track("validKey", null, "valid")); } @Test @@ -1096,15 +1075,11 @@ public void track_with_invalid_keys() { new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - Assert.assertThat(client.track("", "valid_traffic_type", "valid"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(false))); - - Assert.assertThat(client.track(null, "valid_traffic_type", "valid"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(false))); + Assert.assertFalse(client.track("", "valid_traffic_type", "valid")); + Assert.assertFalse(client.track(null, "valid_traffic_type", "valid")); String invalidKeySize = new String(new char[251]).replace('\0', 'a'); - Assert.assertThat(client.track(invalidKeySize, "valid_traffic_type", "valid"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(false))); + Assert.assertFalse(client.track(invalidKeySize, "valid_traffic_type", "valid")); } @Test @@ -1129,51 +1104,36 @@ public void getTreatment_with_invalid_keys() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - - Assert.assertThat(client.getTreatment("valid", "split"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.not(Treatments.CONTROL))); - - Assert.assertThat(client.getTreatment("", "split"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(Treatments.CONTROL))); - - Assert.assertThat(client.getTreatment(null, "split"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(Treatments.CONTROL))); + Assert.assertNotEquals(Treatments.CONTROL, client.getTreatment("valid", "split")); + assertEquals(Treatments.CONTROL, client.getTreatment("", "split")); + assertEquals(Treatments.CONTROL, client.getTreatment(null, "split")); String invalidKeySize = new String(new char[251]).replace('\0', 'a'); - Assert.assertThat(client.getTreatment(invalidKeySize, "split"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(Treatments.CONTROL))); - - Assert.assertThat(client.getTreatment("valid", ""), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(Treatments.CONTROL))); + assertEquals(Treatments.CONTROL, client.getTreatment(invalidKeySize, "split")); - Assert.assertThat(client.getTreatment("valid", null), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(Treatments.CONTROL))); + assertEquals(Treatments.CONTROL, client.getTreatment("valid", "")); + assertEquals(Treatments.CONTROL, client.getTreatment("valid", null)); String matchingKey = new String(new char[250]).replace('\0', 'a'); String bucketingKey = new String(new char[250]).replace('\0', 'a'); Key key = new Key(matchingKey, bucketingKey); - Assert.assertThat(client.getTreatment(key, "split", null), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.not(Treatments.CONTROL))); + Assert.assertNotEquals(Treatments.CONTROL, client.getTreatment(key, "split", null)); key = new Key("valid", ""); - Assert.assertThat(client.getTreatment(key, "split", null), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(Treatments.CONTROL))); + assertEquals(Treatments.CONTROL, client.getTreatment(key, "split", null)); key = new Key("", "valid"); - Assert.assertThat(client.getTreatment(key, "split", null), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(Treatments.CONTROL))); + assertEquals(Treatments.CONTROL, client.getTreatment(key, "split", null)); matchingKey = new String(new char[251]).replace('\0', 'a'); bucketingKey = new String(new char[250]).replace('\0', 'a'); key = new Key(matchingKey, bucketingKey); - Assert.assertThat(client.getTreatment(key, "split", null), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.is(Treatments.CONTROL))); + assertEquals(Treatments.CONTROL, client.getTreatment(key, "split", null)); matchingKey = new String(new char[250]).replace('\0', 'a'); bucketingKey = new String(new char[251]).replace('\0', 'a'); key = new Key(matchingKey, bucketingKey); - Assert.assertThat(client.getTreatment(key, "split", null), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.is(Treatments.CONTROL))); + assertEquals(Treatments.CONTROL, client.getTreatment(key, "split", null)); } @Test @@ -1199,57 +1159,53 @@ public void track_with_properties() { properties.put("ok_property", 123); properties.put("some_property", new Object()); - Assert.assertThat(client.track("key1", "user", "purchase", properties), - org.hamcrest.Matchers.is(true)); + assertTrue(client.track("key1", "user", "purchase", properties)); verify(eventClientMock).track(eventArgumentCaptor.capture(), Mockito.anyInt()); Event captured = eventArgumentCaptor.getValue(); - Assert.assertThat(captured.properties.size(), org.hamcrest.Matchers.is(2)); - Assert.assertThat((Integer) captured.properties.get("ok_property"), org.hamcrest.Matchers.is(123)); - Assert.assertThat(captured.properties.get("some_property"), org.hamcrest.Matchers.nullValue()); + assertEquals(2, captured.properties.size()); + assertEquals(123, captured.properties.get("ok_property")); + assertNull(captured.properties.get("some_property")); properties.clear(); Mockito.reset(eventClientMock); Mockito.when(eventClientMock.track((Event) Mockito.any(), Mockito.anyInt())).thenReturn(true); properties.put("ok_property", 123); properties.put("some_property", Arrays.asList(1, 2, 3)); - Assert.assertThat(client.track("key1", "user", "purchase", properties), - org.hamcrest.Matchers.is(true)); + assertTrue(client.track("key1", "user", "purchase", properties)); eventArgumentCaptor = ArgumentCaptor.forClass(Event.class); verify(eventClientMock).track(eventArgumentCaptor.capture(), Mockito.anyInt()); captured = eventArgumentCaptor.getValue(); - Assert.assertThat(captured.properties.size(), org.hamcrest.Matchers.is(2)); - Assert.assertThat((Integer) captured.properties.get("ok_property"), org.hamcrest.Matchers.is(123)); - Assert.assertThat(captured.properties.get("some_property"), org.hamcrest.Matchers.nullValue()); + assertEquals(2, captured.properties.size()); + assertEquals(123, captured.properties.get("ok_property")); + assertNull(captured.properties.get("some_property")); properties.clear(); Mockito.reset(eventClientMock); Mockito.when(eventClientMock.track((Event) Mockito.any(), Mockito.anyInt())).thenReturn(true); properties.put("ok_property", 123); properties.put("some_property", new HashMap()); - Assert.assertThat(client.track("key1", "user", "purchase", properties), - org.hamcrest.Matchers.is(true)); + assertTrue(client.track("key1", "user", "purchase", properties)); eventArgumentCaptor = ArgumentCaptor.forClass(Event.class); verify(eventClientMock).track(eventArgumentCaptor.capture(), Mockito.anyInt()); captured = eventArgumentCaptor.getValue(); - Assert.assertThat(captured.properties.size(), org.hamcrest.Matchers.is(2)); - Assert.assertThat((Integer) captured.properties.get("ok_property"), org.hamcrest.Matchers.is(123)); - Assert.assertThat(captured.properties.get("some_property"), org.hamcrest.Matchers.nullValue()); + assertEquals(2, captured.properties.size()); + assertEquals(123, captured.properties.get("ok_property")); + assertNull(captured.properties.get("some_property")); properties.clear(); Mockito.reset(eventClientMock); Mockito.when(eventClientMock.track((Event) Mockito.any(), Mockito.anyInt())).thenReturn(true); properties.put("ok_property", 123); - Assert.assertThat(client.track("key1", "user", "purchase", 123, properties), - org.hamcrest.Matchers.is(true)); + assertTrue(client.track("key1", "user", "purchase", 123, properties)); eventArgumentCaptor = ArgumentCaptor.forClass(Event.class); verify(eventClientMock).track(eventArgumentCaptor.capture(), Mockito.anyInt()); captured = eventArgumentCaptor.getValue(); - Assert.assertThat(captured.value, org.hamcrest.Matchers.is(123.0)); - Assert.assertThat(captured.trafficTypeName,org.hamcrest.Matchers.is("user")); - Assert.assertThat(captured.eventTypeId,org.hamcrest.Matchers.is("purchase")); - Assert.assertThat(captured.key,org.hamcrest.Matchers.is("key1")); - Assert.assertThat(captured.properties.size(), org.hamcrest.Matchers.is(1)); - Assert.assertThat((Integer) captured.properties.get("ok_property"), org.hamcrest.Matchers.is(123)); + assertEquals(123.0, captured.value, 0); + assertEquals("user", captured.trafficTypeName); + assertEquals("purchase", captured.eventTypeId); + assertEquals("key1", captured.key); + assertEquals(1, captured.properties.size()); + assertEquals(123, captured.properties.get("ok_property")); properties.clear(); Mockito.reset(eventClientMock); @@ -1260,18 +1216,17 @@ public void track_with_properties() { properties.put("prop4", "something"); properties.put("prop5", true); properties.put("prop6", null); - Assert.assertThat(client.track("key1", "user", "purchase", properties), - org.hamcrest.Matchers.is(true)); + assertTrue(client.track("key1", "user", "purchase", properties)); eventArgumentCaptor = ArgumentCaptor.forClass(Event.class); verify(eventClientMock).track(eventArgumentCaptor.capture(), Mockito.anyInt()); captured = eventArgumentCaptor.getValue(); - Assert.assertThat(captured.properties.size(), org.hamcrest.Matchers.is(6)); - Assert.assertThat((Integer) captured.properties.get("prop1"), org.hamcrest.Matchers.is(1)); - Assert.assertThat((Long) captured.properties.get("prop2"), org.hamcrest.Matchers.is(2L)); - Assert.assertThat((Double) captured.properties.get("prop3"), org.hamcrest.Matchers.is(7.56)); - Assert.assertThat((String) captured.properties.get("prop4"), org.hamcrest.Matchers.is("something")); - Assert.assertThat((Boolean) captured.properties.get("prop5"), org.hamcrest.Matchers.is(true)); - Assert.assertThat(captured.properties.get("prop6"), org.hamcrest.Matchers.nullValue()); + assertEquals(6, captured.properties.size()); + assertEquals(1, captured.properties.get("prop1")); + assertEquals(2L, captured.properties.get("prop2")); + assertEquals(7.56, captured.properties.get("prop3")); + assertEquals("something", captured.properties.get("prop4")); + assertTrue((Boolean) captured.properties.get("prop5")); + assertNull(captured.properties.get("prop6")); // 110 props of 300 bytes should be enough to make the event fail. properties.clear(); @@ -1279,7 +1234,7 @@ public void track_with_properties() { properties.put(new String(new char[300]).replace('\0', 'a') + i , new String(new char[300]).replace('\0', 'a') + i); } - Assert.assertThat(client.track("key1", "user", "purchase", properties), org.hamcrest.Matchers.is(false)); + Assert.assertFalse(client.track("key1", "user", "purchase", properties)); } @Test @@ -1321,19 +1276,13 @@ public void client_cannot_perform_actions_when_destroyed() throws InterruptedExc new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - Assert.assertThat(client.getTreatment("valid", "split"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.not(Treatments.CONTROL))); - - Assert.assertThat(client.track("validKey", "valid_traffic_type", "valid_event"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(true))); + assertEquals(Treatments.ON, client.getTreatment("valid", "split")); + assertTrue(client.track("validKey", "valid_traffic_type", "valid_event")); client.destroy(); - Assert.assertThat(client.getTreatment("valid", "split"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(Treatments.CONTROL))); - - Assert.assertThat(client.track("validKey", "valid_traffic_type", "valid_event"), - org.hamcrest.Matchers.is(org.hamcrest.Matchers.equalTo(false))); + assertEquals(Treatments.CONTROL, client.getTreatment("valid", "split")); + Assert.assertFalse(client.track("validKey", "valid_traffic_type", "valid_event")); } @Test @@ -1371,8 +1320,8 @@ public void worksAndHasConfigTryKetTreatmentWithKey() { Map attributes = new HashMap<>(); String randomKey = RandomStringUtils.random(10); Key key = new Key(randomKey, "BucketingKey"); - assertThat(client.getTreatment(randomKey, test), is(equalTo("on"))); - assertThat(client.getTreatmentWithConfig(key, test, attributes).config(), is(equalTo(configurations.get("on")))); + assertEquals("on", client.getTreatment(randomKey, test)); + assertEquals("{\"size\" : 30}", client.getTreatmentWithConfig(key, test, attributes).config()); } // Times 2 because we are calling getTreatment twice. Once for getTreatment and one for getTreatmentWithConfig @@ -1432,8 +1381,6 @@ public void null_key_results_in_control_getTreatments() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - - assertEquals(Treatments.CONTROL, client.getTreatments(null, Collections.singletonList("test1")).get("test1")); verifyZeroInteractions(splitCacheConsumer); @@ -1463,7 +1410,6 @@ public void null_splits_results_in_empty_getTreatments() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - assertEquals(0, client.getTreatments("key", null).size()); verifyZeroInteractions(splitCacheConsumer); @@ -1493,8 +1439,6 @@ public void exceptions_result_in_control_getTreatments() { verify(splitCacheConsumer).fetchMany(anyList()); } - - @Test public void getTreatments_works() { String test = "test1"; @@ -1548,8 +1492,6 @@ public void empty_splits_results_in_null_getTreatments() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - - Map result = client.getTreatments("key", new ArrayList<>()); assertNotNull(result); assertTrue(result.isEmpty()); @@ -1609,14 +1551,12 @@ public void works_treatments() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - Map result = client.getTreatments("anyKey", Arrays.asList(test, test2)); assertNotNull(result); assertEquals(2, result.size()); assertEquals("on", result.get(test)); assertEquals("on", result.get(test2)); - verify(splitCacheConsumer, times(1)).fetchMany(anyList()); verify(TELEMETRY_STORAGE, times(1)).recordLatency(Mockito.anyObject(), Mockito.anyLong()); } @@ -1654,7 +1594,6 @@ public void works_one_control_treatments() { assertEquals("on", result.get(test)); assertEquals("control", result.get(test2)); - verify(splitCacheConsumer, times(1)).fetchMany(anyList()); verify(TELEMETRY_STORAGE, times(1)).recordLatency(Mockito.anyObject(), Mockito.anyLong()); } @@ -1691,7 +1630,6 @@ public void treatments_worksAndHasConfig() { gates, new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE ); - Map attributes = new HashMap<>(); Map result = client.getTreatmentsWithConfig("randomKey", Arrays.asList(test, test2, "", null), attributes); assertEquals(2, result.size()); @@ -1699,6 +1637,225 @@ public void treatments_worksAndHasConfig() { assertNull(result.get(test2).config()); assertEquals("control", result.get(test2).treatment()); + verify(splitCacheConsumer, times(1)).fetchMany(anyList()); + } + + @Test + public void testTreatmentsByFlagSet() { + String test = "test1"; + + ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), + Lists.newArrayList(partition("on", 100))); + List conditions = Lists.newArrayList(rollOutToEveryone); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, + null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2"))); + + SDKReadinessGates gates = mock(SDKReadinessGates.class); + SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); + SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class); + Map fetchManyResult = new HashMap<>(); + fetchManyResult.put(test, parsedSplit); + when(splitCacheConsumer.fetchMany(new ArrayList<>(Arrays.asList(test)))).thenReturn(fetchManyResult); + List sets = new ArrayList<>(Arrays.asList("set1")); + Map> flagsBySets = new HashMap<>(); + flagsBySets.put("set1", new HashSet<>(Arrays.asList(test))); + when(splitCacheConsumer.getNamesByFlagSets(sets)).thenReturn(flagsBySets); + when(gates.isSDKReady()).thenReturn(true); + + SplitClientImpl client = new SplitClientImpl( + mock(SplitFactory.class), + splitCacheConsumer, + new ImpressionsManager.NoOpImpressionsManager(), + NoopEventsStorageImp.create(), + config, + gates, + new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE + ); + + int numKeys = 5; + Map getTreatmentResult; + for (int i = 0; i < numKeys; i++) { + String randomKey = RandomStringUtils.random(10); + getTreatmentResult = client.getTreatmentsByFlagSet(randomKey, "set1", null); + assertEquals("on", getTreatmentResult.get(test)); + } + verify(splitCacheConsumer, times(numKeys)).fetchMany(new ArrayList<>(Arrays.asList(test))); + verify(TELEMETRY_STORAGE, times(5)).recordLatency(Mockito.anyObject(), Mockito.anyLong()); + } + + @Test + public void testTreatmentsByFlagSetInvalid() { + String test = "test1"; + + ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), + Lists.newArrayList(partition("on", 100))); + List conditions = Lists.newArrayList(rollOutToEveryone); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, + null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2"))); + + SDKReadinessGates gates = mock(SDKReadinessGates.class); + SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); + SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class); + List sets = new ArrayList<>(); + when(gates.isSDKReady()).thenReturn(true); + + SplitClientImpl client = new SplitClientImpl( + mock(SplitFactory.class), + splitCacheConsumer, + new ImpressionsManager.NoOpImpressionsManager(), + NoopEventsStorageImp.create(), + config, + gates, + new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE + ); + assertTrue(client.getTreatmentsByFlagSet(RandomStringUtils.random(10), "", null).isEmpty()); + } + + @Test + public void testTreatmentsByFlagSets() { + String test = "test1"; + String test2 = "test2"; + + ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), + Lists.newArrayList(partition("on", 100))); + List conditions = Lists.newArrayList(rollOutToEveryone); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, + null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2"))); + ParsedSplit parsedSplit2 = ParsedSplit.createParsedSplitForTests(test2, 123, false, Treatments.OFF, conditions, + null, 1, 1, new HashSet<>(Arrays.asList("set3", "set4"))); + + SDKReadinessGates gates = mock(SDKReadinessGates.class); + SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); + SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class); + + Map fetchManyResult = new HashMap<>(); + fetchManyResult.put(test, parsedSplit); + fetchManyResult.put(test2, parsedSplit2); + when(splitCacheConsumer.fetchMany(new ArrayList<>(Arrays.asList(test2, test)))).thenReturn(fetchManyResult); + + List sets = new ArrayList<>(Arrays.asList("set3", "set1")); + Map> flagsBySets = new HashMap<>(); + flagsBySets.put("set1", new HashSet<>(Arrays.asList(test))); + flagsBySets.put("set3", new HashSet<>(Arrays.asList(test2))); + + when(splitCacheConsumer.getNamesByFlagSets(sets)).thenReturn(flagsBySets); + when(gates.isSDKReady()).thenReturn(true); + + SplitClientImpl client = new SplitClientImpl( + mock(SplitFactory.class), + splitCacheConsumer, + new ImpressionsManager.NoOpImpressionsManager(), + NoopEventsStorageImp.create(), + config, + gates, + new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE + ); + int numKeys = 5; + Map getTreatmentResult; + for (int i = 0; i < numKeys; i++) { + String randomKey = RandomStringUtils.random(10); + getTreatmentResult = client.getTreatmentsByFlagSets(randomKey, Arrays.asList("set1", "set3"), null); + assertEquals("on", getTreatmentResult.get(test)); + assertEquals("on", getTreatmentResult.get(test2)); + } + verify(splitCacheConsumer, times(numKeys)).fetchMany(new ArrayList<>(Arrays.asList(test2, test))); + verify(TELEMETRY_STORAGE, times(5)).recordLatency(Mockito.anyObject(), Mockito.anyLong()); + } + + @Test + public void treatments_worksAndHasConfigFlagSet() { + String test = "test1"; + String test2 = "test2"; + + ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100))); + List conditions = Lists.newArrayList(rollOutToEveryone); + + // Add config for only one treatment + Map configurations = new HashMap<>(); + configurations.put(Treatments.ON, "{\"size\" : 30}"); + configurations.put(Treatments.CONTROL, "{\"size\" : 30}"); + + + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, + null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1"))); + Map parsedSplits = new HashMap<>(); + parsedSplits.put(test, parsedSplit); + + SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); + SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class); + when(splitCacheConsumer.fetchMany(anyList())).thenReturn(parsedSplits); + + List sets = new ArrayList<>(Arrays.asList("set1")); + Map> flagsBySets = new HashMap<>(); + flagsBySets.put("set1", new HashSet<>(Arrays.asList(test, test2))); + when(splitCacheConsumer.getNamesByFlagSets(sets)).thenReturn(flagsBySets); + + SDKReadinessGates gates = mock(SDKReadinessGates.class); + + SplitClientImpl client = new SplitClientImpl( + mock(SplitFactory.class), + splitCacheConsumer, + new ImpressionsManager.NoOpImpressionsManager(), + NoopEventsStorageImp.create(), + config, + gates, + new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE + ); + Map attributes = new HashMap<>(); + Map result = client.getTreatmentsWithConfigByFlagSet("randomKey", "set1", attributes); + assertEquals(2, result.size()); + assertEquals(configurations.get("on"), result.get(test).config()); + assertNull(result.get(test2).config()); + assertEquals("control", result.get(test2).treatment()); + + verify(splitCacheConsumer, times(1)).fetchMany(anyList()); + } + + @Test + public void treatments_worksAndHasConfigFlagSets() { + String test = "test1"; + String test2 = "test2"; + + ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100))); + List conditions = Lists.newArrayList(rollOutToEveryone); + + // Add config for only one treatment + Map configurations = new HashMap<>(); + configurations.put(Treatments.ON, "{\"size\" : 30}"); + configurations.put(Treatments.CONTROL, "{\"size\" : 30}"); + + + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, + null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1"))); + Map parsedSplits = new HashMap<>(); + parsedSplits.put(test, parsedSplit); + + SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); + SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class); + when(splitCacheConsumer.fetchMany(anyList())).thenReturn(parsedSplits); + + List sets = new ArrayList<>(Arrays.asList("set1")); + Map> flagsBySets = new HashMap<>(); + flagsBySets.put("set1", new HashSet<>(Arrays.asList(test, test2))); + when(splitCacheConsumer.getNamesByFlagSets(sets)).thenReturn(flagsBySets); + + SDKReadinessGates gates = mock(SDKReadinessGates.class); + + SplitClientImpl client = new SplitClientImpl( + mock(SplitFactory.class), + splitCacheConsumer, + new ImpressionsManager.NoOpImpressionsManager(), + NoopEventsStorageImp.create(), + config, + gates, + new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE + ); + Map attributes = new HashMap<>(); + Map result = client.getTreatmentsWithConfigByFlagSets("randomKey", new ArrayList<>(Arrays.asList("set1")), attributes); + assertEquals(2, result.size()); + assertEquals(configurations.get("on"), result.get(test).config()); + assertNull(result.get(test2).config()); + assertEquals("control", result.get(test2).treatment()); verify(splitCacheConsumer, times(1)).fetchMany(anyList()); } diff --git a/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java b/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java index 622c6b57a..536965c18 100644 --- a/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java +++ b/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java @@ -161,9 +161,9 @@ public void evaluateWithSets() { parsedSplits.put(SPLIT_NAME, split); Mockito.when(_splitCacheConsumer.fetchMany(Arrays.asList(SPLIT_NAME))).thenReturn(parsedSplits); - EvaluatorImp.ByFlagSetsResult result = _evaluator.evaluateFeaturesByFlagSets(MATCHING_KEY, BUCKETING_KEY, sets); + Map result = _evaluator.evaluateFeaturesByFlagSets(MATCHING_KEY, BUCKETING_KEY, sets); - EvaluatorImp.TreatmentLabelAndChangeNumber treatmentLabelAndChangeNumber = result.evaluations.get(SPLIT_NAME); + EvaluatorImp.TreatmentLabelAndChangeNumber treatmentLabelAndChangeNumber = result.get(SPLIT_NAME); assertEquals(DEFAULT_TREATMENT_VALUE, treatmentLabelAndChangeNumber.treatment); assertEquals("default rule", treatmentLabelAndChangeNumber.label); @@ -179,7 +179,7 @@ public void evaluateWithSetsNotHaveFlags() { Map parsedSplits = new HashMap<>(); Mockito.when(_splitCacheConsumer.fetchMany(Arrays.asList(SPLIT_NAME))).thenReturn(parsedSplits); - EvaluatorImp.ByFlagSetsResult result = _evaluator.evaluateFeaturesByFlagSets(MATCHING_KEY, BUCKETING_KEY, sets); - Assert.assertTrue(result.evaluations.isEmpty()); + Map result = _evaluator.evaluateFeaturesByFlagSets(MATCHING_KEY, BUCKETING_KEY, sets); + Assert.assertTrue(result.isEmpty()); } } \ No newline at end of file diff --git a/testing/src/main/java/io/split/client/testing/SplitClientForTest.java b/testing/src/main/java/io/split/client/testing/SplitClientForTest.java index 468c2ee74..885991a44 100644 --- a/testing/src/main/java/io/split/client/testing/SplitClientForTest.java +++ b/testing/src/main/java/io/split/client/testing/SplitClientForTest.java @@ -132,6 +132,26 @@ public Map getTreatmentsWithConfig(Key key, List fe return treatments; } + @Override + public Map getTreatmentsByFlagSet(String key, String flagSet, Map attributes) { + return null; + } + + @Override + public Map getTreatmentsByFlagSets(String key, List flagSets, Map attributes) { + return null; + } + + @Override + public Map getTreatmentsWithConfigByFlagSet(String key, String flagSet, Map attributes) { + return null; + } + + @Override + public Map getTreatmentsWithConfigByFlagSets(String key, List flagSets, Map attributes) { + return null; + } + @Override public void destroy() { From 67ac3c9e755aeec566eed1e01088e139b501653b Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Fri, 29 Sep 2023 13:26:43 -0300 Subject: [PATCH 2/3] [SDKS-7541] Pr suggestions --- .../src/main/java/io/split/client/SplitClientImpl.java | 9 ++++++--- .../java/io/split/telemetry/domain/enums/MethodEnum.java | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java index 192df1f38..7105814f7 100644 --- a/client/src/main/java/io/split/client/SplitClientImpl.java +++ b/client/src/main/java/io/split/client/SplitClientImpl.java @@ -147,7 +147,7 @@ public Map getTreatmentsWithConfig(Key key, List fe @Override public Map getTreatmentsByFlagSet(String key, String flagSet, Map attributes) { return getTreatmentsWithSetsAndWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)), - attributes, MethodEnum.TREATMENTS_BY_FLAG_SETS).entrySet().stream() + attributes, MethodEnum.TREATMENTS_BY_FLAG_SET).entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment())); } @@ -161,7 +161,7 @@ public Map getTreatmentsByFlagSets(String key, List flag @Override public Map getTreatmentsWithConfigByFlagSet(String key, String flagSet, Map attributes) { return getTreatmentsWithSetsAndWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)), - attributes, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SETS); + attributes, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SET); } @Override @@ -385,7 +385,7 @@ private Map getTreatmentsWithSetsAndWithConfigInternal(Stri return new HashMap<>(); } if (filterSetsAreInConfig(flagSetsValidResult.getFlagSets()).isEmpty()) { - _log.warn("The sets are not"); + _log.warn("The sets are not in flagSetsFilter config"); return new HashMap<>(); } checkSDKReady(methodEnum); @@ -393,6 +393,9 @@ private Map getTreatmentsWithSetsAndWithConfigInternal(Stri _log.error("Client has already been destroyed - no calls possible"); return createMapControl(getAllFlags(flagSetsValidResult.getFlagSets())); } + if (!KeyValidator.isValid(matchingKey, "matchingKey", _config.maxStringLength(), methodEnum.getMethod())) { + return createMapControl(getAllFlags(flagSetsValidResult.getFlagSets())); + } if (!KeyValidator.bucketingKeyIsValid(bucketingKey, _config.maxStringLength(), methodEnum.getMethod())) { return createMapControl(getAllFlags(flagSetsValidResult.getFlagSets())); } diff --git a/client/src/main/java/io/split/telemetry/domain/enums/MethodEnum.java b/client/src/main/java/io/split/telemetry/domain/enums/MethodEnum.java index 6239357c6..27b72dbfc 100644 --- a/client/src/main/java/io/split/telemetry/domain/enums/MethodEnum.java +++ b/client/src/main/java/io/split/telemetry/domain/enums/MethodEnum.java @@ -5,8 +5,10 @@ public enum MethodEnum { TREATMENTS("getTreatments"), TREATMENT_WITH_CONFIG("getTreatmentWithConfig"), TREATMENTS_WITH_CONFIG("getTreatmentsWithConfig"), - TREATMENTS_BY_FLAG_SETS("getTreatmentsByFlagSet"), - TREATMENTS_WITH_CONFIG_BY_FLAG_SETS("getTreatmentsWithConfigByFlagSet"), + TREATMENTS_BY_FLAG_SET("getTreatmentsByFlagSet"), + TREATMENTS_BY_FLAG_SETS("getTreatmentsByFlagSets"), + TREATMENTS_WITH_CONFIG_BY_FLAG_SET("getTreatmentsWithConfigByFlagSet"), + TREATMENTS_WITH_CONFIG_BY_FLAG_SETS("getTreatmentsWithConfigByFlagSets"), TRACK("track"); private String _method; From 49455e08260d834e78fc0fe7fc378c200041e8db Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Fri, 29 Sep 2023 17:43:43 -0300 Subject: [PATCH 3/3] [SDKS-7541] Pr sugesstion --- .../java/io/split/client/SplitClientImpl.java | 114 ++++++------------ 1 file changed, 37 insertions(+), 77 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java index 7105814f7..6ca0f8bc2 100644 --- a/client/src/main/java/io/split/client/SplitClientImpl.java +++ b/client/src/main/java/io/split/client/SplitClientImpl.java @@ -115,58 +115,58 @@ public Map getTreatments(String key, List featureFlagNam @Override public Map getTreatments(String key, List featureFlagNames, Map attributes) { - return getTreatmentsWithConfigInternal(key, null, featureFlagNames, attributes, MethodEnum.TREATMENTS) + return getTreatmentsWithConfigInternal(key, null, featureFlagNames, null, attributes, MethodEnum.TREATMENTS) .entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment())); } @Override public Map getTreatments(Key key, List featureFlagNames, Map attributes) { - return getTreatmentsWithConfigInternal(key.matchingKey(), key.bucketingKey(), featureFlagNames, attributes, MethodEnum.TREATMENTS) + return getTreatmentsWithConfigInternal(key.matchingKey(), key.bucketingKey(), featureFlagNames, null, attributes, MethodEnum.TREATMENTS) .entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment())); } @Override public Map getTreatmentsWithConfig(String key, List featureFlagNames) { - return getTreatmentsWithConfigInternal(key, null, featureFlagNames, Collections.emptyMap(), + return getTreatmentsWithConfigInternal(key, null, featureFlagNames, null, Collections.emptyMap(), MethodEnum.TREATMENTS_WITH_CONFIG); } @Override public Map getTreatmentsWithConfig(String key, List featureFlagNames, Map attributes) { - return getTreatmentsWithConfigInternal(key, null, featureFlagNames, attributes, MethodEnum.TREATMENTS_WITH_CONFIG); + return getTreatmentsWithConfigInternal(key, null, featureFlagNames, null, attributes, MethodEnum.TREATMENTS_WITH_CONFIG); } @Override public Map getTreatmentsWithConfig(Key key, List featureFlagNames, Map attributes) { - return getTreatmentsWithConfigInternal(key.matchingKey(), key.bucketingKey(), featureFlagNames, attributes, + return getTreatmentsWithConfigInternal(key.matchingKey(), key.bucketingKey(), featureFlagNames, null, attributes, MethodEnum.TREATMENTS_WITH_CONFIG); } @Override public Map getTreatmentsByFlagSet(String key, String flagSet, Map attributes) { - return getTreatmentsWithSetsAndWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)), + return getTreatmentsWithConfigInternal(key, null, null, new ArrayList<>(Arrays.asList(flagSet)), attributes, MethodEnum.TREATMENTS_BY_FLAG_SET).entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment())); } @Override public Map getTreatmentsByFlagSets(String key, List flagSets, Map attributes) { - return getTreatmentsWithSetsAndWithConfigInternal(key, null, flagSets, + return getTreatmentsWithConfigInternal(key, null, null, flagSets, attributes, MethodEnum.TREATMENTS_BY_FLAG_SETS).entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment())); } @Override public Map getTreatmentsWithConfigByFlagSet(String key, String flagSet, Map attributes) { - return getTreatmentsWithSetsAndWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)), + return getTreatmentsWithConfigInternal(key, null, null, new ArrayList<>(Arrays.asList(flagSet)), attributes, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SET); } @Override public Map getTreatmentsWithConfigByFlagSets(String key, List flagSets, Map attributes) { - return getTreatmentsWithSetsAndWithConfigInternal(key, null, flagSets, + return getTreatmentsWithConfigInternal(key, null, null, flagSets, attributes, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SETS); } @@ -313,9 +313,27 @@ private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bu } private Map getTreatmentsWithConfigInternal(String matchingKey, String bucketingKey, List featureFlagNames, - Map attributes, MethodEnum methodEnum) { + List sets, Map attributes, MethodEnum methodEnum) { + long initTime = System.currentTimeMillis(); - if (featureFlagNames == null) { + FlagSetsValidResult flagSetsValidResult = null; + if (methodEnum == MethodEnum.TREATMENTS_BY_FLAG_SET || methodEnum == MethodEnum.TREATMENTS_BY_FLAG_SETS || + methodEnum == MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SET || methodEnum == MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SETS) { + if (sets == null || sets.isEmpty()) { + _log.warn(String.format("%s: sets must be a non-empty array", methodEnum.getMethod())); + return new HashMap<>(); + } + flagSetsValidResult = FlagSetsValidator.areValid(sets); + if (!flagSetsValidResult.getValid()) { + _log.warn("The sets are invalid"); + return new HashMap<>(); + } + if (filterSetsAreInConfig(flagSetsValidResult.getFlagSets()).isEmpty()) { + _log.warn("The sets are not in flagSetsFilter config"); + return new HashMap<>(); + } + featureFlagNames = getAllFlags(flagSetsValidResult.getFlagSets()); + } else if (featureFlagNames == null) { _log.error(String.format("%s: featureFlagNames must be a non-empty array", methodEnum.getMethod())); return new HashMap<>(); } @@ -325,82 +343,24 @@ private Map getTreatmentsWithConfigInternal(String matching _log.error("Client has already been destroyed - no calls possible"); return createMapControl(featureFlagNames); } - if (!KeyValidator.isValid(matchingKey, "matchingKey", _config.maxStringLength(), methodEnum.getMethod())) { return createMapControl(featureFlagNames); } - if (!KeyValidator.bucketingKeyIsValid(bucketingKey, _config.maxStringLength(), methodEnum.getMethod())) { return createMapControl(featureFlagNames); } else if (featureFlagNames.isEmpty()) { _log.error(String.format("%s: featureFlagNames must be a non-empty array", methodEnum.getMethod())); return new HashMap<>(); } - featureFlagNames = SplitNameValidator.areValid(featureFlagNames, methodEnum.getMethod()); - Map evaluatorResult = _evaluator.evaluateFeatures(matchingKey, - bucketingKey, featureFlagNames, attributes); - List impressions = new ArrayList<>(); - Map result = new HashMap<>(); - evaluatorResult.keySet().forEach(t -> { - if (evaluatorResult.get(t).treatment.equals(Treatments.CONTROL) && evaluatorResult.get(t).label. - equals(Labels.DEFINITION_NOT_FOUND) && _gates.isSDKReady()) { - _log.warn(String.format("%s: you passed \"%s\" that does not exist in this environment please double check " + - "what feature flags exist in the Split user interface.", methodEnum.getMethod(), t)); - result.put(t, SPLIT_RESULT_CONTROL); - } else { - result.put(t, new SplitResult(evaluatorResult.get(t).treatment, evaluatorResult.get(t).configurations)); - impressions.add(new Impression(matchingKey, bucketingKey, t, evaluatorResult.get(t).treatment, System.currentTimeMillis(), - evaluatorResult.get(t).label, evaluatorResult.get(t).changeNumber, attributes)); - } - }); - - _telemetryEvaluationProducer.recordLatency(methodEnum, System.currentTimeMillis() - initTime); - //Track of impressions - if (impressions.size() > 0) { - _impressionManager.track(impressions); + Map evaluatorResult; + if (flagSetsValidResult != null) { + evaluatorResult = _evaluator.evaluateFeaturesByFlagSets(matchingKey, bucketingKey, new ArrayList<>(flagSetsValidResult. + getFlagSets())); + } else { + featureFlagNames = SplitNameValidator.areValid(featureFlagNames, methodEnum.getMethod()); + evaluatorResult = _evaluator.evaluateFeatures(matchingKey, bucketingKey, featureFlagNames, attributes); } - return result; - } catch (Exception e) { - try { - _telemetryEvaluationProducer.recordException(methodEnum); - _log.error("CatchAll Exception", e); - } catch (Exception e1) { - // ignore - } - return createMapControl(featureFlagNames); - } - } - private Map getTreatmentsWithSetsAndWithConfigInternal(String matchingKey, String bucketingKey, List sets, - Map attributes, MethodEnum methodEnum) { - long initTime = System.currentTimeMillis(); - if (sets == null || sets.isEmpty()) { - _log.warn(String.format("%s: sets must be a non-empty array", methodEnum.getMethod())); - return new HashMap<>(); - } - FlagSetsValidResult flagSetsValidResult = FlagSetsValidator.areValid(sets); - try { - if (!flagSetsValidResult.getValid()) { - _log.warn("The sets are invalid"); - return new HashMap<>(); - } - if (filterSetsAreInConfig(flagSetsValidResult.getFlagSets()).isEmpty()) { - _log.warn("The sets are not in flagSetsFilter config"); - return new HashMap<>(); - } - checkSDKReady(methodEnum); - if (_container.isDestroyed()) { - _log.error("Client has already been destroyed - no calls possible"); - return createMapControl(getAllFlags(flagSetsValidResult.getFlagSets())); - } - if (!KeyValidator.isValid(matchingKey, "matchingKey", _config.maxStringLength(), methodEnum.getMethod())) { - return createMapControl(getAllFlags(flagSetsValidResult.getFlagSets())); - } - if (!KeyValidator.bucketingKeyIsValid(bucketingKey, _config.maxStringLength(), methodEnum.getMethod())) { - return createMapControl(getAllFlags(flagSetsValidResult.getFlagSets())); - } - Map evaluatorResult = _evaluator.evaluateFeaturesByFlagSets(matchingKey, - bucketingKey, new ArrayList<>(flagSetsValidResult.getFlagSets())); List impressions = new ArrayList<>(); Map result = new HashMap<>(); evaluatorResult.keySet().forEach(t -> { @@ -427,7 +387,7 @@ private Map getTreatmentsWithSetsAndWithConfigInternal(Stri } catch (Exception e1) { // ignore } - return createMapControl(getAllFlags(flagSetsValidResult.getFlagSets())); + return createMapControl(featureFlagNames); } }