Skip to content

Commit

Permalink
Default treatment in SplitView (#545)
Browse files Browse the repository at this point in the history
  • Loading branch information
gthea authored Oct 18, 2023
1 parent f00e6b2 commit f3029a6
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ private SplitView toSplitView(ParsedSplit parsedSplit) {
splitView.changeNumber = parsedSplit.changeNumber();
splitView.configs = parsedSplit.configurations();
splitView.sets = new ArrayList<>(parsedSplit.sets() == null ? new HashSet<>() : parsedSplit.sets());
splitView.defaultTreatment = parsedSplit.defaultTreatment();

Set<String> treatments = new HashSet<>();
for (ParsedCondition condition : parsedSplit.parsedConditions()) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/io/split/android/client/api/SplitView.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ public class SplitView {
public Map<String, String> configs;
@NonNull
public List<String> sets = new ArrayList<>();
public String defaultTreatment;
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import io.split.android.client.validators.SplitValidatorImpl;
import io.split.android.client.validators.TreatmentManager;
import io.split.android.client.validators.TreatmentManagerImpl;
import io.split.android.client.validators.ValidationMessageLoggerImpl;
import io.split.android.engine.experiments.SplitParser;
import io.split.android.grammar.Treatments;

Expand Down Expand Up @@ -72,7 +73,7 @@ public LocalhostSplitClient(@NonNull LocalhostSplitFactory container,
new EvaluatorImpl(splitsStorage, splitParser), new KeyValidatorImpl(),
new SplitValidatorImpl(), getImpressionsListener(splitClientConfig),
splitClientConfig.labelsEnabled(), eventsManager, attributesManager, attributesMerger,
telemetryStorageProducer, flagSetsFilter, splitsStorage);
telemetryStorageProducer, flagSetsFilter, splitsStorage, new ValidationMessageLoggerImpl());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.Set;

import io.split.android.client.Evaluator;
import io.split.android.client.EvaluatorImpl;
import io.split.android.client.FlagSetsFilter;
import io.split.android.client.api.Key;
import io.split.android.client.attributes.AttributesManager;
import io.split.android.client.attributes.AttributesMerger;
import io.split.android.client.events.ISplitEventsManager;
import io.split.android.client.events.ListenableEventsManager;
import io.split.android.client.impressions.ImpressionListener;
import io.split.android.client.storage.splits.SplitsStorage;
Expand All @@ -31,6 +28,7 @@ public class TreatmentManagerFactoryImpl implements TreatmentManagerFactory {
private final Evaluator mEvaluator;
private final FlagSetsFilter mFlagSetsFilter;
private final SplitsStorage mSplitsStorage;
private final ValidationMessageLogger mValidationMessageLogger;

public TreatmentManagerFactoryImpl(@NonNull KeyValidator keyValidator,
@NonNull SplitValidator splitValidator,
Expand All @@ -50,6 +48,7 @@ public TreatmentManagerFactoryImpl(@NonNull KeyValidator keyValidator,
mEvaluator = new EvaluatorImpl(splitsStorage, splitParser);
mFlagSetsFilter = flagSetsFilter;
mSplitsStorage = checkNotNull(splitsStorage);
mValidationMessageLogger = new ValidationMessageLoggerImpl();
}

@Override
Expand All @@ -67,7 +66,8 @@ public TreatmentManager getTreatmentManager(Key key, ListenableEventsManager eve
mAttributesMerger,
mTelemetryStorageProducer,
mFlagSetsFilter,
mSplitsStorage
mSplitsStorage,
mValidationMessageLogger
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ public TreatmentManagerImpl(String matchingKey,
@NonNull AttributesMerger attributesMerger,
@NonNull TelemetryStorageProducer telemetryStorageProducer,
@Nullable FlagSetsFilter flagSetsFilter,
@NonNull SplitsStorage splitsStorage) {
@NonNull SplitsStorage splitsStorage,
@NonNull ValidationMessageLogger validationLogger) {
mEvaluator = evaluator;
mKeyValidator = keyValidator;
mSplitValidator = splitValidator;
Expand All @@ -84,7 +85,7 @@ public TreatmentManagerImpl(String matchingKey,
mImpressionListener = impressionListener;
mLabelsEnabled = labelsEnabled;
mEventsManager = eventsManager;
mValidationLogger = new ValidationMessageLoggerImpl();
mValidationLogger = checkNotNull(validationLogger);
mAttributesManager = checkNotNull(attributesManager);
mAttributesMerger = checkNotNull(attributesMerger);
mTelemetryStorageProducer = checkNotNull(telemetryStorageProducer);
Expand Down Expand Up @@ -385,16 +386,16 @@ private Map<String, String> controlTreatmentsForSplits(List<String> splits, Stri
return TreatmentManagerHelper.controlTreatmentsForSplits(splits, mSplitValidator, validationTag, mValidationLogger);
}

private EvaluationResult evaluateIfReady(String splitName,
private EvaluationResult evaluateIfReady(String featureFlagName,
Map<String, Object> attributes, String validationTag) {
if (!mEventsManager.eventAlreadyTriggered(SplitEvent.SDK_READY) &&
!mEventsManager.eventAlreadyTriggered(SplitEvent.SDK_READY_FROM_CACHE)) {
mValidationLogger.w("the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method", validationTag);
mValidationLogger.w("the SDK is not ready, results may be incorrect for feature flag " + featureFlagName + ". Make sure to wait for SDK readiness before using this method", validationTag);
mTelemetryStorageProducer.recordNonReadyUsage();

return new EvaluationResult(Treatments.CONTROL, TreatmentLabels.NOT_READY, null, null);
}
return mEvaluator.getTreatment(mMatchingKey, mBucketingKey, splitName, attributes);
return mEvaluator.getTreatment(mMatchingKey, mBucketingKey, featureFlagName, attributes);
}

private void recordLatency(Method treatment, long startTime) {
Expand Down
28 changes: 28 additions & 0 deletions src/test/java/io/split/android/client/SplitManagerImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -158,6 +159,33 @@ public void flagSets() {
assertEquals(new ArrayList<>(split.sets), splitNames.get(0).sets);
}

@Test
public void defaultTreatmentIsPresent() {
Split split = SplitHelper.createSplit("FeatureName", 123, true,
"some_treatment", Lists.newArrayList(getTestCondition()),
"traffic", 456L, 1, null);
when(mSplitsStorage.get("FeatureName")).thenReturn(split);

SplitView featureFlag = mSplitManager.split("FeatureName");

assertEquals("some_treatment", featureFlag.defaultTreatment);
}

@Test
public void defaultTreatmentIsPresentWhenFetchingMultipleSplits() {
Map<String, Split> splitsMap = new HashMap<>();
Split split = SplitHelper.createSplit("FeatureName", 123, true,
"some_treatment", Lists.newArrayList(getTestCondition()),
"traffic", 456L, 1, null);
splitsMap.put(split.name, split);
when(mSplitsStorage.getAll()).thenReturn(splitsMap);

List<SplitView> splitNames = mSplitManager.splits();

assertEquals(1, splitNames.size());
assertEquals("some_treatment", splitNames.get(0).defaultTreatment);
}

private Condition getTestCondition() {
return SplitHelper.createCondition(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(ConditionsTestUtil.partition("off", 10)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import io.split.android.client.validators.KeyValidator;
import io.split.android.client.validators.SplitValidator;
import io.split.android.client.validators.TreatmentManagerImpl;
import io.split.android.client.validators.ValidationMessageLoggerImpl;

public class TreatmentManagerTelemetryTest {

Expand Down Expand Up @@ -72,7 +73,7 @@ public void setUp() {
attributesMerger,
telemetryStorageProducer,
mFlagSetsFilter,
mSplitsStorage);
mSplitsStorage, new ValidationMessageLoggerImpl());

when(evaluator.getTreatment(anyString(), anyString(), anyString(), anyMap())).thenReturn(new EvaluationResult("test", "label"));
}
Expand Down
37 changes: 32 additions & 5 deletions src/test/java/io/split/android/client/TreatmentManagerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
import io.split.android.client.validators.SplitValidatorImpl;
import io.split.android.client.validators.TreatmentManager;
import io.split.android.client.validators.TreatmentManagerImpl;
import io.split.android.client.validators.ValidationMessageLogger;
import io.split.android.client.validators.ValidationMessageLoggerImpl;
import io.split.android.engine.experiments.SplitParser;
import io.split.android.fake.ImpressionListenerMock;
import io.split.android.fake.SplitEventsManagerStub;
Expand All @@ -57,11 +59,13 @@ public class TreatmentManagerTest {
private FlagSetsFilter mFlagSetsFilter;
TreatmentManagerImpl treatmentManager;
private SplitsStorage mSplitsStorage;
private ValidationMessageLogger mValidationMessageLogger;

@Before
public void loadSplitsFromFile() {
mFlagSetsFilter = new FlagSetsFilterImpl(new HashSet<>());
mSplitsStorage = mock(SplitsStorage.class);
mValidationMessageLogger = mock(ValidationMessageLogger.class);
treatmentManager = initializeTreatmentManager();
if (evaluator == null) {
FileHelper fileHelper = new FileHelper();
Expand Down Expand Up @@ -168,7 +172,7 @@ public void testNonExistingSplits() {
}

@Test
public void testEmtpySplit() {
public void testEmptySplit() {
String matchingKey = "nico_test";
String splitName = "";
List<String> splitList = new ArrayList<>();
Expand Down Expand Up @@ -293,6 +297,24 @@ public void getTreatmentsWithConfigTakesValuesFromAttributesManagerIntoAccount()
verify(attributesManager).getAllAttributes();
}

@Test
public void evaluationWhenNotReadyLogsCorrectMessage() {
ValidationMessageLogger validationMessageLogger = mock(ValidationMessageLogger.class);
SplitValidator splitValidator = mock(SplitValidator.class);
Evaluator evaluatorMock = mock(Evaluator.class);
ListenableEventsManager eventsManager = mock(ListenableEventsManager.class);
when(evaluatorMock.getTreatment(eq("my_key"), eq(null), eq("test_split"), anyMap()))
.thenReturn(new EvaluationResult("test", "test"));
when(splitValidator.validateName(any())).thenReturn(null);
when(splitValidator.splitNotFoundMessage(any())).thenReturn(null);
when(eventsManager.eventAlreadyTriggered(SplitEvent.SDK_READY)).thenReturn(false);
when(eventsManager.eventAlreadyTriggered(SplitEvent.SDK_READY_FROM_CACHE)).thenReturn(false);
createTreatmentManager("my_key", null, validationMessageLogger, splitValidator, evaluatorMock, eventsManager)
.getTreatment("test_split", null, false);

verify(validationMessageLogger).w(eq("the SDK is not ready, results may be incorrect for feature flag test_split. Make sure to wait for SDK readiness before using this method"), any());
}

private void assertControl(List<String> splitList, String treatment, Map<String, String> treatmentList, SplitResult splitResult, Map<String, SplitResult> splitResultList) {
Assert.assertNotNull(treatment);
Assert.assertEquals(Treatments.CONTROL, treatment);
Expand All @@ -318,14 +340,18 @@ private void assertControl(List<String> splitList, String treatment, Map<String,
}

private TreatmentManager createTreatmentManager(String matchingKey, String bucketingKey) {
return createTreatmentManager(matchingKey, bucketingKey, new ValidationMessageLoggerImpl(), new SplitValidatorImpl(), evaluator, eventsManagerStub);
}

private TreatmentManager createTreatmentManager(String matchingKey, String bucketingKey, ValidationMessageLogger validationLogger, SplitValidator splitValidator, Evaluator evaluator, ListenableEventsManager eventsManager) {

SplitClientConfig config = SplitClientConfig.builder().build();
return new TreatmentManagerImpl(
matchingKey, bucketingKey, evaluator,
new KeyValidatorImpl(), new SplitValidatorImpl(),
new ImpressionListenerMock(), config.labelsEnabled(), eventsManagerStub,
new KeyValidatorImpl(), splitValidator,
new ImpressionListenerMock(), config.labelsEnabled(), eventsManager,
mock(AttributesManager.class), mock(AttributesMerger.class),
mock(TelemetryStorageProducer.class), mFlagSetsFilter, mSplitsStorage);
mock(TelemetryStorageProducer.class), mFlagSetsFilter, mSplitsStorage, validationLogger);
}

private TreatmentManagerImpl initializeTreatmentManager() {
Expand Down Expand Up @@ -354,7 +380,8 @@ private TreatmentManagerImpl initializeTreatmentManager(Evaluator evaluator) {
mock(AttributesMerger.class),
telemetryStorageProducer,
mFlagSetsFilter,
mSplitsStorage);
mSplitsStorage,
new ValidationMessageLoggerImpl());
}

private Map<String, Split> splitsMap(List<Split> splits) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import io.split.android.client.validators.KeyValidator;
import io.split.android.client.validators.SplitValidator;
import io.split.android.client.validators.TreatmentManagerImpl;
import io.split.android.client.validators.ValidationMessageLoggerImpl;

public class TreatmentManagerWithFlagSetsTest {

Expand Down Expand Up @@ -153,7 +154,7 @@ private void initializeTreatmentManager() {
mAttributesMerger,
mTelemetryStorageProducer,
mFlagSetsFilter,
mSplitsStorage);
mSplitsStorage, new ValidationMessageLoggerImpl());
}

@Test
Expand Down

0 comments on commit f3029a6

Please sign in to comment.