diff --git a/src/androidTest/java/helper/TestableSplitConfigBuilder.java b/src/androidTest/java/helper/TestableSplitConfigBuilder.java index dadffa336..7a674b0d8 100644 --- a/src/androidTest/java/helper/TestableSplitConfigBuilder.java +++ b/src/androidTest/java/helper/TestableSplitConfigBuilder.java @@ -6,6 +6,7 @@ import io.split.android.client.ServiceEndpoints; import io.split.android.client.SplitClientConfig; import io.split.android.client.SyncConfig; +import io.split.android.client.fallback.FallbackTreatmentsConfiguration; import io.split.android.client.impressions.ImpressionListener; import io.split.android.client.network.CertificatePinningConfiguration; import io.split.android.client.network.DevelopmentSslConfig; @@ -15,7 +16,6 @@ import io.split.android.client.shared.UserConsent; import io.split.android.client.utils.logger.Logger; import io.split.android.client.utils.logger.SplitLogLevel; -import io.split.android.client.fallback.FallbackTreatmentsConfiguration; public class TestableSplitConfigBuilder { diff --git a/src/androidTest/java/tests/integration/fallback/FallbackTreatmentsTest.java b/src/androidTest/java/tests/integration/fallback/FallbackTreatmentsTest.java index 86837b1ec..92abf6439 100644 --- a/src/androidTest/java/tests/integration/fallback/FallbackTreatmentsTest.java +++ b/src/androidTest/java/tests/integration/fallback/FallbackTreatmentsTest.java @@ -29,9 +29,8 @@ import io.split.android.client.api.Key; import io.split.android.client.events.SplitEvent; import io.split.android.client.events.SplitEventTask; -import io.split.android.client.fallback.FallbackConfiguration; -import io.split.android.client.fallback.FallbackTreatment; import io.split.android.client.fallback.FallbackTreatmentsConfiguration; +import io.split.android.client.fallback.FallbackTreatment; import io.split.android.client.impressions.Impression; import io.split.android.client.impressions.ImpressionListener; import io.split.android.client.service.impressions.ImpressionsMode; @@ -239,11 +238,8 @@ public MockResponse dispatch(RecordedRequest request) { Map byFlag = new HashMap<>(); byFlag.put("any_flag", new FallbackTreatment("OFF_FALLBACK")); - FallbackConfiguration byFactory = FallbackConfiguration.builder() - .byFlag(byFlag) - .build(); FallbackTreatmentsConfiguration fbConfig = FallbackTreatmentsConfiguration.builder() - .byFactory(byFactory) + .byFlag(byFlag) .build(); SplitClientConfig config = buildConfig(fbConfig, true, 1); @@ -301,11 +297,8 @@ public MockResponse dispatch(RecordedRequest request) { }; mWebServer.setDispatcher(dispatcher); - FallbackConfiguration byFactory = FallbackConfiguration.builder() - .global(new FallbackTreatment("OFF_FALLBACK")) - .build(); FallbackTreatmentsConfiguration fbConfig = FallbackTreatmentsConfiguration.builder() - .byFactory(byFactory) + .global(new FallbackTreatment("OFF_FALLBACK")) .build(); SplitClientConfig config = buildConfig(fbConfig); @@ -329,13 +322,10 @@ public MockResponse dispatch(RecordedRequest request) { public void case4_FlagOverrideBeatsFactoryDefaultReturnsOnFallbackForOverriddenAndOffFallbackForOthers() throws Exception { Map byFlag = new HashMap<>(); byFlag.put("my_flag", new FallbackTreatment("ON_FALLBACK")); - FallbackConfiguration byFactory = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration fbConfig = FallbackTreatmentsConfiguration.builder() .global(new FallbackTreatment("OFF_FALLBACK")) .byFlag(byFlag) .build(); - FallbackTreatmentsConfiguration fbConfig = FallbackTreatmentsConfiguration.builder() - .byFactory(byFactory) - .build(); SplitClientConfig config = buildConfig(fbConfig); @@ -363,11 +353,8 @@ public void case4_FlagOverrideBeatsFactoryDefaultReturnsOnFallbackForOverriddenA public void case2_factoryWideOverrideReturnsFallbackForUnknownFlagsAndTwoKeys() throws Exception { // endpoints provided by helper in buildConfig - FallbackConfiguration byFactory = FallbackConfiguration.builder() - .global(new FallbackTreatment("FALLBACK_TREATMENT")) - .build(); FallbackTreatmentsConfiguration fbConfig = FallbackTreatmentsConfiguration.builder() - .byFactory(byFactory) + .global(new FallbackTreatment("FALLBACK_TREATMENT")) .build(); SplitClientConfig config = buildConfig(fbConfig); @@ -409,11 +396,8 @@ public void case3_factorySpecificOverrideReturnsFallbackForOneFlagAndControlForO Map byFlag = new HashMap<>(); byFlag.put("non_existent_flag", new FallbackTreatment("FALLBACK_TREATMENT")); - FallbackConfiguration byFactory = FallbackConfiguration.builder() - .byFlag(byFlag) - .build(); FallbackTreatmentsConfiguration fbConfig = FallbackTreatmentsConfiguration.builder() - .byFactory(byFactory) + .byFlag(byFlag) .build(); SplitClientConfig config = SplitClientConfig.builder() @@ -466,13 +450,10 @@ public void case7_fallbackDynamicConfigPropagationTreatmentAndConfigReturned() t Map byFlag = new HashMap<>(); byFlag.put("my_flag", new FallbackTreatment("ON_FALLBACK", "{\"flag\":true}")); - FallbackConfiguration byFactory = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration fbConfig = FallbackTreatmentsConfiguration.builder() .global(new FallbackTreatment("OFF_FALLBACK", "{\"global\":true}")) .byFlag(byFlag) .build(); - FallbackTreatmentsConfiguration fbConfig = FallbackTreatmentsConfiguration.builder() - .byFactory(byFactory) - .build(); SplitClientConfig config = SplitClientConfig.builder() .serviceEndpoints(endpoints) @@ -545,11 +526,8 @@ public MockResponse dispatch(RecordedRequest request) { mWebServer.setDispatcher(dispatcher); // Configure global fallback so unknown flags return a fallback treatment - FallbackConfiguration byFactory = FallbackConfiguration.builder() - .global(new FallbackTreatment("OFF_FALLBACK")) - .build(); FallbackTreatmentsConfiguration fbConfig = FallbackTreatmentsConfiguration.builder() - .byFactory(byFactory) + .global(new FallbackTreatment("OFF_FALLBACK")) .build(); final List capturedImpressions = Collections.synchronizedList(new ArrayList<>()); diff --git a/src/main/java/io/split/android/client/EvaluatorImpl.java b/src/main/java/io/split/android/client/EvaluatorImpl.java index d1fceddf3..7eb3db19d 100644 --- a/src/main/java/io/split/android/client/EvaluatorImpl.java +++ b/src/main/java/io/split/android/client/EvaluatorImpl.java @@ -4,7 +4,7 @@ import io.split.android.client.dtos.ConditionType; import io.split.android.client.exceptions.ChangeNumberExceptionWrapper; -import io.split.android.client.fallback.FallbackConfiguration; +import io.split.android.client.fallback.FallbackTreatmentsConfiguration; import io.split.android.client.fallback.FallbackTreatment; import io.split.android.client.fallback.FallbackTreatmentsCalculator; import io.split.android.client.fallback.FallbackTreatmentsCalculatorImpl; @@ -23,7 +23,7 @@ public class EvaluatorImpl implements Evaluator { private final FallbackTreatmentsCalculator mFallbackCalculator; public EvaluatorImpl(SplitsStorage splitsStorage, SplitParser splitParser) { - this(splitsStorage, splitParser, new FallbackTreatmentsCalculatorImpl(FallbackConfiguration.builder().build())); + this(splitsStorage, splitParser, new FallbackTreatmentsCalculatorImpl(FallbackTreatmentsConfiguration.builder().build())); } public EvaluatorImpl(SplitsStorage splitsStorage, SplitParser splitParser, FallbackTreatmentsCalculator fallbackCalculator) { diff --git a/src/main/java/io/split/android/client/fallback/FallbackConfiguration.java b/src/main/java/io/split/android/client/fallback/FallbackConfiguration.java deleted file mode 100644 index 0ba19fd56..000000000 --- a/src/main/java/io/split/android/client/fallback/FallbackConfiguration.java +++ /dev/null @@ -1,103 +0,0 @@ -package io.split.android.client.fallback; - -import androidx.annotation.Nullable; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -public final class FallbackConfiguration { - - @Nullable - private final FallbackTreatment mGlobal; - private final Map mByFlag; - - private FallbackConfiguration(@Nullable FallbackTreatment global, - @Nullable Map byFlag) { - mGlobal = global; - if (byFlag == null || byFlag.isEmpty()) { - mByFlag = Collections.emptyMap(); - } else { - mByFlag = Collections.unmodifiableMap(new HashMap<>(byFlag)); - } - } - - @Nullable - public FallbackTreatment getGlobal() { - return mGlobal; - } - - public Map getByFlag() { - return mByFlag; - } - - /** - * Creates a new {@link Builder} for {@link FallbackConfiguration}. - * Use this to provide an optional global fallback and flag-specific fallbacks. - */ - public static Builder builder() { - return new Builder(); - } - - public static final class Builder { - @Nullable - private FallbackTreatment mGlobal; - @Nullable - private Map mByFlag; - - private Builder() { - mGlobal = null; - mByFlag = null; - } - - /** - * Sets an optional global fallback treatment to be used when no flag-specific - * fallback exists for a given flag. This value is returned only in place of - * the "control" treatment. - * - * @param global optional global {@link FallbackTreatment} - * @return this builder instance - */ - public Builder global(@Nullable FallbackTreatment global) { - mGlobal = global; - return this; - } - - /** - * Sets optional flag-specific fallback treatments, where keys are flag names. - * These take precedence over the global fallback. - * - * @param byFlag map of flag name to {@link FallbackTreatment}; may be null or empty - * @return this builder instance - */ - public Builder byFlag(@Nullable Map byFlag) { - mByFlag = byFlag; - return this; - } - - /** - * Builds an immutable {@link FallbackConfiguration} snapshot of the - * configured values. - * - * @return a new immutable {@link FallbackConfiguration} - */ - public FallbackConfiguration build() { - return new FallbackConfiguration(mGlobal, mByFlag); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - FallbackConfiguration that = (FallbackConfiguration) o; - return Objects.equals(mGlobal, that.mGlobal) && - Objects.equals(mByFlag, that.mByFlag); - } - - @Override - public int hashCode() { - return Objects.hash(mGlobal, mByFlag); - } -} diff --git a/src/main/java/io/split/android/client/fallback/FallbackTreatmentsCalculatorImpl.java b/src/main/java/io/split/android/client/fallback/FallbackTreatmentsCalculatorImpl.java index a7d30a79c..0eb727a1e 100644 --- a/src/main/java/io/split/android/client/fallback/FallbackTreatmentsCalculatorImpl.java +++ b/src/main/java/io/split/android/client/fallback/FallbackTreatmentsCalculatorImpl.java @@ -1,5 +1,7 @@ package io.split.android.client.fallback; +import static io.split.android.client.utils.Utils.checkNotNull; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -12,10 +14,10 @@ public final class FallbackTreatmentsCalculatorImpl implements FallbackTreatment private static final String LABEL_PREFIX = "fallback - "; @NonNull - private final FallbackConfiguration mConfig; + private final FallbackTreatmentsConfiguration mConfig; - public FallbackTreatmentsCalculatorImpl(@NonNull FallbackConfiguration config) { - mConfig = config; + public FallbackTreatmentsCalculatorImpl(@NonNull FallbackTreatmentsConfiguration config) { + mConfig = checkNotNull(config); } @NonNull diff --git a/src/main/java/io/split/android/client/fallback/FallbackTreatmentsConfiguration.java b/src/main/java/io/split/android/client/fallback/FallbackTreatmentsConfiguration.java index e379184d8..4406d4af1 100644 --- a/src/main/java/io/split/android/client/fallback/FallbackTreatmentsConfiguration.java +++ b/src/main/java/io/split/android/client/fallback/FallbackTreatmentsConfiguration.java @@ -3,49 +3,111 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + public final class FallbackTreatmentsConfiguration { @Nullable - private final FallbackConfiguration mByFactory; + private final FallbackTreatment mGlobal; + private final Map mByFlag; - private FallbackTreatmentsConfiguration(@Nullable FallbackConfiguration byFactory) { - mByFactory = byFactory; + private FallbackTreatmentsConfiguration(@Nullable FallbackTreatment global, + @Nullable Map byFlag) { + mGlobal = global; + if (byFlag == null || byFlag.isEmpty()) { + mByFlag = Collections.emptyMap(); + } else { + mByFlag = Collections.unmodifiableMap(new HashMap<>(byFlag)); + } } @Nullable - public FallbackConfiguration getByFactory() { - return mByFactory; + public FallbackTreatment getGlobal() { + return mGlobal; } + public Map getByFlag() { + return mByFlag; + } + + /** + * Creates a new {@link Builder} for {@link FallbackTreatmentsConfiguration}. + * Use this to provide an optional global fallback and flag-specific fallbacks. + */ public static Builder builder() { return new Builder(); } public static final class Builder { @Nullable - private FallbackConfiguration mByFactory; + private FallbackTreatment mGlobal; + @Nullable + private Map mByFlag; private FallbacksSanitizer mSanitizer; private Builder() { + mGlobal = null; + mByFlag = null; mSanitizer = new FallbacksSanitizerImpl(); } - @VisibleForTesting - Builder sanitizer(FallbacksSanitizer sanitizer) { - mSanitizer = sanitizer; + /** + * Sets an optional global fallback treatment to be used when no flag-specific + * fallback exists for a given flag. This value is returned only in place of + * the "control" treatment. + * + * @param global optional global {@link FallbackTreatment} + * @return this builder instance + */ + public Builder global(@Nullable FallbackTreatment global) { + mGlobal = global; return this; } - public Builder byFactory(@Nullable FallbackConfiguration byFactory) { - mByFactory = byFactory; + /** + * Sets optional flag-specific fallback treatments, where keys are flag names. + * These take precedence over the global fallback. + * + * @param byFlag map of flag name to {@link FallbackTreatment}; may be null or empty + * @return this builder instance + */ + public Builder byFlag(@Nullable Map byFlag) { + mByFlag = byFlag; return this; } + /** + * Builds a {@link FallbackTreatmentsConfiguration} for the configured values. + * + * @return a new immutable {@link FallbackTreatmentsConfiguration} + */ public FallbackTreatmentsConfiguration build() { - FallbackConfiguration sanitized = (mByFactory == null) - ? null - : mSanitizer.sanitize(mByFactory); - return new FallbackTreatmentsConfiguration(sanitized); + FallbackTreatment sanitizedGlobal = mSanitizer.sanitizeGlobal(mGlobal); + Map sanitizedByFlag = mSanitizer.sanitizeByFlag(mByFlag); + return new FallbackTreatmentsConfiguration(sanitizedGlobal, sanitizedByFlag); + } + + @VisibleForTesting + Builder sanitizer(FallbacksSanitizer sanitizer) { + mSanitizer = sanitizer; + return this; } } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FallbackTreatmentsConfiguration that = (FallbackTreatmentsConfiguration) o; + return Objects.equals(mGlobal, that.mGlobal) && + Objects.equals(mByFlag, that.mByFlag); + } + + @Override + public int hashCode() { + return Objects.hash(mGlobal, mByFlag); + } } diff --git a/src/main/java/io/split/android/client/fallback/FallbacksSanitizer.java b/src/main/java/io/split/android/client/fallback/FallbacksSanitizer.java index b52dd49e4..29aaf0307 100644 --- a/src/main/java/io/split/android/client/fallback/FallbacksSanitizer.java +++ b/src/main/java/io/split/android/client/fallback/FallbacksSanitizer.java @@ -1,9 +1,12 @@ package io.split.android.client.fallback; import androidx.annotation.Nullable; +import java.util.Map; interface FallbacksSanitizer { @Nullable - FallbackConfiguration sanitize(@Nullable FallbackConfiguration config); + FallbackTreatment sanitizeGlobal(@Nullable FallbackTreatment global); + + Map sanitizeByFlag(@Nullable Map byFlag); } diff --git a/src/main/java/io/split/android/client/fallback/FallbacksSanitizerImpl.java b/src/main/java/io/split/android/client/fallback/FallbacksSanitizerImpl.java index 7f9a4e226..70e34194d 100644 --- a/src/main/java/io/split/android/client/fallback/FallbacksSanitizerImpl.java +++ b/src/main/java/io/split/android/client/fallback/FallbacksSanitizerImpl.java @@ -19,46 +19,25 @@ class FallbacksSanitizerImpl implements FallbacksSanitizer { private static final String TREATMENT_REGEXP = "^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$"; private static final Pattern TREATMENT_PATTERN = Pattern.compile(TREATMENT_REGEXP); - /** - * Sanitizes the provided fallback configuration by applying validation rules. - * Invalid entries are dropped and warnings are logged. - * - * @param config the configuration to sanitize; may be null - * @return a new sanitized configuration, or null if input was null - */ - @Nullable - public FallbackConfiguration sanitize(@Nullable FallbackConfiguration config) { - if (config == null) { - return null; - } - - // Sanitize global treatment - FallbackTreatment sanitizedGlobal = sanitizeGlobalTreatment(config.getGlobal()); - - // Sanitize by-flag treatments - Map sanitizedByFlag = sanitizeByFlagTreatments(config.getByFlag()); - - return FallbackConfiguration.builder() - .global(sanitizedGlobal) - .byFlag(sanitizedByFlag) - .build(); - } + + @Override @Nullable - private FallbackTreatment sanitizeGlobalTreatment(@Nullable FallbackTreatment global) { + public FallbackTreatment sanitizeGlobal(@Nullable FallbackTreatment global) { if (global == null) { return null; } if (!isValidTreatment(global)) { - Logger.e("Discarded global fallback: Invalid treatment (max " + MAX_TREATMENT_LENGTH + " chars and comply with " + TREATMENT_REGEXP + ")"); + Logger.e("Fallback treatments - Discarded global fallback: Invalid treatment (max " + MAX_TREATMENT_LENGTH + " chars and comply with " + TREATMENT_REGEXP + ")"); return null; } return global; } - private Map sanitizeByFlagTreatments(Map byFlag) { + @Override + public Map sanitizeByFlag(@Nullable Map byFlag) { if (byFlag == null || byFlag.isEmpty()) { return new HashMap<>(); } @@ -70,12 +49,12 @@ private Map sanitizeByFlagTreatments(Map splitsMap(List splits) { diff --git a/src/test/java/io/split/android/client/TreatmentManagerWithFlagSetsTest.java b/src/test/java/io/split/android/client/TreatmentManagerWithFlagSetsTest.java index ff4be2aad..aa12c3d5e 100644 --- a/src/test/java/io/split/android/client/TreatmentManagerWithFlagSetsTest.java +++ b/src/test/java/io/split/android/client/TreatmentManagerWithFlagSetsTest.java @@ -26,7 +26,7 @@ import io.split.android.client.attributes.AttributesMerger; import io.split.android.client.events.ListenableEventsManager; import io.split.android.client.events.SplitEvent; -import io.split.android.client.fallback.FallbackConfiguration; +import io.split.android.client.fallback.FallbackTreatmentsConfiguration; import io.split.android.client.fallback.FallbackTreatmentsCalculatorImpl; import io.split.android.client.impressions.ImpressionListener; import io.split.android.client.storage.splits.SplitsStorage; @@ -158,7 +158,7 @@ private void initializeTreatmentManager() { mTelemetryStorageProducer, mFlagSetsFilter, mSplitsStorage, new ValidationMessageLoggerImpl(), new FlagSetsValidatorImpl(), new PropertyValidatorImpl(), - new FallbackTreatmentsCalculatorImpl(FallbackConfiguration.builder().build())); + new FallbackTreatmentsCalculatorImpl(FallbackTreatmentsConfiguration.builder().build())); } @Test diff --git a/src/test/java/io/split/android/client/fallback/FallbackTreatmentsCalculatorTest.java b/src/test/java/io/split/android/client/fallback/FallbackTreatmentsCalculatorTest.java index 00083a0fa..37c5353c0 100644 --- a/src/test/java/io/split/android/client/fallback/FallbackTreatmentsCalculatorTest.java +++ b/src/test/java/io/split/android/client/fallback/FallbackTreatmentsCalculatorTest.java @@ -20,7 +20,7 @@ public void flagLevelOverrideTakesPrecedence() { FallbackTreatment byFlag = new FallbackTreatment("on", "{\"f\":true}"); Map map = new HashMap<>(); map.put("my_flag", byFlag); - FallbackConfiguration config = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration config = FallbackTreatmentsConfiguration.builder() .global(global) .byFlag(map) .build(); @@ -38,7 +38,7 @@ public void flagLevelOverrideTakesPrecedence() { @Test public void globalFallbackIsReturnedWhenNoFlagOverride() { FallbackTreatment global = new FallbackTreatment("off"); - FallbackConfiguration config = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration config = FallbackTreatmentsConfiguration.builder() .global(global) .byFlag(Collections.emptyMap()) .build(); @@ -55,7 +55,7 @@ public void flagLevelFallbackIsReturnedWhenConfigured() { FallbackTreatment byFlag = new FallbackTreatment("on"); Map map = new HashMap<>(); map.put("flagA", byFlag); - FallbackConfiguration config = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration config = FallbackTreatmentsConfiguration.builder() .byFlag(map) .build(); @@ -68,7 +68,7 @@ public void flagLevelFallbackIsReturnedWhenConfigured() { @Test public void returnsControlWhenNoFallbackConfigured() { - FallbackConfiguration config = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration config = FallbackTreatmentsConfiguration.builder() .build(); FallbackTreatmentsCalculator calculator = new FallbackTreatmentsCalculatorImpl(config); @@ -83,7 +83,7 @@ public void nonexistentFlagFallsBackToGlobal() { FallbackTreatment global = new FallbackTreatment("off"); Map map = new HashMap<>(); map.put("flagA", new FallbackTreatment("on")); - FallbackConfiguration config = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration config = FallbackTreatmentsConfiguration.builder() .global(global) .byFlag(map) .build(); @@ -98,7 +98,7 @@ public void nonexistentFlagFallsBackToGlobal() { @Test public void labelIsPrefixed() { FallbackTreatment global = new FallbackTreatment("off"); - FallbackConfiguration config = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration config = FallbackTreatmentsConfiguration.builder() .global(global) .build(); @@ -112,7 +112,7 @@ public void labelIsPrefixed() { @Test public void noLabelReturnsNull() { FallbackTreatment global = new FallbackTreatment("off"); - FallbackConfiguration config = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration config = FallbackTreatmentsConfiguration.builder() .global(global) .build(); diff --git a/src/test/java/io/split/android/client/fallback/FallbackTreatmentsConfigurationBuilderTest.java b/src/test/java/io/split/android/client/fallback/FallbackTreatmentsConfigurationBuilderTest.java deleted file mode 100644 index 4080395d5..000000000 --- a/src/test/java/io/split/android/client/fallback/FallbackTreatmentsConfigurationBuilderTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.split.android.client.fallback; - -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.Test; -import org.mockito.Mockito; - -import java.util.HashMap; -import java.util.Map; - -public class FallbackTreatmentsConfigurationBuilderTest { - - @Test - public void builderAppliesSanitization() { - FallbacksSanitizer sanitizer = Mockito.mock(FallbacksSanitizer.class); - - Map map = new HashMap<>(); - map.put("valid_flag", new FallbackTreatment("on")); - FallbackConfiguration byFactory = FallbackConfiguration.builder() - .global(new FallbackTreatment("off")) - .byFlag(map) - .build(); - - FallbackConfiguration sanitized = FallbackConfiguration.builder() - .global(null) // assume sanitizer drops invalid global, example - .byFlag(map) - .build(); - - when(sanitizer.sanitize(byFactory)).thenReturn(sanitized); - - FallbackTreatmentsConfiguration cfg = FallbackTreatmentsConfiguration.builder() - .sanitizer(sanitizer) // package-private method - .byFactory(byFactory) - .build(); - - assertSame(sanitized, cfg.getByFactory()); - verify(sanitizer, times(1)).sanitize(byFactory); - } - - @Test - public void nullByFactoryAllowed_andSanitizerNotInvoked() { - FallbacksSanitizer sanitizer = Mockito.mock(FallbacksSanitizer.class); - - FallbackTreatmentsConfiguration cfg = FallbackTreatmentsConfiguration.builder() - .sanitizer(sanitizer) // package-private method - .byFactory(null) - .build(); - - assertNull(cfg.getByFactory()); - verify(sanitizer, never()).sanitize(any()); - } -} diff --git a/src/test/java/io/split/android/client/fallback/FallbackConfigurationTest.java b/src/test/java/io/split/android/client/fallback/FallbackTreatmentsConfigurationTest.java similarity index 76% rename from src/test/java/io/split/android/client/fallback/FallbackConfigurationTest.java rename to src/test/java/io/split/android/client/fallback/FallbackTreatmentsConfigurationTest.java index ae786c583..f9d2c11a7 100644 --- a/src/test/java/io/split/android/client/fallback/FallbackConfigurationTest.java +++ b/src/test/java/io/split/android/client/fallback/FallbackTreatmentsConfigurationTest.java @@ -9,7 +9,7 @@ import java.util.HashMap; import java.util.Map; -public class FallbackConfigurationTest { +public class FallbackTreatmentsConfigurationTest { @Test public void constructorSetsFields() { @@ -17,7 +17,7 @@ public void constructorSetsFields() { Map map = new HashMap<>(); map.put("flagA", new FallbackTreatment("off")); - FallbackConfiguration cfg = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration cfg = FallbackTreatmentsConfiguration.builder() .global(global) .byFlag(map) .build(); @@ -33,7 +33,7 @@ public void byFlagIsUnmodifiable() { Map byFlag = new HashMap<>(); byFlag.put("flagA", new FallbackTreatment("off")); - FallbackConfiguration config = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration config = FallbackTreatmentsConfiguration.builder() .global(global) .byFlag(byFlag) .build(); @@ -60,9 +60,9 @@ public void equalityAndHashCodeByValue() { Map b = new HashMap<>(); b.put("flagA", new FallbackTreatment("off")); - FallbackConfiguration configOne = FallbackConfiguration.builder().global(global).byFlag(a).build(); - FallbackConfiguration configTwo = FallbackConfiguration.builder().global(global).byFlag(b).build(); - FallbackConfiguration configThree = FallbackConfiguration.builder().global(null).byFlag(b).build(); + FallbackTreatmentsConfiguration configOne = FallbackTreatmentsConfiguration.builder().global(global).byFlag(a).build(); + FallbackTreatmentsConfiguration configTwo = FallbackTreatmentsConfiguration.builder().global(global).byFlag(b).build(); + FallbackTreatmentsConfiguration configThree = FallbackTreatmentsConfiguration.builder().global(null).byFlag(b).build(); assertEquals(configOne, configTwo); assertEquals(configOne.hashCode(), configTwo.hashCode()); diff --git a/src/test/java/io/split/android/client/fallback/FallbacksSanitizerImplTest.java b/src/test/java/io/split/android/client/fallback/FallbacksSanitizerImplTest.java index cbb0898c5..638dab54e 100644 --- a/src/test/java/io/split/android/client/fallback/FallbacksSanitizerImplTest.java +++ b/src/test/java/io/split/android/client/fallback/FallbacksSanitizerImplTest.java @@ -45,13 +45,13 @@ public void dropsInvalidFlagNamesAndTreatments() { byFlag.put(LONG_101, new FallbackTreatment("off")); byFlag.put("tooLongTreatment", new FallbackTreatment(LONG_101)); - FallbackConfiguration config = FallbackConfiguration.builder() - .global(new FallbackTreatment("on")) - .byFlag(byFlag) + FallbackTreatment sanitizedGlobal = mSanitizer.sanitizeGlobal(new FallbackTreatment("on")); + Map sanitizedByFlag = mSanitizer.sanitizeByFlag(byFlag); + FallbackTreatmentsConfiguration sanitized = FallbackTreatmentsConfiguration.builder() + .global(sanitizedGlobal) + .byFlag(sanitizedByFlag) .build(); - FallbackConfiguration sanitized = mSanitizer.sanitize(config); - Deque errors = mLogPrinter.getLoggedMessages().get(android.util.Log.ERROR); assertTrue("Expected ERROR logs to be present", errors != null && !errors.isEmpty()); long invalidFlagNameCount = errors.stream().filter(m -> m.contains("Invalid flag name")).count(); @@ -67,13 +67,13 @@ public void dropsInvalidFlagNamesAndTreatments() { @Test public void dropsInvalidGlobalTreatment() { - FallbackConfiguration config = FallbackConfiguration.builder() - .global(new FallbackTreatment(LONG_101)) // invalid treatment length - .byFlag(null) + FallbackTreatment sanitizedGlobal = mSanitizer.sanitizeGlobal(new FallbackTreatment(LONG_101)); // invalid treatment length + Map sanitizedByFlag = mSanitizer.sanitizeByFlag(null); + FallbackTreatmentsConfiguration sanitized = FallbackTreatmentsConfiguration.builder() + .global(sanitizedGlobal) + .byFlag(sanitizedByFlag) .build(); - FallbackConfiguration sanitized = mSanitizer.sanitize(config); - // Assert error log for discarded global fallback only Deque errors = mLogPrinter.getLoggedMessages().get(android.util.Log.ERROR); assertTrue("Expected ERROR logs to be present", errors != null && !errors.isEmpty()); @@ -90,13 +90,13 @@ public void byFlagTreatmentIsDroppedWhenInvalidFormat() { byFlag.put("valid_num_dot", new FallbackTreatment("123.on")); byFlag.put("null_treatment", new FallbackTreatment(null)); - FallbackConfiguration config = FallbackConfiguration.builder() - .global(null) - .byFlag(byFlag) + FallbackTreatment sanitizedGlobal = mSanitizer.sanitizeGlobal(null); + Map sanitizedByFlag = mSanitizer.sanitizeByFlag(byFlag); + FallbackTreatmentsConfiguration sanitized = FallbackTreatmentsConfiguration.builder() + .global(sanitizedGlobal) + .byFlag(sanitizedByFlag) .build(); - FallbackConfiguration sanitized = mSanitizer.sanitize(config); - // Assert error logs for invalid treatments under flags Deque errors = mLogPrinter.getLoggedMessages().get(android.util.Log.ERROR); assertTrue("Expected ERROR logs to be present", errors != null && !errors.isEmpty()); @@ -117,14 +117,14 @@ public void globalTreatmentIsDroppedWhenInvalidFormat() { byFlag.put(VALID_FLAG, new FallbackTreatment("on_1-2")); byFlag.put("null_treatment", new FallbackTreatment(null)); - FallbackConfiguration config = FallbackConfiguration.builder() - // Global invalid due to regex (letters cannot be followed by '.') - .global(new FallbackTreatment("on.off")) - .byFlag(byFlag) + // Global invalid due to regex (letters cannot be followed by '.') + FallbackTreatment sanitizedGlobal = mSanitizer.sanitizeGlobal(new FallbackTreatment("on.off")); + Map sanitizedByFlag = mSanitizer.sanitizeByFlag(byFlag); + FallbackTreatmentsConfiguration sanitized = FallbackTreatmentsConfiguration.builder() + .global(sanitizedGlobal) + .byFlag(sanitizedByFlag) .build(); - FallbackConfiguration sanitized = mSanitizer.sanitize(config); - // Assert error logs were emitted for invalid entries Deque errorLogs = mLogPrinter.getLoggedMessages().get(android.util.Log.ERROR); assertTrue("Expected ERROR logs to be present", errorLogs != null && !errorLogs.isEmpty()); @@ -153,13 +153,13 @@ public void validFormatTreatmentIsNotDropped() { byFlag.put("numWithDot", new FallbackTreatment("123.on")); byFlag.put(VALID_FLAG, new FallbackTreatment("on_1-2")); - FallbackConfiguration config = FallbackConfiguration.builder() - .global(new FallbackTreatment("on")) - .byFlag(byFlag) + FallbackTreatment sanitizedGlobal = mSanitizer.sanitizeGlobal(new FallbackTreatment("on")); + Map sanitizedByFlag = mSanitizer.sanitizeByFlag(byFlag); + FallbackTreatmentsConfiguration sanitized = FallbackTreatmentsConfiguration.builder() + .global(sanitizedGlobal) + .byFlag(sanitizedByFlag) .build(); - FallbackConfiguration sanitized = mSanitizer.sanitize(config); - assertEquals(2, sanitized.getByFlag().size()); assertTrue(sanitized.getByFlag().containsKey("numWithDot")); assertEquals("123.on", sanitized.getByFlag().get("numWithDot").getTreatment()); diff --git a/src/test/java/io/split/android/client/validators/TreatmentManagerFallbackTreatmentsTest.java b/src/test/java/io/split/android/client/validators/TreatmentManagerFallbackTreatmentsTest.java index 646c7fc0f..1e7990603 100644 --- a/src/test/java/io/split/android/client/validators/TreatmentManagerFallbackTreatmentsTest.java +++ b/src/test/java/io/split/android/client/validators/TreatmentManagerFallbackTreatmentsTest.java @@ -25,7 +25,7 @@ import io.split.android.client.attributes.AttributesManager; import io.split.android.client.attributes.AttributesMerger; import io.split.android.client.dtos.Split; -import io.split.android.client.fallback.FallbackConfiguration; +import io.split.android.client.fallback.FallbackTreatmentsConfiguration; import io.split.android.client.fallback.FallbackTreatment; import io.split.android.client.fallback.FallbackTreatmentsCalculator; import io.split.android.client.fallback.FallbackTreatmentsCalculatorImpl; @@ -46,7 +46,7 @@ public class TreatmentManagerFallbackTreatmentsTest { @Test public void evaluatorDefinitionNotFoundUsesFallback() { - FallbackConfiguration cfg = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration cfg = FallbackTreatmentsConfiguration.builder() .global(new FallbackTreatment("FALLBACK_TREATMENT", "{\"k\":1}")) .build(); FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(cfg); @@ -67,7 +67,7 @@ public void evaluatorDefinitionNotFoundUsesFallback() { @Test public void evaluatorExceptionUsesFallback() { - FallbackConfiguration cfg = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration cfg = FallbackTreatmentsConfiguration.builder() .global(new FallbackTreatment("FALLBACK_TREATMENT_2")) .build(); FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(cfg); @@ -88,7 +88,7 @@ public void evaluatorExceptionUsesFallback() { @Test public void helperControlTreatmentsPathUsesFallback() { - FallbackConfiguration cfg = FallbackConfiguration.builder() + FallbackTreatmentsConfiguration cfg = FallbackTreatmentsConfiguration.builder() .global(new FallbackTreatment("FALLBACK_HELPER", "cfg")) .build(); FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(cfg); diff --git a/src/test/java/io/split/android/client/validators/TreatmentManagerHelperTest.java b/src/test/java/io/split/android/client/validators/TreatmentManagerHelperTest.java index a1ed47e27..16c938caf 100644 --- a/src/test/java/io/split/android/client/validators/TreatmentManagerHelperTest.java +++ b/src/test/java/io/split/android/client/validators/TreatmentManagerHelperTest.java @@ -12,7 +12,7 @@ import java.util.Map; import io.split.android.client.SplitResult; -import io.split.android.client.fallback.FallbackConfiguration; +import io.split.android.client.fallback.FallbackTreatmentsConfiguration; import io.split.android.client.fallback.FallbackTreatment; import io.split.android.client.fallback.FallbackTreatmentsCalculator; import io.split.android.client.fallback.FallbackTreatmentsCalculatorImpl; @@ -26,7 +26,7 @@ public void controlTreatmentsForSplitsValidatesSplitsWhenValidatorAndLoggerAreNo when(validator.validateName("split2")).thenReturn(new ValidationErrorInfo(ValidationErrorInfo.ERROR_SOME, "message")); - FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(FallbackConfiguration.builder() + FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(FallbackTreatmentsConfiguration.builder() .global(new FallbackTreatment("control")) .build()); @@ -44,7 +44,7 @@ public void controlTreatmentsForSplitsWithConfigValidatesSplitsWhenValidatorAndL when(validator.validateName("split2")).thenReturn(new ValidationErrorInfo(ValidationErrorInfo.ERROR_SOME, "message")); - FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(FallbackConfiguration.builder() + FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(FallbackTreatmentsConfiguration.builder() .global(new FallbackTreatment("control")) .build()); @@ -62,7 +62,7 @@ public void controlTreatmentsForSplitsWithConfigOnlyAddsValueForValidSplits() { when(validator.validateName("split2")).thenReturn(new ValidationErrorInfo(ValidationErrorInfo.ERROR_SOME, "message")); - FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(FallbackConfiguration.builder() + FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(FallbackTreatmentsConfiguration.builder() .global(new FallbackTreatment("control")) .build()); @@ -83,7 +83,7 @@ public void controlTreatmentsForSplitsOnlyAddsValuesForValidSplits() { when(validator.validateName("split2")).thenReturn(new ValidationErrorInfo(ValidationErrorInfo.ERROR_SOME, "message")); - FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(FallbackConfiguration.builder() + FallbackTreatmentsCalculator calc = new FallbackTreatmentsCalculatorImpl(FallbackTreatmentsConfiguration.builder() .global(new FallbackTreatment("control")) .build()); diff --git a/src/test/java/io/split/android/engine/splitter/SplitterTest.java b/src/test/java/io/split/android/engine/splitter/SplitterTest.java index c408f3f7b..32826214b 100644 --- a/src/test/java/io/split/android/engine/splitter/SplitterTest.java +++ b/src/test/java/io/split/android/engine/splitter/SplitterTest.java @@ -17,7 +17,7 @@ import java.util.List; import io.split.android.client.dtos.Partition; -import io.split.android.client.fallback.FallbackConfiguration; +import io.split.android.client.fallback.FallbackTreatmentsConfiguration; import io.split.android.client.fallback.FallbackTreatment; import io.split.android.client.fallback.FallbackTreatmentsCalculator; import io.split.android.client.fallback.FallbackTreatmentsCalculatorImpl; @@ -41,7 +41,7 @@ public void works() { for (int i = 0; i < n; i++) { String key = RandomStringUtils.random(20); - String treatment = Splitter.getTreatment(key, 123, partitions, 1, new FallbackTreatmentsCalculatorImpl(FallbackConfiguration.builder().build())); + String treatment = Splitter.getTreatment(key, 123, partitions, 1, new FallbackTreatmentsCalculatorImpl(FallbackTreatmentsConfiguration.builder().build())); treatments[Integer.parseInt(treatment) - 1]++; } @@ -62,7 +62,7 @@ public void ifHundredPercentOneTreatmentWeShortcut() { List partitions = Collections.singletonList(partition); - assertThat(Splitter.getTreatment("13", 15, partitions, 1, new FallbackTreatmentsCalculatorImpl(FallbackConfiguration.builder().build())), is(equalTo("on"))); + assertThat(Splitter.getTreatment("13", 15, partitions, 1, new FallbackTreatmentsCalculatorImpl(FallbackTreatmentsConfiguration.builder().build())), is(equalTo("on"))); } @Test