diff --git a/client/src/main/java/io/split/client/SplitClient.java b/client/src/main/java/io/split/client/SplitClient.java index e997be448..a07718b1f 100644 --- a/client/src/main/java/io/split/client/SplitClient.java +++ b/client/src/main/java/io/split/client/SplitClient.java @@ -256,7 +256,7 @@ public interface SplitClient { Map getTreatmentsWithConfig(String key, List featureFlagNames, Map attributes); /** - * Same as {@link #getTreatments(Key, List, Map)} but it returns for each feature flag the configuration associated to the + * Same as {@link #getTreatments(Key, 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. * * @param key the matching and bucketing keys. MUST NOT be null. @@ -268,6 +268,21 @@ 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. + * @return for each feature flag the evaluated treatment, the default treatment of this feature flag, or 'control'. + */ + Map getTreatmentsByFlagSet(String key, String flagSet); + /** * 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. @@ -300,6 +315,21 @@ public interface SplitClient { */ Map getTreatmentsByFlagSet(Key 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. + * @return for each feature flag the evaluated treatment, the default treatment of this feature flag, or 'control'. + */ + Map getTreatmentsByFlagSets(String key, List flagSets); + /** * 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. @@ -332,6 +362,22 @@ public interface SplitClient { */ Map getTreatmentsByFlagSets(Key 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. + * @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); + /** * 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. @@ -366,6 +412,22 @@ public interface SplitClient { */ Map getTreatmentsWithConfigByFlagSet(Key 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. + * @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); + /** * 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. @@ -444,7 +506,6 @@ public interface SplitClient { * @param key the identifier of the entity * @param trafficType the type of the event * @param eventType the type of the event - * @param value the value of the event * * @return true if the track was successful, false otherwise */ diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java index 5ac3f934c..08e7beaa6 100644 --- a/client/src/main/java/io/split/client/SplitClientImpl.java +++ b/client/src/main/java/io/split/client/SplitClientImpl.java @@ -150,6 +150,13 @@ public Map getTreatmentsWithConfig(Key key, List fe MethodEnum.TREATMENTS_WITH_CONFIG); } + @Override + public Map getTreatmentsByFlagSet(String key, String flagSet) { + return getTreatmentsBySetsWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)), + null, MethodEnum.TREATMENTS_BY_FLAG_SET).entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment())); + } + @Override public Map getTreatmentsByFlagSet(String key, String flagSet, Map attributes) { return getTreatmentsBySetsWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)), @@ -164,6 +171,13 @@ public Map getTreatmentsByFlagSet(Key key, String flagSet, Map e.getValue().treatment())); } + @Override + public Map getTreatmentsByFlagSets(String key, List flagSets) { + return getTreatmentsBySetsWithConfigInternal(key, null, flagSets, + null, 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 getTreatmentsBySetsWithConfigInternal(key, null, flagSets, @@ -178,6 +192,12 @@ public Map getTreatmentsByFlagSets(Key key, List flagSet .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment())); } + @Override + public Map getTreatmentsWithConfigByFlagSet(String key, String flagSet) { + return getTreatmentsBySetsWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)), + null, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SET); + } + @Override public Map getTreatmentsWithConfigByFlagSet(String key, String flagSet, Map attributes) { return getTreatmentsBySetsWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)), @@ -190,6 +210,12 @@ public Map getTreatmentsWithConfigByFlagSet(Key key, String attributes, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SET); } + @Override + public Map getTreatmentsWithConfigByFlagSets(String key, List flagSets) { + return getTreatmentsBySetsWithConfigInternal(key, null, flagSets, + null, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SETS); + } + @Override public Map getTreatmentsWithConfigByFlagSets(String key, List flagSets, Map attributes) { return getTreatmentsBySetsWithConfigInternal(key, null, flagSets, @@ -381,7 +407,8 @@ private Map getTreatmentsBySetsWithConfigInternal(String ma return new HashMap<>(); } Set cleanFlagSets = cleanup(sets); - if (filterSetsAreInConfig(cleanFlagSets, methodEnum).isEmpty()) { + cleanFlagSets = filterSetsAreInConfig(cleanFlagSets, methodEnum); + if (cleanFlagSets.isEmpty()) { return new HashMap<>(); } List featureFlagNames = new ArrayList<>(); @@ -447,8 +474,8 @@ private Map validateBeforeEvaluate(List featureFlag } return null; } - private List filterSetsAreInConfig(Set sets, MethodEnum methodEnum) { - List setsToReturn = new ArrayList<>(); + private Set filterSetsAreInConfig(Set sets, MethodEnum methodEnum) { + Set setsToReturn = new HashSet<>(); for (String set : sets) { if (!_flagSetsFilter.intersect(set)) { _log.warn(String.format("%s: you passed %s which is not part of the configured FlagSetsFilter, " + diff --git a/client/src/main/java/io/split/inputValidation/FlagSetsValidator.java b/client/src/main/java/io/split/inputValidation/FlagSetsValidator.java index 4efccb0b8..6b6df2d88 100644 --- a/client/src/main/java/io/split/inputValidation/FlagSetsValidator.java +++ b/client/src/main/java/io/split/inputValidation/FlagSetsValidator.java @@ -33,7 +33,7 @@ public static Set cleanup(List flagSets) { } if (!Pattern.matches(FLAG_SET_REGEX, flagSet)) { _log.warn(String.format("you passed %s, Flag Set must adhere to the regular expressions %s. This means a Flag Set must be " + - "start with a letter, be in lowercase, alphanumeric and have a max length of 50 characters. %s was discarded.", + "start with a letter or number, be in lowercase, alphanumeric and have a max length of 50 characters. %s was discarded.", flagSet, FLAG_SET_REGEX, flagSet)); continue; } diff --git a/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java b/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java index 7920a6af0..62baaf44b 100644 --- a/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java +++ b/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java @@ -110,9 +110,7 @@ public Map> getNamesByFlagSets(List flagSets) { Map> toReturn = new HashMap<>(); for (String set: flagSets) { HashSet keys = _flagSets.get(set); - if(keys != null){ - toReturn.put(set, keys); - } + toReturn.put(set, keys); } return toReturn; } diff --git a/client/src/test/java/io/split/client/SplitClientImplTest.java b/client/src/test/java/io/split/client/SplitClientImplTest.java index 59d5cc066..4210b9782 100644 --- a/client/src/test/java/io/split/client/SplitClientImplTest.java +++ b/client/src/test/java/io/split/client/SplitClientImplTest.java @@ -1955,7 +1955,7 @@ public void testTreatmentsByFlagSets() { fetchManyResult.put(test2, parsedSplit2); when(splitCacheConsumer.fetchMany(new ArrayList<>(Arrays.asList(test2, test)))).thenReturn(fetchManyResult); - List sets = new ArrayList<>(Arrays.asList("set1", "set3")); + 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))); diff --git a/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java b/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java index 5a42d2915..ada94588f 100644 --- a/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java +++ b/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java @@ -24,6 +24,7 @@ import java.util.stream.Stream; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class InMemoryCacheTest { @@ -229,7 +230,8 @@ public void testGetNamesByFlagSets() { assertTrue(namesByFlagSets.get("set1").contains("splitName_2")); assertFalse(namesByFlagSets.get("set1").contains("splitName_3")); assertFalse(namesByFlagSets.get("set1").contains("splitName_4")); - assertFalse(namesByFlagSets.keySet().contains("set3")); + assertTrue(namesByFlagSets.keySet().contains("set3")); + assertNull(namesByFlagSets.get("set3")); _cache.remove("splitName_2"); namesByFlagSets = _cache.getNamesByFlagSets(new ArrayList<>(Arrays.asList("set1", "set2", "set3"))); 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 7fee29996..0c9173457 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,11 @@ public Map getTreatmentsWithConfig(Key key, List fe return treatments; } + @Override + public Map getTreatmentsByFlagSet(String key, String flagSet) { + return null; + } + @Override public Map getTreatmentsByFlagSet(String key, String flagSet, Map attributes) { return new HashMap<>(); @@ -142,6 +147,11 @@ public Map getTreatmentsByFlagSet(Key key, String flagSet, Map(); } + @Override + public Map getTreatmentsByFlagSets(String key, List flagSets) { + return null; + } + @Override public Map getTreatmentsByFlagSets(String key, List flagSets, Map attributes) { return new HashMap<>(); @@ -152,6 +162,11 @@ public Map getTreatmentsByFlagSets(Key key, List flagSet return new HashMap<>(); } + @Override + public Map getTreatmentsWithConfigByFlagSet(String key, String flagSet) { + return null; + } + @Override public Map getTreatmentsWithConfigByFlagSet(String key, String flagSet, Map attributes) { return new HashMap<>(); @@ -162,6 +177,11 @@ public Map getTreatmentsWithConfigByFlagSet(Key key, String return new HashMap<>(); } + @Override + public Map getTreatmentsWithConfigByFlagSets(String key, List flagSets) { + return null; + } + @Override public Map getTreatmentsWithConfigByFlagSets(String key, List flagSets, Map attributes) { return new HashMap<>();