From 78070d13119f9484cdbca1c9ea503febcae8c5b2 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Thu, 7 Sep 2023 18:40:11 -0300 Subject: [PATCH 01/16] Refactor internal filter tracking to use a Map --- .../split/android/client/FilterBuilder.java | 28 +++++++-------- .../split/android/client/FilterGrouper.java | 12 +++++-- .../android/client/SplitFactoryHelper.java | 28 +++++---------- .../android/client/SplitFactoryImpl.java | 10 +++--- .../localhost/LocalhostSplitFactory.java | 10 ++++-- .../executor/SplitTaskFactoryImpl.java | 13 ++++--- .../service/splits/SplitChangeProcessor.java | 6 ++-- .../synchronizer/WorkManagerWrapper.java | 4 +-- .../android/client/FilterGrouperTest.java | 36 ++++++++++++------- .../splits/SplitChangeProcessorTest.java | 5 +-- 10 files changed, 84 insertions(+), 68 deletions(-) diff --git a/src/main/java/io/split/android/client/FilterBuilder.java b/src/main/java/io/split/android/client/FilterBuilder.java index 335fcb841..88d1cd5c2 100644 --- a/src/main/java/io/split/android/client/FilterBuilder.java +++ b/src/main/java/io/split/android/client/FilterBuilder.java @@ -6,14 +6,14 @@ import androidx.annotation.Nullable; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.SortedSet; +import java.util.TreeMap; import java.util.TreeSet; import io.split.android.client.utils.logger.Logger; -import io.split.android.client.utils.StringHelper; public class FilterBuilder { @@ -30,18 +30,15 @@ public FilterBuilder(List filters) { } public String buildQueryString() { - - if (mFilters.size() == 0) { + if (mFilters.isEmpty()) { return ""; } - StringHelper stringHelper = new StringHelper(); StringBuilder queryString = new StringBuilder(); - List sortedFilters = getGroupedFilter(); - Collections.sort(sortedFilters, new SplitFilterComparator()); + Map sortedFilters = getGroupedFilter(); - for (SplitFilter splitFilter : sortedFilters) { + for (SplitFilter splitFilter : sortedFilters.values()) { SplitFilter.Type filterType = splitFilter.getType(); SortedSet deduptedValues = new TreeSet<>(splitFilter.getValues()); if (deduptedValues.size() < splitFilter.getValues().size()) { @@ -56,15 +53,18 @@ public String buildQueryString() { queryString.append("&"); queryString.append(filterType.queryStringField()); queryString.append("="); - queryString.append(stringHelper.join(",", deduptedValues)); + queryString.append(String.join(",", deduptedValues)); } return queryString.toString(); } @NonNull - public List getGroupedFilter() { - return new ArrayList<>(mFilterGrouper.group(mFilters)); + public Map getGroupedFilter() { + TreeMap sortedFilters = new TreeMap<>(new SplitFilterTypeComparator()); + sortedFilters.putAll(mFilterGrouper.group(mFilters)); + + return sortedFilters; } private void addFilters(List filters) { @@ -103,10 +103,10 @@ private void validateFilterSize(SplitFilter.Type type, int size) { } } - private static class SplitFilterComparator implements Comparator { + private static class SplitFilterTypeComparator implements Comparator { @Override - public int compare(SplitFilter o1, SplitFilter o2) { - return o1.getType().compareTo(o2.getType()); + public int compare(SplitFilter.Type o1, SplitFilter.Type o2) { + return o1.compareTo(o2); } } } diff --git a/src/main/java/io/split/android/client/FilterGrouper.java b/src/main/java/io/split/android/client/FilterGrouper.java index 6e5e39fbb..7b9f52746 100644 --- a/src/main/java/io/split/android/client/FilterGrouper.java +++ b/src/main/java/io/split/android/client/FilterGrouper.java @@ -7,7 +7,12 @@ class FilterGrouper { - List group(List filters) { + /** + * Groups filters by type + * @param filters list of filters to group + * @return map of grouped filters. The key is the filter type, the value is the filter + */ + Map group(List filters) { Map> groupedValues = new HashMap<>(); for (SplitFilter filter : filters) { List groupValues = groupedValues.get(filter.getType()); @@ -18,12 +23,13 @@ List group(List filters) { groupValues.addAll(filter.getValues()); } - List groupedFilters = new ArrayList<>(); + Map groupedFilters = new HashMap<>(); for (Map.Entry> filterEntry : groupedValues.entrySet()) { if (filterEntry.getValue().size() > 0) { - groupedFilters.add(new SplitFilter(filterEntry.getKey(), filterEntry.getValue())); + groupedFilters.put(filterEntry.getKey(), new SplitFilter(filterEntry.getKey(), filterEntry.getValue())); } } + return groupedFilters; } } diff --git a/src/main/java/io/split/android/client/SplitFactoryHelper.java b/src/main/java/io/split/android/client/SplitFactoryHelper.java index 83cb7a841..6541a05e7 100644 --- a/src/main/java/io/split/android/client/SplitFactoryHelper.java +++ b/src/main/java/io/split/android/client/SplitFactoryHelper.java @@ -10,11 +10,8 @@ import java.io.File; import java.net.URI; import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; +import java.util.HashMap; import java.util.Map; -import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingDeque; @@ -189,9 +186,12 @@ SplitApiFacade buildApiFacade(SplitClientConfig splitClientConfig, } WorkManagerWrapper buildWorkManagerWrapper(Context context, SplitClientConfig splitClientConfig, - String apiKey, String databaseName, List filters) { + String apiKey, String databaseName, Map filters) { + SplitFilter filter = filters.get(SplitFilter.Type.BY_SET) != null ? + filters.get(SplitFilter.Type.BY_SET) : + filters.get(SplitFilter.Type.BY_NAME); return new WorkManagerWrapper( - WorkManager.getInstance(context), splitClientConfig, apiKey, databaseName, filters); + WorkManager.getInstance(context), splitClientConfig, apiKey, databaseName, filter); } @@ -414,27 +414,17 @@ SplitUpdatesWorker getSplitUpdatesWorker(SplitClientConfig config, return null; } - Pair, String>, Set> getFilterConfiguration(SyncConfig syncConfig) { + Pair, String> getFilterConfiguration(SyncConfig syncConfig) { String splitsFilterQueryString = null; - List groupedFilters = new ArrayList<>(); - Set configuredFlagSets = new HashSet<>(); + Map groupedFilters = new HashMap<>(); if (syncConfig != null) { FilterBuilder filterBuilder = new FilterBuilder(syncConfig.getFilters()); groupedFilters = filterBuilder.getGroupedFilter(); splitsFilterQueryString = filterBuilder.buildQueryString(); - - if (!groupedFilters.isEmpty()) { - SplitFilter splitFilter = groupedFilters.get(0); - - // In the case of BY_SET, all filters will be grouped into one with the {@link SplitFilter.Type#BY_SET} type - if (splitFilter != null && splitFilter.getType() == SplitFilter.Type.BY_SET) { - configuredFlagSets.addAll(splitFilter.getValues()); - } - } } - return new Pair<>(new Pair<>(groupedFilters, splitsFilterQueryString), configuredFlagSets); + return new Pair<>(groupedFilters, splitsFilterQueryString); } private TelemetryStorage getTelemetryStorage(boolean shouldRecordTelemetry, TelemetryStorage telemetryStorage) { diff --git a/src/main/java/io/split/android/client/SplitFactoryImpl.java b/src/main/java/io/split/android/client/SplitFactoryImpl.java index af1cecedc..a6b3421c7 100644 --- a/src/main/java/io/split/android/client/SplitFactoryImpl.java +++ b/src/main/java/io/split/android/client/SplitFactoryImpl.java @@ -7,7 +7,9 @@ import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import io.split.android.client.api.Key; @@ -171,10 +173,10 @@ public void taskExecuted(@NonNull SplitTaskExecutionInfo taskInfo) { mStorageContainer = factoryHelper.buildStorageContainer(config.userConsent(), splitDatabase, config.shouldRecordTelemetry(), splitCipher, telemetryStorage); - Pair, String>, Set> filtersConfig = factoryHelper.getFilterConfiguration(config.syncConfig()); - List filters = filtersConfig.first.first; - String splitsFilterQueryStringFromConfig = filtersConfig.first.second; - Set configuredFlagSets = filtersConfig.second; + Pair, String> filtersConfig = factoryHelper.getFilterConfiguration(config.syncConfig()); + Map filters = filtersConfig.first; + String splitsFilterQueryStringFromConfig = filtersConfig.second; + Set configuredFlagSets = (filters.get(SplitFilter.Type.BY_SET) != null) ? new HashSet<>(filters.get(SplitFilter.Type.BY_SET).getValues()) : new HashSet<>(); SplitApiFacade splitApiFacade = factoryHelper.buildApiFacade( config, defaultHttpClient, splitsFilterQueryStringFromConfig); diff --git a/src/main/java/io/split/android/client/localhost/LocalhostSplitFactory.java b/src/main/java/io/split/android/client/localhost/LocalhostSplitFactory.java index de3efad14..1f79f0e8d 100644 --- a/src/main/java/io/split/android/client/localhost/LocalhostSplitFactory.java +++ b/src/main/java/io/split/android/client/localhost/LocalhostSplitFactory.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import io.split.android.client.FilterBuilder; @@ -76,11 +77,14 @@ public LocalhostSplitFactory(String key, Context context, Set configuredSets = new HashSet<>(); if (config.syncConfig() != null) { - List groupedFilters = new FilterBuilder(config.syncConfig().getFilters()) + Map groupedFilters = new FilterBuilder(config.syncConfig().getFilters()) .getGroupedFilter(); - if (!groupedFilters.isEmpty() && groupedFilters.get(0) != null && groupedFilters.get(0).getType() == SplitFilter.Type.BY_SET) { - configuredSets.addAll(groupedFilters.get(0).getValues()); + if (!groupedFilters.isEmpty()) { + SplitFilter bySetFilter = groupedFilters.get(SplitFilter.Type.BY_SET); + if (bySetFilter != null) { + configuredSets.addAll(bySetFilter.getValues()); + } } } diff --git a/src/main/java/io/split/android/client/service/executor/SplitTaskFactoryImpl.java b/src/main/java/io/split/android/client/service/executor/SplitTaskFactoryImpl.java index e828a1cdb..8df128d86 100644 --- a/src/main/java/io/split/android/client/service/executor/SplitTaskFactoryImpl.java +++ b/src/main/java/io/split/android/client/service/executor/SplitTaskFactoryImpl.java @@ -66,7 +66,7 @@ public SplitTaskFactoryImpl(@NonNull SplitClientConfig splitClientConfig, @NonNull SplitStorageContainer splitStorageContainer, @Nullable String splitsFilterQueryString, ISplitEventsManager eventsManager, - @Nullable List filters, + @Nullable Map filters, @Nullable TestingConfig testingConfig) { mSplitClientConfig = checkNotNull(splitClientConfig); @@ -91,13 +91,16 @@ public SplitTaskFactoryImpl(@NonNull SplitClientConfig splitClientConfig, mTelemetryRuntimeProducer); } - mFilters = (filters == null) ? new ArrayList<>() : filters; + mFilters = (filters == null) ? new ArrayList<>() : new ArrayList<>(filters.values()); int flagSetCount = 0; int invalidFlagSetCount = 0; - if (!mFilters.isEmpty() && mFilters.get(0) != null && mFilters.get(0).getType() == SplitFilter.Type.BY_SET) { - flagSetCount = mFilters.get(0).getValues().size(); - invalidFlagSetCount = mFilters.get(0).getInvalidValueCount(); + if (filters != null && !filters.isEmpty()) { + SplitFilter bySetFilter = filters.get(SplitFilter.Type.BY_SET); + if (bySetFilter != null) { + flagSetCount = bySetFilter.getValues().size(); + invalidFlagSetCount = bySetFilter.getInvalidValueCount(); + } } mTelemetryTaskFactory = new TelemetryTaskFactoryImpl(mSplitApiFacade.getTelemetryConfigRecorder(), diff --git a/src/main/java/io/split/android/client/service/splits/SplitChangeProcessor.java b/src/main/java/io/split/android/client/service/splits/SplitChangeProcessor.java index 47ea3541f..a24848d42 100644 --- a/src/main/java/io/split/android/client/service/splits/SplitChangeProcessor.java +++ b/src/main/java/io/split/android/client/service/splits/SplitChangeProcessor.java @@ -7,11 +7,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import io.split.android.client.SplitFilter; import io.split.android.client.dtos.Split; import io.split.android.client.dtos.SplitChange; -import io.split.android.client.dtos.Status; import io.split.android.client.storage.splits.ProcessedSplitChange; public class SplitChangeProcessor { @@ -25,12 +25,12 @@ public class SplitChangeProcessor { this((SplitFilter) null); } - public SplitChangeProcessor(@Nullable List filters) { + public SplitChangeProcessor(@Nullable Map filters) { // We're only supporting one filter type if (filters == null || filters.isEmpty()) { mSplitFilter = null; } else { - mSplitFilter = filters.get(0); + mSplitFilter = filters.values().iterator().next(); } mStatusProcessStrategy = new StatusProcessStrategy(); diff --git a/src/main/java/io/split/android/client/service/synchronizer/WorkManagerWrapper.java b/src/main/java/io/split/android/client/service/synchronizer/WorkManagerWrapper.java index b2beb4b08..8a255706e 100644 --- a/src/main/java/io/split/android/client/service/synchronizer/WorkManagerWrapper.java +++ b/src/main/java/io/split/android/client/service/synchronizer/WorkManagerWrapper.java @@ -53,14 +53,14 @@ public WorkManagerWrapper(@NonNull WorkManager workManager, @NonNull SplitClientConfig splitClientConfig, @NonNull String apiKey, @NonNull String databaseName, - @Nullable List filters) { + @Nullable SplitFilter filter) { mWorkManager = checkNotNull(workManager); mDatabaseName = checkNotNull(databaseName); mSplitClientConfig = checkNotNull(splitClientConfig); mApiKey = checkNotNull(apiKey); mShouldLoadFromLocal = new HashSet<>(); mConstraints = buildConstraints(); - mFilter = (filters != null && filters.size() == 1) ? filters.get(0) : null; + mFilter = filter; } public void setFetcherExecutionListener(SplitTaskExecutionListener fetcherExecutionListener) { diff --git a/src/test/java/io/split/android/client/FilterGrouperTest.java b/src/test/java/io/split/android/client/FilterGrouperTest.java index c5b5e6868..e3a7fbcec 100644 --- a/src/test/java/io/split/android/client/FilterGrouperTest.java +++ b/src/test/java/io/split/android/client/FilterGrouperTest.java @@ -1,11 +1,16 @@ package io.split.android.client; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import org.junit.Assert; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; public class FilterGrouperTest { @@ -13,18 +18,23 @@ public class FilterGrouperTest { @Test public void groupingFilters() { - List ungropedFilters = new ArrayList<>(); - ungropedFilters.add(SplitFilter.byName(Arrays.asList("f1", "f2", "f3"))); - ungropedFilters.add(SplitFilter.byName(Arrays.asList("f2", "f3", "f4"))); - ungropedFilters.add(SplitFilter.byName(Arrays.asList("f4", "f5", "f6"))); - ungropedFilters.add(SplitFilter.byPrefix(Arrays.asList("f1", "f2", "f3"))); - ungropedFilters.add(SplitFilter.byPrefix(Arrays.asList("f2", "f3", "f4"))); - ungropedFilters.add(SplitFilter.byPrefix(Arrays.asList("f4", "f5", "f6"))); - - List groupedFiltes = mFilterGrouper.group(ungropedFilters); - - /// This compoe - Assert.assertEquals(2, groupedFiltes.size()); + List ungroupedFilters = new ArrayList<>(); + ungroupedFilters.add(SplitFilter.byName(Arrays.asList("f1", "f2", "f3"))); + ungroupedFilters.add(SplitFilter.byName(Arrays.asList("f2", "f3", "f4"))); + ungroupedFilters.add(SplitFilter.byName(Arrays.asList("f4", "f5", "f6"))); + ungroupedFilters.add(SplitFilter.byPrefix(Arrays.asList("f1", "f2", "f3"))); + ungroupedFilters.add(SplitFilter.byPrefix(Arrays.asList("f2", "f3", "f4"))); + ungroupedFilters.add(SplitFilter.byPrefix(Arrays.asList("f4", "f5", "f6"))); + ungroupedFilters.add(SplitFilter.bySet(Arrays.asList("f1", "f2", "f3"))); + ungroupedFilters.add(SplitFilter.bySet(Arrays.asList("f2", "f3", "f4"))); + ungroupedFilters.add(SplitFilter.bySet(Arrays.asList("f4", "f5", "f6"))); + + Map groupedFilters = mFilterGrouper.group(ungroupedFilters); + + // this class only merges filters of the same type + assertEquals(3, groupedFilters.size()); + assertTrue(groupedFilters.containsKey(SplitFilter.Type.BY_NAME)); + assertTrue(groupedFilters.containsKey(SplitFilter.Type.BY_PREFIX)); + assertTrue(groupedFilters.containsKey(SplitFilter.Type.BY_SET)); } - } diff --git a/src/test/java/io/split/android/client/service/splits/SplitChangeProcessorTest.java b/src/test/java/io/split/android/client/service/splits/SplitChangeProcessorTest.java index 8821cbf5a..d270ec649 100644 --- a/src/test/java/io/split/android/client/service/splits/SplitChangeProcessorTest.java +++ b/src/test/java/io/split/android/client/service/splits/SplitChangeProcessorTest.java @@ -11,6 +11,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import io.split.android.client.SplitFilter; @@ -206,8 +207,8 @@ public void featureFlagsAreFilteredByNameWhenThereIsSplitFilterByName() { @Test public void creatingWithNullFilterProcessesEverything() { - List filterList = null; - mProcessor = new SplitChangeProcessor(filterList); + Map filterMap = null; + mProcessor = new SplitChangeProcessor(filterMap); Split split1 = newSplit("split_1", Status.ACTIVE); Split split2 = newSplit("split_2", Status.ARCHIVED); From a0359e8641698404b82c9e1a15bb50166f46c15b Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Thu, 7 Sep 2023 18:47:37 -0300 Subject: [PATCH 02/16] Fix test --- .../client/service/synchronizer/WorkManagerWrapperTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/io/split/android/client/service/synchronizer/WorkManagerWrapperTest.java b/src/test/java/io/split/android/client/service/synchronizer/WorkManagerWrapperTest.java index a79498fa4..edfbd899e 100644 --- a/src/test/java/io/split/android/client/service/synchronizer/WorkManagerWrapperTest.java +++ b/src/test/java/io/split/android/client/service/synchronizer/WorkManagerWrapperTest.java @@ -73,7 +73,7 @@ public void setUp() throws Exception { splitClientConfig, "api_key", "test_database_name", - Collections.singletonList(SplitFilter.bySet(Arrays.asList("set_1", "set_2"))) + SplitFilter.bySet(Arrays.asList("set_1", "set_2")) ); } From 1b7004c20ad46da622f7c4f81c5bc3b9edbb2e0a Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Fri, 8 Sep 2023 10:24:00 -0300 Subject: [PATCH 03/16] Cleanup --- .../android/client/SplitFactoryHelper.java | 14 ++++++ .../android/client/SplitFactoryImpl.java | 3 +- .../executor/SplitTaskFactoryImpl.java | 44 +++++++++++-------- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/main/java/io/split/android/client/SplitFactoryHelper.java b/src/main/java/io/split/android/client/SplitFactoryHelper.java index 6541a05e7..399a8740a 100644 --- a/src/main/java/io/split/android/client/SplitFactoryHelper.java +++ b/src/main/java/io/split/android/client/SplitFactoryHelper.java @@ -11,7 +11,9 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingDeque; @@ -427,6 +429,18 @@ Pair, String> getFilterConfiguration(SyncConf return new Pair<>(groupedFilters, splitsFilterQueryString); } + @NonNull + Set getConfiguredFlagSets(Map filters) { + Set configuredFlagSets; + SplitFilter flagSetSplitFilter = filters.get(SplitFilter.Type.BY_SET); + if (flagSetSplitFilter != null) { + configuredFlagSets = new HashSet<>(flagSetSplitFilter.getValues()); + } else { + configuredFlagSets = new HashSet<>(); + } + return configuredFlagSets; + } + private TelemetryStorage getTelemetryStorage(boolean shouldRecordTelemetry, TelemetryStorage telemetryStorage) { if (telemetryStorage != null) { return telemetryStorage; diff --git a/src/main/java/io/split/android/client/SplitFactoryImpl.java b/src/main/java/io/split/android/client/SplitFactoryImpl.java index a6b3421c7..c387d9d55 100644 --- a/src/main/java/io/split/android/client/SplitFactoryImpl.java +++ b/src/main/java/io/split/android/client/SplitFactoryImpl.java @@ -176,7 +176,6 @@ public void taskExecuted(@NonNull SplitTaskExecutionInfo taskInfo) { Pair, String> filtersConfig = factoryHelper.getFilterConfiguration(config.syncConfig()); Map filters = filtersConfig.first; String splitsFilterQueryStringFromConfig = filtersConfig.second; - Set configuredFlagSets = (filters.get(SplitFilter.Type.BY_SET) != null) ? new HashSet<>(filters.get(SplitFilter.Type.BY_SET).getValues()) : new HashSet<>(); SplitApiFacade splitApiFacade = factoryHelper.buildApiFacade( config, defaultHttpClient, splitsFilterQueryStringFromConfig); @@ -271,7 +270,7 @@ public void taskExecuted(@NonNull SplitTaskExecutionInfo taskInfo) { telemetrySynchronizer, mStorageContainer, splitTaskExecutor, splitApiFacade, validationLogger, keyValidator, customerImpressionListener, streamingComponents.getPushNotificationManager(), componentsRegister, workManagerWrapper, - eventsTracker, configuredFlagSets); + eventsTracker, factoryHelper.getConfiguredFlagSets(filters)); mDestroyer = new Runnable() { public void run() { Logger.w("Shutdown called for split"); diff --git a/src/main/java/io/split/android/client/service/executor/SplitTaskFactoryImpl.java b/src/main/java/io/split/android/client/service/executor/SplitTaskFactoryImpl.java index 8df128d86..e91cd8c3a 100644 --- a/src/main/java/io/split/android/client/service/executor/SplitTaskFactoryImpl.java +++ b/src/main/java/io/split/android/client/service/executor/SplitTaskFactoryImpl.java @@ -92,25 +92,7 @@ public SplitTaskFactoryImpl(@NonNull SplitClientConfig splitClientConfig, } mFilters = (filters == null) ? new ArrayList<>() : new ArrayList<>(filters.values()); - - int flagSetCount = 0; - int invalidFlagSetCount = 0; - if (filters != null && !filters.isEmpty()) { - SplitFilter bySetFilter = filters.get(SplitFilter.Type.BY_SET); - if (bySetFilter != null) { - flagSetCount = bySetFilter.getValues().size(); - invalidFlagSetCount = bySetFilter.getInvalidValueCount(); - } - } - - mTelemetryTaskFactory = new TelemetryTaskFactoryImpl(mSplitApiFacade.getTelemetryConfigRecorder(), - mSplitApiFacade.getTelemetryStatsRecorder(), - telemetryStorage, - splitClientConfig, - mSplitsStorageContainer.getSplitsStorage(), - mSplitsStorageContainer.getMySegmentsStorageContainer(), - flagSetCount, - invalidFlagSetCount); + mTelemetryTaskFactory = initializeTelemetryTaskFactory(splitClientConfig, filters, telemetryStorage); } @Override @@ -212,4 +194,28 @@ public TelemetryStatsRecorderTask getTelemetryStatsRecorderTask() { public SplitInPlaceUpdateTask createSplitsUpdateTask(Split featureFlag, long since) { return new SplitInPlaceUpdateTask(mSplitsStorageContainer.getSplitsStorage(), mSplitChangeProcessor, mEventsManager, mTelemetryRuntimeProducer, featureFlag, since); } + + @NonNull + private TelemetryTaskFactory initializeTelemetryTaskFactory(@NonNull SplitClientConfig splitClientConfig, @Nullable Map filters, TelemetryStorage telemetryStorage) { + final TelemetryTaskFactory mTelemetryTaskFactory; + int flagSetCount = 0; + int invalidFlagSetCount = 0; + if (filters != null && !filters.isEmpty()) { + SplitFilter bySetFilter = filters.get(SplitFilter.Type.BY_SET); + if (bySetFilter != null) { + flagSetCount = bySetFilter.getValues().size(); + invalidFlagSetCount = bySetFilter.getInvalidValueCount(); + } + } + + mTelemetryTaskFactory = new TelemetryTaskFactoryImpl(mSplitApiFacade.getTelemetryConfigRecorder(), + mSplitApiFacade.getTelemetryStatsRecorder(), + telemetryStorage, + splitClientConfig, + mSplitsStorageContainer.getSplitsStorage(), + mSplitsStorageContainer.getMySegmentsStorageContainer(), + flagSetCount, + invalidFlagSetCount); + return mTelemetryTaskFactory; + } } From 77a894a7ee96794b98931688a08f93f7195e73c7 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Fri, 8 Sep 2023 18:06:16 -0300 Subject: [PATCH 04/16] WIP tests --- .../assets/split_changes_flag_set-0.json | 108 +++++++++ .../assets/split_changes_flag_set-1.json | 108 +++++++++ .../assets/split_changes_flag_set-2.json | 210 +++++++++++++++++ .../integration/sets/FlagSetsPollingTest.java | 223 ++++++++++++++++++ 4 files changed, 649 insertions(+) create mode 100644 src/androidTest/assets/split_changes_flag_set-0.json create mode 100644 src/androidTest/assets/split_changes_flag_set-1.json create mode 100644 src/androidTest/assets/split_changes_flag_set-2.json create mode 100644 src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java diff --git a/src/androidTest/assets/split_changes_flag_set-0.json b/src/androidTest/assets/split_changes_flag_set-0.json new file mode 100644 index 000000000..b3c0556d1 --- /dev/null +++ b/src/androidTest/assets/split_changes_flag_set-0.json @@ -0,0 +1,108 @@ +{ + "splits": [ + { + "trafficTypeName": "client", + "name": "workm", + "trafficAllocation": 100, + "trafficAllocationSeed": 147392224, + "seed": 524417105, + "status": "ACTIVE", + "killed": false, + "defaultTreatment": "on", + "changeNumber": 1602798638344, + "algo": 2, + "configurations": {}, + "sets": ["set_3"], + "conditions": [ + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "client", + "attribute": null + }, + "matcherType": "IN_SEGMENT", + "negate": false, + "userDefinedSegmentMatcherData": { + "segmentName": "new_segment" + }, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 0 + }, + { + "treatment": "off", + "size": 0 + }, + { + "treatment": "free", + "size": 100 + }, + { + "treatment": "conta", + "size": 0 + } + ], + "label": "in segment new_segment" + }, + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "client", + "attribute": null + }, + "matcherType": "ALL_KEYS", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 100 + }, + { + "treatment": "off", + "size": 0 + }, + { + "treatment": "free", + "size": 0 + }, + { + "treatment": "conta", + "size": 0 + } + ], + "label": "default rule" + } + ] + } + ], + "since": 1602797638344, + "till": 1602798638344 +} diff --git a/src/androidTest/assets/split_changes_flag_set-1.json b/src/androidTest/assets/split_changes_flag_set-1.json new file mode 100644 index 000000000..6ed91ced6 --- /dev/null +++ b/src/androidTest/assets/split_changes_flag_set-1.json @@ -0,0 +1,108 @@ +{ + "splits": [ + { + "trafficTypeName": "client", + "name": "workm", + "trafficAllocation": 100, + "trafficAllocationSeed": 147392224, + "seed": 524417105, + "status": "ACTIVE", + "killed": false, + "defaultTreatment": "on", + "changeNumber": 1602797638344, + "algo": 2, + "configurations": {}, + "sets": ["set_1"], + "conditions": [ + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "client", + "attribute": null + }, + "matcherType": "IN_SEGMENT", + "negate": false, + "userDefinedSegmentMatcherData": { + "segmentName": "new_segment" + }, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 0 + }, + { + "treatment": "off", + "size": 0 + }, + { + "treatment": "free", + "size": 100 + }, + { + "treatment": "conta", + "size": 0 + } + ], + "label": "in segment new_segment" + }, + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "client", + "attribute": null + }, + "matcherType": "ALL_KEYS", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 100 + }, + { + "treatment": "off", + "size": 0 + }, + { + "treatment": "free", + "size": 0 + }, + { + "treatment": "conta", + "size": 0 + } + ], + "label": "default rule" + } + ] + } + ], + "since": 1602796638344, + "till": 1602797638344 +} diff --git a/src/androidTest/assets/split_changes_flag_set-2.json b/src/androidTest/assets/split_changes_flag_set-2.json new file mode 100644 index 000000000..2d28b7582 --- /dev/null +++ b/src/androidTest/assets/split_changes_flag_set-2.json @@ -0,0 +1,210 @@ +{ + "splits": [ + { + "trafficTypeName": "client", + "name": "workm", + "trafficAllocation": 100, + "trafficAllocationSeed": 147392224, + "seed": 524417105, + "status": "ACTIVE", + "killed": false, + "defaultTreatment": "on", + "changeNumber": 1602796638344, + "algo": 2, + "configurations": {}, + "sets": ["set_1", "set_2"], + "conditions": [ + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "client", + "attribute": null + }, + "matcherType": "IN_SEGMENT", + "negate": false, + "userDefinedSegmentMatcherData": { + "segmentName": "new_segment" + }, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 0 + }, + { + "treatment": "off", + "size": 0 + }, + { + "treatment": "free", + "size": 100 + }, + { + "treatment": "conta", + "size": 0 + } + ], + "label": "in segment new_segment" + }, + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "client", + "attribute": null + }, + "matcherType": "ALL_KEYS", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 100 + }, + { + "treatment": "off", + "size": 0 + }, + { + "treatment": "free", + "size": 0 + }, + { + "treatment": "conta", + "size": 0 + } + ], + "label": "default rule" + } + ] + }, + { + "trafficTypeName": "client", + "name": "workm_set_3", + "trafficAllocation": 100, + "trafficAllocationSeed": 147392224, + "seed": 524417105, + "status": "ACTIVE", + "killed": false, + "defaultTreatment": "on", + "changeNumber": 1602796638344, + "algo": 2, + "configurations": {}, + "sets": ["set_3"], + "conditions": [ + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "client", + "attribute": null + }, + "matcherType": "IN_SEGMENT", + "negate": false, + "userDefinedSegmentMatcherData": { + "segmentName": "new_segment" + }, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 0 + }, + { + "treatment": "off", + "size": 0 + }, + { + "treatment": "free", + "size": 100 + }, + { + "treatment": "conta", + "size": 0 + } + ], + "label": "in segment new_segment" + }, + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "client", + "attribute": null + }, + "matcherType": "ALL_KEYS", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 100 + }, + { + "treatment": "off", + "size": 0 + }, + { + "treatment": "free", + "size": 0 + }, + { + "treatment": "conta", + "size": 0 + } + ], + "label": "default rule" + } + ] + } + ], + "since": -1, + "till": 1602796638344 +} diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java new file mode 100644 index 000000000..126032207 --- /dev/null +++ b/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java @@ -0,0 +1,223 @@ +package tests.integration.sets; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; + +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import fake.HttpClientMock; +import fake.HttpResponseMock; +import fake.HttpResponseMockDispatcher; +import helper.DatabaseHelper; +import helper.FileHelper; +import helper.IntegrationHelper; +import helper.TestableSplitConfigBuilder; +import io.split.android.client.SplitClient; +import io.split.android.client.SplitClientConfig; +import io.split.android.client.SplitFactory; +import io.split.android.client.SplitFilter; +import io.split.android.client.SyncConfig; +import io.split.android.client.dtos.SplitChange; +import io.split.android.client.events.SplitEvent; +import io.split.android.client.events.SplitEventTask; +import io.split.android.client.storage.db.SplitEntity; +import io.split.android.client.storage.db.SplitRoomDatabase; +import io.split.android.client.utils.Json; +import io.split.android.client.utils.logger.Logger; + +public class FlagSetsPollingTest { + + private final FileHelper fileHelper = new FileHelper(); + private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); + private CountDownLatch hitsLatch; + private CountDownLatch firstChangeLatch; + private CountDownLatch secondChangeLatch; + private CountDownLatch thirdChangeLatch; + private SplitRoomDatabase mRoomDb; + + @Before + public void setUp() throws Exception { + mRoomDb = DatabaseHelper.getTestDatabase(mContext); + mRoomDb.clearAllTables(); + + hitsLatch = new CountDownLatch(3); + firstChangeLatch = new CountDownLatch(1); + secondChangeLatch = new CountDownLatch(1); + thirdChangeLatch = new CountDownLatch(1); + } + + @Test + public void featureFlagIsUpdatedAccordingToSetsWhenTheyAreConfigured() throws IOException, InterruptedException { + /* + This test creates a factory with 2 configured sets. + + The first split change will have 2 splits, one that belongs to set_1 and set_2 and one that belongs to set_3; + -> it should be added to storage + + The second change will have 1 split that belongs to set_1 only. + -> it should remain in storage and be updated + + The third change will have 1 split that belongs to set_3 only. + -> it should be removed from storage + */ + + createFactory(mContext, mRoomDb, false, "set_1", "set_2"); + + boolean awaitFirst = firstChangeLatch.await(5, TimeUnit.SECONDS); + Thread.sleep(200); + int firstSize = mRoomDb.splitDao().getAll().size(); + boolean firstSetsCorrect = mRoomDb.splitDao().getAll().get(0).getBody().contains("[\"set_1\",\"set_2\"]"); + + boolean awaitSecond = secondChangeLatch.await(5, TimeUnit.SECONDS); + Thread.sleep(200); + int secondSize = mRoomDb.splitDao().getAll().size(); + boolean secondSetsCorrect = mRoomDb.splitDao().getAll().get(0).getBody().contains("[\"set_1\"]"); + + boolean awaitThird = thirdChangeLatch.await(5, TimeUnit.SECONDS); + Thread.sleep(200); + int thirdSize = mRoomDb.splitDao().getAll().size(); + + boolean awaitHits = hitsLatch.await(120, TimeUnit.SECONDS); + + assertEquals(1, firstSize); + assertEquals(1, secondSize); + assertEquals(0, thirdSize); + assertTrue(awaitFirst); + assertTrue(awaitSecond); + assertTrue(awaitThird); + assertTrue(firstSetsCorrect); + assertTrue(secondSetsCorrect); + + assertTrue(awaitHits); + } + + @Test + public void featureFlagSetsAreIgnoredWhenSetsAreNotConfigured() throws IOException, InterruptedException { + /* + This test creates a factory with no sets configured. + + The first split change will have 2 splits, one that belongs to set_1 and set_2 and one that belongs to set_3; + -> both should be added to storage. + + The second change will have 1 split that belongs to set_1 only. + -> that split should be updated. + + The third change will have 1 split that belongs to set_3 only. + -> that split should be updated. + */ + + createFactory(mContext, mRoomDb, false); + + boolean awaitFirst = firstChangeLatch.await(5, TimeUnit.SECONDS); + Thread.sleep(800); + int firstSize = mRoomDb.splitDao().getAll().size(); + List firstEntities = mRoomDb.splitDao().getAll(); + boolean firstSetsCorrect = firstEntities.get(0).getBody().contains("[\"set_1\",\"set_2\"]") && + firstEntities.get(1).getBody().contains("[\"set_3\"]"); + + boolean awaitSecond = secondChangeLatch.await(5, TimeUnit.SECONDS); + Thread.sleep(1000); + int secondSize = mRoomDb.splitDao().getAll().size(); + List secondEntities = mRoomDb.splitDao().getAll(); + String body0 = secondEntities.get(0).getBody(); + String body1 = secondEntities.get(1).getBody(); + boolean secondSetsCorrect = body1.contains("[\"set_1\"]") && + body1.contains("\"name\":\"workm\",") && + body0.contains("\"name\":\"workm_set_3\",") && + body0.contains("[\"set_3\"]"); + + Logger.w("body0: " + body0); + Logger.w("body1: " + body1); + + boolean awaitThird = thirdChangeLatch.await(5, TimeUnit.SECONDS); + Thread.sleep(800); + List thirdEntities = mRoomDb.splitDao().getAll(); + int thirdSize = thirdEntities.size(); + boolean thirdSetsCorrect = thirdEntities.get(0).getBody().contains("[\"set_3\"]"); + + boolean awaitHits = hitsLatch.await(120, TimeUnit.SECONDS); + + assertEquals(2, firstSize); + assertEquals(2, secondSize); + assertEquals(2, thirdSize); + assertTrue(awaitFirst); + assertTrue(awaitSecond); + assertTrue(awaitThird); + assertTrue(firstSetsCorrect); + assertTrue(secondSetsCorrect); + assertTrue(thirdSetsCorrect); + + assertTrue(awaitHits); + } + + private SplitFactory createFactory( + Context mContext, + SplitRoomDatabase splitRoomDatabase, + boolean streamingEnabled, + String... sets) throws IOException { + SplitClientConfig config = new TestableSplitConfigBuilder() + .ready(30000) + .trafficType("client") + .enableDebug() + .impressionsRefreshRate(1000) + .impressionsCountersRefreshRate(1000) + .syncConfig(SyncConfig.builder() + .addSplitFilter(SplitFilter.bySet(Arrays.asList(sets))) + .build()) + .featuresRefreshRate(2) + .streamingEnabled(streamingEnabled) + .eventFlushInterval(1000) + .build(); + + Map responses = new HashMap<>(); + responses.put("splitChanges", (uri, httpMethod, body) -> { + String since = uri.getQuery().split("&")[0].split("=")[1]; + + hitsLatch.countDown(); + if (since.equals("-1")) { + firstChangeLatch.countDown(); + return new HttpResponseMock(200, loadSplitChangeWithSet(2)); + } else if (since.equals("1602796638344")) { + secondChangeLatch.countDown(); + return new HttpResponseMock(200, loadSplitChangeWithSet(1)); + } else { + thirdChangeLatch.countDown(); + return new HttpResponseMock(200, loadSplitChangeWithSet(0)); + } + }); + + responses.put("mySegments/CUSTOMER_ID", (uri, httpMethod, body) -> new HttpResponseMock(200, IntegrationHelper.emptyMySegments())); + + HttpResponseMockDispatcher httpResponseMockDispatcher = IntegrationHelper.buildDispatcher(responses); + + return IntegrationHelper.buildFactory( + IntegrationHelper.dummyApiKey(), + IntegrationHelper.dummyUserKey(), + config, + mContext, + new HttpClientMock(httpResponseMockDispatcher), + splitRoomDatabase, null, null, null); + } + + private String loadSplitChangeWithSet(int setsCount) { + String change = fileHelper.loadFileContent(mContext, "split_changes_flag_set-" + setsCount + ".json"); + SplitChange parsedChange = Json.fromJson(change, SplitChange.class); + parsedChange.since = parsedChange.till; + + return Json.toJson(parsedChange); + } +} From ec40928ee22e0327f796654a254266749794f2e7 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Mon, 11 Sep 2023 12:17:23 -0300 Subject: [PATCH 05/16] Streaming test setup --- .../java/helper/IntegrationHelper.java | 4 + .../integration/sets/FlagSetsPollingTest.java | 29 ++- .../sets/FlagSetsStreamingTest.java | 196 ++++++++++++++++++ 3 files changed, 218 insertions(+), 11 deletions(-) create mode 100644 src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java diff --git a/src/androidTest/java/helper/IntegrationHelper.java b/src/androidTest/java/helper/IntegrationHelper.java index 243b46dbe..031c70c24 100644 --- a/src/androidTest/java/helper/IntegrationHelper.java +++ b/src/androidTest/java/helper/IntegrationHelper.java @@ -322,6 +322,10 @@ public interface ResponseClosure { HttpResponseMock onResponse(URI uri, HttpMethod httpMethod, String body); + + static String getSinceFromUri(URI uri) { + return uri.getQuery().split("&")[0].split("=")[1]; + } } /** diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java index 126032207..dfc0a8b98 100644 --- a/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java +++ b/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java @@ -3,6 +3,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static helper.IntegrationHelper.ResponseClosure.getSinceFromUri; + import android.content.Context; import androidx.test.platform.app.InstrumentationRegistry; @@ -65,13 +67,13 @@ public void featureFlagIsUpdatedAccordingToSetsWhenTheyAreConfigured() throws IO /* This test creates a factory with 2 configured sets. - The first split change will have 2 splits, one that belongs to set_1 and set_2 and one that belongs to set_3; + The first split change will have 2 splits (workm and workm_set_3), one that belongs to set_1 and set_2 and one that belongs to set_3; -> it should be added to storage - The second change will have 1 split that belongs to set_1 only. + The second change will have 1 split (workm) that belongs to set_1 only. -> it should remain in storage and be updated - The third change will have 1 split that belongs to set_3 only. + The third change will have 1 split (workm) that belongs to set_3 only. -> it should be removed from storage */ @@ -110,27 +112,27 @@ public void featureFlagSetsAreIgnoredWhenSetsAreNotConfigured() throws IOExcepti /* This test creates a factory with no sets configured. - The first split change will have 2 splits, one that belongs to set_1 and set_2 and one that belongs to set_3; + The first split change will have 2 splits (workm and workm_set_3), one that belongs to set_1 and set_2 and one that belongs to set_3; -> both should be added to storage. - The second change will have 1 split that belongs to set_1 only. + The second change will have 1 split (workm) that belongs to set_1 only. -> that split should be updated. - The third change will have 1 split that belongs to set_3 only. + The third change will have 1 split (workm) that belongs to set_3 only. -> that split should be updated. */ createFactory(mContext, mRoomDb, false); boolean awaitFirst = firstChangeLatch.await(5, TimeUnit.SECONDS); - Thread.sleep(800); + Thread.sleep(500); int firstSize = mRoomDb.splitDao().getAll().size(); List firstEntities = mRoomDb.splitDao().getAll(); boolean firstSetsCorrect = firstEntities.get(0).getBody().contains("[\"set_1\",\"set_2\"]") && firstEntities.get(1).getBody().contains("[\"set_3\"]"); boolean awaitSecond = secondChangeLatch.await(5, TimeUnit.SECONDS); - Thread.sleep(1000); + Thread.sleep(500); int secondSize = mRoomDb.splitDao().getAll().size(); List secondEntities = mRoomDb.splitDao().getAll(); String body0 = secondEntities.get(0).getBody(); @@ -144,10 +146,15 @@ public void featureFlagSetsAreIgnoredWhenSetsAreNotConfigured() throws IOExcepti Logger.w("body1: " + body1); boolean awaitThird = thirdChangeLatch.await(5, TimeUnit.SECONDS); - Thread.sleep(800); + Thread.sleep(500); List thirdEntities = mRoomDb.splitDao().getAll(); int thirdSize = thirdEntities.size(); - boolean thirdSetsCorrect = thirdEntities.get(0).getBody().contains("[\"set_3\"]"); + String body30 = thirdEntities.get(0).getBody(); + String body31 = thirdEntities.get(1).getBody(); + boolean thirdSetsCorrect = body31.contains("[\"set_3\"]") && + body31.contains("\"name\":\"workm\",") && + body30.contains("\"name\":\"workm_set_3\",") && + body30.contains("[\"set_3\"]"); boolean awaitHits = hitsLatch.await(120, TimeUnit.SECONDS); @@ -185,7 +192,7 @@ private SplitFactory createFactory( Map responses = new HashMap<>(); responses.put("splitChanges", (uri, httpMethod, body) -> { - String since = uri.getQuery().split("&")[0].split("=")[1]; + String since = getSinceFromUri(uri); hitsLatch.countDown(); if (since.equals("-1")) { diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java new file mode 100644 index 000000000..03e53aac4 --- /dev/null +++ b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java @@ -0,0 +1,196 @@ +package tests.integration.sets; + +import static org.junit.Assert.assertNotNull; + +import static helper.IntegrationHelper.ResponseClosure.getSinceFromUri; + +import android.content.Context; + +import androidx.annotation.Nullable; +import androidx.test.platform.app.InstrumentationRegistry; + +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import fake.HttpClientMock; +import fake.HttpResponseMock; +import fake.HttpResponseMockDispatcher; +import helper.DatabaseHelper; +import helper.FileHelper; +import helper.IntegrationHelper; +import helper.TestableSplitConfigBuilder; +import io.split.android.client.SplitClient; +import io.split.android.client.SplitClientConfig; +import io.split.android.client.SplitFactory; +import io.split.android.client.SplitFilter; +import io.split.android.client.SyncConfig; +import io.split.android.client.dtos.SplitChange; +import io.split.android.client.events.SplitEvent; +import io.split.android.client.events.SplitEventTask; +import io.split.android.client.storage.db.SplitRoomDatabase; +import io.split.android.client.utils.Json; + +public class FlagSetsStreamingTest { + + private final FileHelper fileHelper = new FileHelper(); + private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); + private SplitRoomDatabase mRoomDb; + + @Before + public void setUp() { + mRoomDb = DatabaseHelper.getTestDatabase(mContext); + mRoomDb.clearAllTables(); + } + + @Test + public void sdkWithoutSetsConfiguredDoesNotTakeFeatureFlagSetsIntoAccount() throws IOException, InterruptedException { + SplitClient readyClient = getReadyClient(mContext, mRoomDb, true); + + assertNotNull(readyClient); + + + } + + /** + * SDK initialization with config.sets=["a", "b"] : + *

+ * if a SPLIT_UPDATE is received with {name:"test", "sets":["a", "b"]}, it should process it since is part of the config.Sets + *

+ * if a SPLIT_UPDATE is received with {name:"test", "sets":["a"]}, it should process it since is still part of the config.Sets + *

+ * if a SPLIT_UPDATE is received with {name:"test", "sets":[]} and the featureFlag is present in the storage, means that it was part of the config.Sets but not anymore. The featureFlag should be removed. + *

+ * if a SPLIT_UPDATE is received with {name:"test", "sets":["x"]} and the featureFlag is present in the storage, that means that was part of the config.Sets but not anymore. The featureFlag should be removed. + *

+ * if a SPLIT_UPDATE is received with {name:"test", "sets":["x", "y"]}, and the featureFlag is not part of the storage, the notification should be discarded since is NOT part of the config.Sets + *

+ * if a SPLIT_KILL is received with {cn:2, name:"test", "defaultTreatment":"off"} , two scenarios possibles: + *

+ * if featureFlag is present in the storage, the featureFlag should process the local kill behaviour. + *

+ * if not, a fetch must be needed. + */ + + @Test + public void sdkWithSetsConfiguredDeletedDueToEmptySets() { + /* + * Initialize a factory with a & b sets configured. + * + * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["a", "b"]}. It should process it since is part of the config.Sets + * + * 2. Receive a SPLIT_UPDATE with {name:"test", "sets":["a"]}. It should process it since is still part of the config.Sets + * + * 3. Receive a SPLIT_UPDATE with {name:"test", "sets":[]}. The featureFlag should be removed. + * + */ + } + + @Test + public void sdkWithSetsConfiguredDeletedDueToNonMatchingSets() { + /* + * Initialize a factory with a & b sets configured. + * + * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["a", "b"]}. It should process it since is part of the config.Sets + * + * 2. Receive a SPLIT_UPDATE with {name:"test", "sets":["x"]}. The featureFlag should be removed. + * + * 3. Receive a SPLIT_UPDATE with {name:"test", "sets":["x", "y"]}. No changes in storage. + */ + } + + @Test + public void sdkWithSetsReceivesSplitKill() { + /* + * Initialize a factory with a & b sets configured. + * + * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["a", "b"]}. It should process it since is part of the config.Sets + * + * 2. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" }. The featureFlag should be removed and a fetch should be performed. + */ + } + + @Test + public void sdkWithSetsReceivesSplitKillForNonExistingFeatureFlag() { + /* + * Initialize a factory with a & b sets configured. + * + * 1. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" }. No changes in storage, a fetch should be performed. + */ + } + + @Nullable + private SplitClient getReadyClient( + Context mContext, + SplitRoomDatabase splitRoomDatabase, + boolean streamingEnabled, + String... sets) throws IOException, InterruptedException { + SplitClientConfig config = new TestableSplitConfigBuilder() + .ready(30000) + .trafficType("client") + .enableDebug() + .impressionsRefreshRate(1000) + .impressionsCountersRefreshRate(1000) + .syncConfig(SyncConfig.builder() + .addSplitFilter(SplitFilter.bySet(Arrays.asList(sets))) + .build()) + .featuresRefreshRate(2) + .streamingEnabled(streamingEnabled) + .eventFlushInterval(1000) + .build(); +CountDownLatch authLatch = new CountDownLatch(1); + Map responses = new HashMap<>(); + responses.put("splitChanges", (uri, httpMethod, body) -> { + String since = getSinceFromUri(uri); + + if (since.equals("-1")) { + return new HttpResponseMock(200, loadSplitChangeWithSet(2)); + } else { + return new HttpResponseMock(200, IntegrationHelper.emptySplitChanges(1602796638344L, 1602796638344L)); + } + }); + responses.put("mySegments/CUSTOMER_ID", (uri, httpMethod, body) -> new HttpResponseMock(200, IntegrationHelper.emptyMySegments())); + responses.put("v2/auth", (uri, httpMethod, body) -> { + authLatch.countDown(); + return new HttpResponseMock(200, IntegrationHelper.streamingEnabledToken()); + }); + + HttpResponseMockDispatcher httpResponseMockDispatcher = IntegrationHelper.buildDispatcher(responses); + + SplitFactory splitFactory = IntegrationHelper.buildFactory( + IntegrationHelper.dummyApiKey(), + IntegrationHelper.dummyUserKey(), + config, + mContext, + new HttpClientMock(httpResponseMockDispatcher), + splitRoomDatabase, null, null, null); + + CountDownLatch readyLatch = new CountDownLatch(1); + SplitClient client = splitFactory.client(); + client.on(SplitEvent.SDK_READY, new SplitEventTask() { + @Override + public void onPostExecutionView(SplitClient client) { + readyLatch.countDown(); + } + }); + + boolean await = readyLatch.await(5, TimeUnit.SECONDS); + boolean authAwait = authLatch.await(5, TimeUnit.SECONDS); + + return (await && authAwait) ? client : null; + } + + private String loadSplitChangeWithSet(int setsCount) { + String change = fileHelper.loadFileContent(mContext, "split_changes_flag_set-" + setsCount + ".json"); + SplitChange parsedChange = Json.fromJson(change, SplitChange.class); + parsedChange.since = parsedChange.till; + + return Json.toJson(parsedChange); + } +} From 15175ec9d5f9e5eb6f45359853d678f80d2ed7e2 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Mon, 11 Sep 2023 14:45:59 -0300 Subject: [PATCH 06/16] First streaming test --- .../java/helper/IntegrationHelper.java | 20 +++---- .../sets/FlagSetsStreamingTest.java | 55 ++++++++++++++++--- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/androidTest/java/helper/IntegrationHelper.java b/src/androidTest/java/helper/IntegrationHelper.java index 031c70c24..28378942d 100644 --- a/src/androidTest/java/helper/IntegrationHelper.java +++ b/src/androidTest/java/helper/IntegrationHelper.java @@ -2,6 +2,7 @@ import android.content.Context; +import androidx.annotation.Nullable; import androidx.core.util.Pair; import com.google.common.base.Strings; @@ -16,6 +17,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.BlockingQueue; import fake.HttpClientMock; import fake.HttpResponseMock; @@ -257,7 +259,7 @@ public static String splitChangeV2CompressionType0() { "eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiJkNDMxY2RkMC1iMGJlLTExZWEtOGE4MC0xNjYwYWRhOWNlMzkiLCJuYW1lIjoibWF1cm9famF2YSIsInRyYWZmaWNBbGxvY2F0aW9uIjoxMDAsInRyYWZmaWNBbGxvY2F0aW9uU2VlZCI6LTkyMzkxNDkxLCJzZWVkIjotMTc2OTM3NzYwNCwic3RhdHVzIjoiQUNUSVZFIiwia2lsbGVkIjpmYWxzZSwiZGVmYXVsdFRyZWF0bWVudCI6Im9mZiIsImNoYW5nZU51bWJlciI6MTY4NDMyOTg1NDM4NSwiYWxnbyI6MiwiY29uZmlndXJhdGlvbnMiOnt9LCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiV0hJVEVMSVNUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7Im1hdGNoZXJUeXBlIjoiV0hJVEVMSVNUIiwibmVnYXRlIjpmYWxzZSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOnsid2hpdGVsaXN0IjpbImFkbWluIiwibWF1cm8iLCJuaWNvIl19fV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjoxMDB9XSwibGFiZWwiOiJ3aGl0ZWxpc3RlZCJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibWF1ci0yIn19XX0sInBhcnRpdGlvbnMiOlt7InRyZWF0bWVudCI6Im9uIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjoxMDB9LHsidHJlYXRtZW50IjoiVjQiLCJzaXplIjowfSx7InRyZWF0bWVudCI6InY1Iiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbWF1ci0yIn0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6InVzZXIifSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2V9XX0sInBhcnRpdGlvbnMiOlt7InRyZWF0bWVudCI6Im9uIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjoxMDB9LHsidHJlYXRtZW50IjoiVjQiLCJzaXplIjowfSx7InRyZWF0bWVudCI6InY1Iiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0="); } - private static String splitChangeV2(String changeNumber, String previousChangeNumber, String compressionType, String compressedPayload) { + public static String splitChangeV2(String changeNumber, String previousChangeNumber, String compressionType, String compressedPayload) { return "id: vQQ61wzBRO:0:0\n" + "event: message\n" + "data: {\"id\":\"m2T85LA4fQ:0:0\",\"clientId\":\"pri:NzIyNjY1MzI4\",\"timestamp\":"+System.currentTimeMillis()+",\"encoding\":\"json\",\"channel\":\"NzM2MDI5Mzc0_MTgyNTg1MTgwNg==_splits\",\"data\":\"{\\\"type\\\":\\\"SPLIT_UPDATE\\\",\\\"changeNumber\\\":"+changeNumber+",\\\"pcn\\\":"+previousChangeNumber+",\\\"c\\\":"+compressionType+",\\\"d\\\":\\\""+compressedPayload+"\\\"}\"}\n"; @@ -270,17 +272,17 @@ private static String splitChangeV2(String changeNumber, String previousChangeNu * @return The dispatcher to be used in {@link HttpClientMock} */ public static HttpResponseMockDispatcher buildDispatcher(Map responses) { - return buildDispatcher(responses, Collections.emptyMap()); + return buildDispatcher(responses, null); } /** * Builds a dispatcher with the given responses. * * @param responses The responses to be returned by the dispatcher. The keys are url paths. - * @param streamingResponses The streaming responses to be returned by the dispatcher. The keys are url paths. + * @param streamingQueue The streaming responses to be returned by the dispatcher. * @return The dispatcher to be used in {@link HttpClientMock} */ - public static HttpResponseMockDispatcher buildDispatcher(Map responses, Map streamingResponses) { + public static HttpResponseMockDispatcher buildDispatcher(Map responses, @Nullable BlockingQueue streamingQueue) { return new HttpResponseMockDispatcher() { @Override public HttpResponseMock getResponse(URI uri, HttpMethod method, String body) { @@ -300,17 +302,11 @@ public HttpResponseMock getResponse(URI uri, HttpMethod method, String body) { @Override public HttpStreamResponseMock getStreamResponse(URI uri) { try { - String path = uri.getPath().replace("/api/", ""); - if (streamingResponses.containsKey(path)) { - return streamingResponses.get(path).onResponse(uri); - } else { - return new HttpStreamResponseMock(200, null); - } + return new HttpStreamResponseMock(200, streamingQueue); } catch (IOException e) { e.printStackTrace(); + return null; } - - return null; } }; } diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java index 03e53aac4..c8315d247 100644 --- a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java +++ b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java @@ -1,8 +1,10 @@ package tests.integration.sets; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static helper.IntegrationHelper.ResponseClosure.getSinceFromUri; +import static helper.IntegrationHelper.splitChangeV2; import android.content.Context; @@ -16,7 +18,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import fake.HttpClientMock; @@ -36,9 +40,18 @@ import io.split.android.client.events.SplitEventTask; import io.split.android.client.storage.db.SplitRoomDatabase; import io.split.android.client.utils.Json; +import io.split.android.client.utils.logger.Logger; +import tests.integration.shared.TestingHelper; public class FlagSetsStreamingTest { + // workm with set_3 + private static final String set0SplitChange = splitChangeV2("1602798638344", "1602797638344", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjE2MDI3OTg2MzgzNDQsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMyJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); + // workm with set_1 + private static final String set1SplitChange = splitChangeV2("1602797638344", "1602796638344", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjE2MDI3OTc2MzgzNDQsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMSJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); + // mauro_java with no sets + private static final String noSetsSplitChange = splitChangeV2("1602799638344", "1602796638344", "0","eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiJkNDMxY2RkMC1iMGJlLTExZWEtOGE4MC0xNjYwYWRhOWNlMzkiLCJuYW1lIjoibWF1cm9famF2YSIsInRyYWZmaWNBbGxvY2F0aW9uIjoxMDAsInRyYWZmaWNBbGxvY2F0aW9uU2VlZCI6LTkyMzkxNDkxLCJzZWVkIjotMTc2OTM3NzYwNCwic3RhdHVzIjoiQUNUSVZFIiwia2lsbGVkIjpmYWxzZSwiZGVmYXVsdFRyZWF0bWVudCI6Im9mZiIsImNoYW5nZU51bWJlciI6MTYwMjc5OTYzODM0NCwiYWxnbyI6MiwiY29uZmlndXJhdGlvbnMiOnt9LCJzZXRzIjpbXSwiY29uZGl0aW9ucyI6W3siY29uZGl0aW9uVHlwZSI6IldISVRFTElTVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJtYXRjaGVyVHlwZSI6IldISVRFTElTVCIsIm5lZ2F0ZSI6ZmFsc2UsIndoaXRlbGlzdE1hdGNoZXJEYXRhIjp7IndoaXRlbGlzdCI6WyJhZG1pbiIsIm1hdXJvIiwibmljbyJdfX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoid2hpdGVsaXN0ZWQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6Im1hdXItMiJ9fV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6IlY0Iiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJ2NSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG1hdXItMiJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6IlY0Iiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJ2NSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); + private final FileHelper fileHelper = new FileHelper(); private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); private SplitRoomDatabase mRoomDb; @@ -50,12 +63,39 @@ public void setUp() { } @Test - public void sdkWithoutSetsConfiguredDoesNotTakeFeatureFlagSetsIntoAccount() throws IOException, InterruptedException { - SplitClient readyClient = getReadyClient(mContext, mRoomDb, true); + public void sdkWithoutSetsConfiguredDoesExcludeUpdates() throws IOException, InterruptedException { + /* + * Initialize a factory with streaming enabled and no sets. + * + * Receive notification with new feature flag with no sets. + * + * Verify that the feature flag is added. + */ + LinkedBlockingDeque mStreamingData = new LinkedBlockingDeque<>(); + SplitClient readyClient = getReadyClient(mContext, mRoomDb, true, mStreamingData); + + assertEquals(2, mRoomDb.splitDao().getAll().size()); + CountDownLatch updateLatch = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, new SplitEventTask() { + @Override + public void onPostExecutionView(SplitClient client) { + updateLatch.countDown(); + } + }); + pushToStreaming(mStreamingData, noSetsSplitChange); + boolean updateAwait = updateLatch.await(5, TimeUnit.SECONDS); - assertNotNull(readyClient); + assertTrue(updateAwait); + assertEquals(3, mRoomDb.splitDao().getAll().size()); + } + private static void pushToStreaming(LinkedBlockingDeque streamingData, String message) throws InterruptedException { + try { + streamingData.put(message + "" + "\n"); + Logger.d("Pushed message: " + message); + } catch (InterruptedException e) { + } } /** @@ -77,7 +117,6 @@ public void sdkWithoutSetsConfiguredDoesNotTakeFeatureFlagSetsIntoAccount() thro *

* if not, a fetch must be needed. */ - @Test public void sdkWithSetsConfiguredDeletedDueToEmptySets() { /* @@ -130,6 +169,7 @@ private SplitClient getReadyClient( Context mContext, SplitRoomDatabase splitRoomDatabase, boolean streamingEnabled, + BlockingQueue streamingData, String... sets) throws IOException, InterruptedException { SplitClientConfig config = new TestableSplitConfigBuilder() .ready(30000) @@ -144,7 +184,7 @@ private SplitClient getReadyClient( .streamingEnabled(streamingEnabled) .eventFlushInterval(1000) .build(); -CountDownLatch authLatch = new CountDownLatch(1); + CountDownLatch authLatch = new CountDownLatch(1); Map responses = new HashMap<>(); responses.put("splitChanges", (uri, httpMethod, body) -> { String since = getSinceFromUri(uri); @@ -161,7 +201,7 @@ private SplitClient getReadyClient( return new HttpResponseMock(200, IntegrationHelper.streamingEnabledToken()); }); - HttpResponseMockDispatcher httpResponseMockDispatcher = IntegrationHelper.buildDispatcher(responses); + HttpResponseMockDispatcher httpResponseMockDispatcher = IntegrationHelper.buildDispatcher(responses, streamingData); SplitFactory splitFactory = IntegrationHelper.buildFactory( IntegrationHelper.dummyApiKey(), @@ -182,6 +222,7 @@ public void onPostExecutionView(SplitClient client) { boolean await = readyLatch.await(5, TimeUnit.SECONDS); boolean authAwait = authLatch.await(5, TimeUnit.SECONDS); + TestingHelper.pushKeepAlive(streamingData); return (await && authAwait) ? client : null; } From 55c18bb5cf0a57eefff85609d894755be3d7a718 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Mon, 11 Sep 2023 16:56:21 -0300 Subject: [PATCH 07/16] More tests --- .../sets/FlagSetsStreamingTest.java | 93 +++++++++++++------ 1 file changed, 65 insertions(+), 28 deletions(-) diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java index c8315d247..a92cd7100 100644 --- a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java +++ b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; @@ -38,6 +39,7 @@ import io.split.android.client.dtos.SplitChange; import io.split.android.client.events.SplitEvent; import io.split.android.client.events.SplitEventTask; +import io.split.android.client.storage.db.SplitEntity; import io.split.android.client.storage.db.SplitRoomDatabase; import io.split.android.client.utils.Json; import io.split.android.client.utils.logger.Logger; @@ -45,12 +47,16 @@ public class FlagSetsStreamingTest { + // workm with no sets + private static final String setNoneSplitChange = splitChangeV2("4", "3", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjUsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6W10sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJJTl9TRUdNRU5UIiwibmVnYXRlIjpmYWxzZSwidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOnsic2VnbWVudE5hbWUiOiJuZXdfc2VnbWVudCJ9LCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbmV3X3NlZ21lbnQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjpudWxsLCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImZyZWUiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0="); // workm with set_3 - private static final String set0SplitChange = splitChangeV2("1602798638344", "1602797638344", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjE2MDI3OTg2MzgzNDQsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMyJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); + private static final String set0SplitChange = splitChangeV2("4", "3", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjQsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMyJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); // workm with set_1 - private static final String set1SplitChange = splitChangeV2("1602797638344", "1602796638344", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjE2MDI3OTc2MzgzNDQsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMSJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); + private static final String set1SplitChange = splitChangeV2("3", "2", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjMsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMSJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); + // workm with set_1, set_2 + private static final String set3SplitChange = splitChangeV2("2", "1", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjIsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMSIsInNldF8yIl0sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJJTl9TRUdNRU5UIiwibmVnYXRlIjpmYWxzZSwidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOnsic2VnbWVudE5hbWUiOiJuZXdfc2VnbWVudCJ9LCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbmV3X3NlZ21lbnQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjpudWxsLCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImZyZWUiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0"); // mauro_java with no sets - private static final String noSetsSplitChange = splitChangeV2("1602799638344", "1602796638344", "0","eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiJkNDMxY2RkMC1iMGJlLTExZWEtOGE4MC0xNjYwYWRhOWNlMzkiLCJuYW1lIjoibWF1cm9famF2YSIsInRyYWZmaWNBbGxvY2F0aW9uIjoxMDAsInRyYWZmaWNBbGxvY2F0aW9uU2VlZCI6LTkyMzkxNDkxLCJzZWVkIjotMTc2OTM3NzYwNCwic3RhdHVzIjoiQUNUSVZFIiwia2lsbGVkIjpmYWxzZSwiZGVmYXVsdFRyZWF0bWVudCI6Im9mZiIsImNoYW5nZU51bWJlciI6MTYwMjc5OTYzODM0NCwiYWxnbyI6MiwiY29uZmlndXJhdGlvbnMiOnt9LCJzZXRzIjpbXSwiY29uZGl0aW9ucyI6W3siY29uZGl0aW9uVHlwZSI6IldISVRFTElTVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJtYXRjaGVyVHlwZSI6IldISVRFTElTVCIsIm5lZ2F0ZSI6ZmFsc2UsIndoaXRlbGlzdE1hdGNoZXJEYXRhIjp7IndoaXRlbGlzdCI6WyJhZG1pbiIsIm1hdXJvIiwibmljbyJdfX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoid2hpdGVsaXN0ZWQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6Im1hdXItMiJ9fV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6IlY0Iiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJ2NSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG1hdXItMiJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6IlY0Iiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJ2NSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); + private static final String noSetsSplitChange = splitChangeV2("2", "1", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiJkNDMxY2RkMC1iMGJlLTExZWEtOGE4MC0xNjYwYWRhOWNlMzkiLCJuYW1lIjoibWF1cm9famF2YSIsInRyYWZmaWNBbGxvY2F0aW9uIjoxMDAsInRyYWZmaWNBbGxvY2F0aW9uU2VlZCI6LTkyMzkxNDkxLCJzZWVkIjotMTc2OTM3NzYwNCwic3RhdHVzIjoiQUNUSVZFIiwia2lsbGVkIjpmYWxzZSwiZGVmYXVsdFRyZWF0bWVudCI6Im9mZiIsImNoYW5nZU51bWJlciI6MTYwMjc5OTYzODM0NCwiYWxnbyI6MiwiY29uZmlndXJhdGlvbnMiOnt9LCJzZXRzIjpbXSwiY29uZGl0aW9ucyI6W3siY29uZGl0aW9uVHlwZSI6IldISVRFTElTVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJtYXRjaGVyVHlwZSI6IldISVRFTElTVCIsIm5lZ2F0ZSI6ZmFsc2UsIndoaXRlbGlzdE1hdGNoZXJEYXRhIjp7IndoaXRlbGlzdCI6WyJhZG1pbiIsIm1hdXJvIiwibmljbyJdfX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoid2hpdGVsaXN0ZWQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6Im1hdXItMiJ9fV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6IlY0Iiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJ2NSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG1hdXItMiJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6IlY0Iiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJ2NSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); private final FileHelper fileHelper = new FileHelper(); private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); @@ -74,28 +80,19 @@ public void sdkWithoutSetsConfiguredDoesExcludeUpdates() throws IOException, Int LinkedBlockingDeque mStreamingData = new LinkedBlockingDeque<>(); SplitClient readyClient = getReadyClient(mContext, mRoomDb, true, mStreamingData); - assertEquals(2, mRoomDb.splitDao().getAll().size()); + int initialSplitsSize = mRoomDb.splitDao().getAll().size(); + + // set up update listener CountDownLatch updateLatch = new CountDownLatch(1); - readyClient.on(SplitEvent.SDK_UPDATE, new SplitEventTask() { - @Override - public void onPostExecutionView(SplitClient client) { - updateLatch.countDown(); - } - }); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(updateLatch)); + + // push change pushToStreaming(mStreamingData, noSetsSplitChange); boolean updateAwait = updateLatch.await(5, TimeUnit.SECONDS); assertTrue(updateAwait); - assertEquals(3, mRoomDb.splitDao().getAll().size()); - } - - private static void pushToStreaming(LinkedBlockingDeque streamingData, String message) throws InterruptedException { - try { - streamingData.put(message + "" + "\n"); - - Logger.d("Pushed message: " + message); - } catch (InterruptedException e) { - } + assertEquals(0, initialSplitsSize); + assertEquals(1, mRoomDb.splitDao().getAll().size()); } /** @@ -118,17 +115,52 @@ private static void pushToStreaming(LinkedBlockingDeque streamingData, S * if not, a fetch must be needed. */ @Test - public void sdkWithSetsConfiguredDeletedDueToEmptySets() { + public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, InterruptedException { /* * Initialize a factory with a & b sets configured. * - * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["a", "b"]}. It should process it since is part of the config.Sets + * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]}. It should process it since is part of the config.Sets * - * 2. Receive a SPLIT_UPDATE with {name:"test", "sets":["a"]}. It should process it since is still part of the config.Sets + * 2. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1"]}. It should process it since is still part of the config.Sets * * 3. Receive a SPLIT_UPDATE with {name:"test", "sets":[]}. The featureFlag should be removed. * */ + LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); + SplitClient readyClient = getReadyClient(mContext, mRoomDb, true, streamingData, "set_1", "set_2"); + + // 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]} + CountDownLatch firstUpdate = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(firstUpdate)); + pushToStreaming(streamingData, set3SplitChange); + boolean firstUpdateAwait = firstUpdate.await(5, TimeUnit.SECONDS); + List entities = mRoomDb.splitDao().getAll(); + boolean firstUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\",\"set_2\"]") && + entities.get(0).getBody().contains("\"name\":\"workm\""); + + // 2. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1"]} + CountDownLatch secondUpdate = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(secondUpdate)); + pushToStreaming(streamingData, set1SplitChange); + boolean secondUpdateAwait = secondUpdate.await(5, TimeUnit.SECONDS); + entities = mRoomDb.splitDao().getAll(); + boolean secondUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\"]") && + entities.get(0).getBody().contains("\"name\":\"workm\""); + + // 3. Receive a SPLIT_UPDATE with {name:"test", "sets":[]} + CountDownLatch thirdUpdate = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(thirdUpdate)); + pushToStreaming(streamingData, setNoneSplitChange); + boolean thirdUpdateAwait = thirdUpdate.await(5, TimeUnit.SECONDS); + entities = mRoomDb.splitDao().getAll(); + boolean thirdUpdateStored = entities.isEmpty(); + + assertTrue(firstUpdateAwait); + assertTrue(firstUpdateStored); + assertTrue(secondUpdateAwait); + assertTrue(secondUpdateStored); + assertTrue(thirdUpdateAwait); + assertTrue(thirdUpdateStored); } @Test @@ -189,11 +221,7 @@ private SplitClient getReadyClient( responses.put("splitChanges", (uri, httpMethod, body) -> { String since = getSinceFromUri(uri); - if (since.equals("-1")) { - return new HttpResponseMock(200, loadSplitChangeWithSet(2)); - } else { - return new HttpResponseMock(200, IntegrationHelper.emptySplitChanges(1602796638344L, 1602796638344L)); - } + return new HttpResponseMock(200, IntegrationHelper.emptySplitChanges(-1, 1)); }); responses.put("mySegments/CUSTOMER_ID", (uri, httpMethod, body) -> new HttpResponseMock(200, IntegrationHelper.emptyMySegments())); responses.put("v2/auth", (uri, httpMethod, body) -> { @@ -234,4 +262,13 @@ private String loadSplitChangeWithSet(int setsCount) { return Json.toJson(parsedChange); } + + private static void pushToStreaming(LinkedBlockingDeque streamingData, String message) throws InterruptedException { + try { + streamingData.put(message + "" + "\n"); + + Logger.d("Pushed message: " + message); + } catch (InterruptedException ignored) { + } + } } From b70e8956b43b7368a87a65639c27b93528af7576 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Mon, 11 Sep 2023 18:51:58 -0300 Subject: [PATCH 08/16] More tests --- .../sets/FlagSetsStreamingTest.java | 77 ++++++++++++++----- .../splits/FeatureFlagProcessStrategy.java | 3 + .../splits/SplitInPlaceUpdateTask.java | 2 +- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java index a92cd7100..61d0cb412 100644 --- a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java +++ b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java @@ -2,7 +2,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; - import static helper.IntegrationHelper.ResponseClosure.getSinceFromUri; import static helper.IntegrationHelper.splitChangeV2; @@ -28,7 +27,6 @@ import fake.HttpResponseMock; import fake.HttpResponseMockDispatcher; import helper.DatabaseHelper; -import helper.FileHelper; import helper.IntegrationHelper; import helper.TestableSplitConfigBuilder; import io.split.android.client.SplitClient; @@ -36,29 +34,28 @@ import io.split.android.client.SplitFactory; import io.split.android.client.SplitFilter; import io.split.android.client.SyncConfig; -import io.split.android.client.dtos.SplitChange; import io.split.android.client.events.SplitEvent; import io.split.android.client.events.SplitEventTask; import io.split.android.client.storage.db.SplitEntity; import io.split.android.client.storage.db.SplitRoomDatabase; -import io.split.android.client.utils.Json; import io.split.android.client.utils.logger.Logger; import tests.integration.shared.TestingHelper; public class FlagSetsStreamingTest { + // workm with set_3, set_4 + private static final String splitChange5 = splitChangeV2("5", "4", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjUsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMyIsInNldF80Il0sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJJTl9TRUdNRU5UIiwibmVnYXRlIjpmYWxzZSwidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOnsic2VnbWVudE5hbWUiOiJuZXdfc2VnbWVudCJ9LCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbmV3X3NlZ21lbnQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjpudWxsLCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImZyZWUiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0"); // workm with no sets - private static final String setNoneSplitChange = splitChangeV2("4", "3", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjUsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6W10sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJJTl9TRUdNRU5UIiwibmVnYXRlIjpmYWxzZSwidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOnsic2VnbWVudE5hbWUiOiJuZXdfc2VnbWVudCJ9LCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbmV3X3NlZ21lbnQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjpudWxsLCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImZyZWUiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0="); + private static final String splitChange5None = splitChangeV2("5", "4", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjUsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6W10sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJJTl9TRUdNRU5UIiwibmVnYXRlIjpmYWxzZSwidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOnsic2VnbWVudE5hbWUiOiJuZXdfc2VnbWVudCJ9LCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbmV3X3NlZ21lbnQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjpudWxsLCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImZyZWUiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0="); // workm with set_3 - private static final String set0SplitChange = splitChangeV2("4", "3", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjQsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMyJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); + private static final String splitChange4 = splitChangeV2("4", "3", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjQsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMyJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); // workm with set_1 - private static final String set1SplitChange = splitChangeV2("3", "2", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjMsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMSJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); + private static final String splitChange3 = splitChangeV2("3", "2", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjMsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMSJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); // workm with set_1, set_2 - private static final String set3SplitChange = splitChangeV2("2", "1", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjIsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMSIsInNldF8yIl0sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJJTl9TRUdNRU5UIiwibmVnYXRlIjpmYWxzZSwidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOnsic2VnbWVudE5hbWUiOiJuZXdfc2VnbWVudCJ9LCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbmV3X3NlZ21lbnQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjpudWxsLCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImZyZWUiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0"); + private static final String splitChange2 = splitChangeV2("2", "1", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjIsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMSIsInNldF8yIl0sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJJTl9TRUdNRU5UIiwibmVnYXRlIjpmYWxzZSwidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOnsic2VnbWVudE5hbWUiOiJuZXdfc2VnbWVudCJ9LCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbmV3X3NlZ21lbnQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjpudWxsLCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImZyZWUiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0"); // mauro_java with no sets private static final String noSetsSplitChange = splitChangeV2("2", "1", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiJkNDMxY2RkMC1iMGJlLTExZWEtOGE4MC0xNjYwYWRhOWNlMzkiLCJuYW1lIjoibWF1cm9famF2YSIsInRyYWZmaWNBbGxvY2F0aW9uIjoxMDAsInRyYWZmaWNBbGxvY2F0aW9uU2VlZCI6LTkyMzkxNDkxLCJzZWVkIjotMTc2OTM3NzYwNCwic3RhdHVzIjoiQUNUSVZFIiwia2lsbGVkIjpmYWxzZSwiZGVmYXVsdFRyZWF0bWVudCI6Im9mZiIsImNoYW5nZU51bWJlciI6MTYwMjc5OTYzODM0NCwiYWxnbyI6MiwiY29uZmlndXJhdGlvbnMiOnt9LCJzZXRzIjpbXSwiY29uZGl0aW9ucyI6W3siY29uZGl0aW9uVHlwZSI6IldISVRFTElTVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJtYXRjaGVyVHlwZSI6IldISVRFTElTVCIsIm5lZ2F0ZSI6ZmFsc2UsIndoaXRlbGlzdE1hdGNoZXJEYXRhIjp7IndoaXRlbGlzdCI6WyJhZG1pbiIsIm1hdXJvIiwibmljbyJdfX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoid2hpdGVsaXN0ZWQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6Im1hdXItMiJ9fV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6IlY0Iiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJ2NSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG1hdXItMiJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6IlY0Iiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJ2NSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); - private final FileHelper fileHelper = new FileHelper(); private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); private SplitRoomDatabase mRoomDb; @@ -132,7 +129,7 @@ public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, Int // 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]} CountDownLatch firstUpdate = new CountDownLatch(1); readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(firstUpdate)); - pushToStreaming(streamingData, set3SplitChange); + pushToStreaming(streamingData, splitChange2); boolean firstUpdateAwait = firstUpdate.await(5, TimeUnit.SECONDS); List entities = mRoomDb.splitDao().getAll(); boolean firstUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\",\"set_2\"]") && @@ -141,7 +138,7 @@ public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, Int // 2. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1"]} CountDownLatch secondUpdate = new CountDownLatch(1); readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(secondUpdate)); - pushToStreaming(streamingData, set1SplitChange); + pushToStreaming(streamingData, splitChange3); boolean secondUpdateAwait = secondUpdate.await(5, TimeUnit.SECONDS); entities = mRoomDb.splitDao().getAll(); boolean secondUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\"]") && @@ -150,7 +147,7 @@ public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, Int // 3. Receive a SPLIT_UPDATE with {name:"test", "sets":[]} CountDownLatch thirdUpdate = new CountDownLatch(1); readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(thirdUpdate)); - pushToStreaming(streamingData, setNoneSplitChange); + pushToStreaming(streamingData, splitChange5None); boolean thirdUpdateAwait = thirdUpdate.await(5, TimeUnit.SECONDS); entities = mRoomDb.splitDao().getAll(); boolean thirdUpdateStored = entities.isEmpty(); @@ -164,7 +161,7 @@ public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, Int } @Test - public void sdkWithSetsConfiguredDeletedDueToNonMatchingSets() { + public void sdkWithSetsConfiguredDeletedDueToNonMatchingSets() throws IOException, InterruptedException { /* * Initialize a factory with a & b sets configured. * @@ -174,6 +171,52 @@ public void sdkWithSetsConfiguredDeletedDueToNonMatchingSets() { * * 3. Receive a SPLIT_UPDATE with {name:"test", "sets":["x", "y"]}. No changes in storage. */ + + LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); + SplitClient readyClient = getReadyClient(mContext, mRoomDb, true, streamingData, "set_1", "set_2"); + + // 1. Receive a SPLIT_UPDATE with "sets":["set_1", "set_2"] + CountDownLatch firstUpdate = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(firstUpdate)); + pushToStreaming(streamingData, splitChange2); + boolean firstUpdateAwait = firstUpdate.await(5, TimeUnit.SECONDS); + List entities = mRoomDb.splitDao().getAll(); + boolean firstUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\",\"set_2\"]") && + entities.get(0).getBody().contains("\"name\":\"workm\""); + + // 2. Receive a SPLIT_UPDATE with "sets":["set_1"] + CountDownLatch secondUpdate = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(secondUpdate)); + pushToStreaming(streamingData, splitChange3); + boolean secondUpdateAwait = secondUpdate.await(5, TimeUnit.SECONDS); + entities = mRoomDb.splitDao().getAll(); + boolean secondUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\"]") && + entities.get(0).getBody().contains("\"name\":\"workm\""); + + // 3. Receive a SPLIT_UPDATE with "sets":["set_3"] + CountDownLatch thirdUpdate = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(thirdUpdate)); + pushToStreaming(streamingData, splitChange4); + boolean thirdUpdateAwait = thirdUpdate.await(5, TimeUnit.SECONDS); + entities = mRoomDb.splitDao().getAll(); + boolean thirdUpdateStored = entities.size() == 0; + + // 4. Receive a SPLIT_UPDATE with "sets":["set_3", "set_4"] + CountDownLatch fourthUpdate = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(fourthUpdate)); + pushToStreaming(streamingData, splitChange5); + boolean fourthUpdateAwait = fourthUpdate.await(5, TimeUnit.SECONDS); + entities = mRoomDb.splitDao().getAll(); + boolean fourthUpdateStored = entities.size() == 0; + + assertTrue(firstUpdateAwait); + assertTrue(firstUpdateStored); + assertTrue(secondUpdateAwait); + assertTrue(secondUpdateStored); + assertTrue(thirdUpdateAwait); + assertTrue(thirdUpdateStored); + assertTrue(fourthUpdateAwait); + assertTrue(fourthUpdateStored); } @Test @@ -255,14 +298,6 @@ public void onPostExecutionView(SplitClient client) { return (await && authAwait) ? client : null; } - private String loadSplitChangeWithSet(int setsCount) { - String change = fileHelper.loadFileContent(mContext, "split_changes_flag_set-" + setsCount + ".json"); - SplitChange parsedChange = Json.fromJson(change, SplitChange.class); - parsedChange.since = parsedChange.till; - - return Json.toJson(parsedChange); - } - private static void pushToStreaming(LinkedBlockingDeque streamingData, String message) throws InterruptedException { try { streamingData.put(message + "" + "\n"); diff --git a/src/main/java/io/split/android/client/service/splits/FeatureFlagProcessStrategy.java b/src/main/java/io/split/android/client/service/splits/FeatureFlagProcessStrategy.java index 2f50f6bbb..fafc48806 100644 --- a/src/main/java/io/split/android/client/service/splits/FeatureFlagProcessStrategy.java +++ b/src/main/java/io/split/android/client/service/splits/FeatureFlagProcessStrategy.java @@ -6,6 +6,7 @@ import io.split.android.client.dtos.Split; import io.split.android.client.dtos.Status; +import io.split.android.client.utils.logger.Logger; interface FeatureFlagProcessStrategy { @@ -36,6 +37,7 @@ class NamesProcessStrategy implements FeatureFlagProcessStrategy { @Override public void process(List activeFeatureFlags, List archivedFeatureFlags, Split featureFlag) { + Logger.v("Processing with names"); // If the feature flag name is in the filter, we process it according to its status. Otherwise it is ignored if (mConfiguredValues.contains(featureFlag.name)) { mStatusProcessStrategy.process(activeFeatureFlags, archivedFeatureFlags, featureFlag); @@ -55,6 +57,7 @@ class SetsProcessStrategy implements FeatureFlagProcessStrategy { @Override public void process(List activeFeatureFlags, List archivedFeatureFlags, Split featureFlag) { + Logger.v("Processing with sets"); if (featureFlag.sets == null || featureFlag.sets.isEmpty()) { archivedFeatureFlags.add(featureFlag); return; diff --git a/src/main/java/io/split/android/client/service/splits/SplitInPlaceUpdateTask.java b/src/main/java/io/split/android/client/service/splits/SplitInPlaceUpdateTask.java index e9d072cf6..c34dd6539 100644 --- a/src/main/java/io/split/android/client/service/splits/SplitInPlaceUpdateTask.java +++ b/src/main/java/io/split/android/client/service/splits/SplitInPlaceUpdateTask.java @@ -49,7 +49,7 @@ public SplitTaskExecutionInfo execute() { mEventsManager.notifyInternalEvent(SplitInternalEvent.SPLITS_UPDATED); mTelemetryRuntimeProducer.recordUpdatesFromSSE(UpdatesFromSSEEnum.SPLITS); - Logger.d("Updated feature flag: " + mSplit.name); + Logger.v("Updated feature flag"); return SplitTaskExecutionInfo.success(SplitTaskType.SPLITS_SYNC); } catch (Exception ex) { Logger.e("Could not update feature flag"); From 67e32c0bf8e6ac443ed7962aab05fbaa89ab9c98 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Mon, 11 Sep 2023 19:14:06 -0300 Subject: [PATCH 09/16] Fix test --- .../sets/FlagSetsStreamingTest.java | 39 ++++++------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java index 61d0cb412..83f6daaab 100644 --- a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java +++ b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java @@ -46,7 +46,7 @@ public class FlagSetsStreamingTest { // workm with set_3, set_4 private static final String splitChange5 = splitChangeV2("5", "4", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjUsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMyIsInNldF80Il0sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJJTl9TRUdNRU5UIiwibmVnYXRlIjpmYWxzZSwidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOnsic2VnbWVudE5hbWUiOiJuZXdfc2VnbWVudCJ9LCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbmV3X3NlZ21lbnQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjpudWxsLCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImZyZWUiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0"); // workm with no sets - private static final String splitChange5None = splitChangeV2("5", "4", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjUsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6W10sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJJTl9TRUdNRU5UIiwibmVnYXRlIjpmYWxzZSwidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOnsic2VnbWVudE5hbWUiOiJuZXdfc2VnbWVudCJ9LCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbmV3X3NlZ21lbnQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjpudWxsLCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImZyZWUiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0="); + private static final String splitChange4None = splitChangeV2("4", "3", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjUsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6W10sImNvbmRpdGlvbnMiOlt7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJJTl9TRUdNRU5UIiwibmVnYXRlIjpmYWxzZSwidXNlckRlZmluZWRTZWdtZW50TWF0Y2hlckRhdGEiOnsic2VnbWVudE5hbWUiOiJuZXdfc2VnbWVudCJ9LCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImluIHNlZ21lbnQgbmV3X3NlZ21lbnQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoiY2xpZW50IiwiYXR0cmlidXRlIjpudWxsfSwibWF0Y2hlclR5cGUiOiJBTExfS0VZUyIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjpudWxsLCJ3aGl0ZWxpc3RNYXRjaGVyRGF0YSI6bnVsbCwidW5hcnlOdW1lcmljTWF0Y2hlckRhdGEiOm51bGwsImJldHdlZW5NYXRjaGVyRGF0YSI6bnVsbCwiYm9vbGVhbk1hdGNoZXJEYXRhIjpudWxsLCJkZXBlbmRlbmN5TWF0Y2hlckRhdGEiOm51bGwsInN0cmluZ01hdGNoZXJEYXRhIjpudWxsfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJvZmYiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImZyZWUiLCJzaXplIjowfSx7InRyZWF0bWVudCI6ImNvbnRhIiwic2l6ZSI6MH1dLCJsYWJlbCI6ImRlZmF1bHQgcnVsZSJ9XX0="); // workm with set_3 private static final String splitChange4 = splitChangeV2("4", "3", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJjbGllbnQiLCJuYW1lIjoid29ya20iLCJ0cmFmZmljQWxsb2NhdGlvbiI6MTAwLCJ0cmFmZmljQWxsb2NhdGlvblNlZWQiOjE0NzM5MjIyNCwic2VlZCI6NTI0NDE3MTA1LCJzdGF0dXMiOiJBQ1RJVkUiLCJraWxsZWQiOmZhbHNlLCJkZWZhdWx0VHJlYXRtZW50Ijoib24iLCJjaGFuZ2VOdW1iZXIiOjQsImFsZ28iOjIsImNvbmZpZ3VyYXRpb25zIjp7fSwic2V0cyI6WyJzZXRfMyJdLCJjb25kaXRpb25zIjpbeyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiSU5fU0VHTUVOVCIsIm5lZ2F0ZSI6ZmFsc2UsInVzZXJEZWZpbmVkU2VnbWVudE1hdGNoZXJEYXRhIjp7InNlZ21lbnROYW1lIjoibmV3X3NlZ21lbnQifSwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjowfSx7InRyZWF0bWVudCI6Im9mZiIsInNpemUiOjB9LHsidHJlYXRtZW50IjoiZnJlZSIsInNpemUiOjEwMH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG5ld19zZWdtZW50In0seyJjb25kaXRpb25UeXBlIjoiUk9MTE9VVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJrZXlTZWxlY3RvciI6eyJ0cmFmZmljVHlwZSI6ImNsaWVudCIsImF0dHJpYnV0ZSI6bnVsbH0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6bnVsbCwid2hpdGVsaXN0TWF0Y2hlckRhdGEiOm51bGwsInVuYXJ5TnVtZXJpY01hdGNoZXJEYXRhIjpudWxsLCJiZXR3ZWVuTWF0Y2hlckRhdGEiOm51bGwsImJvb2xlYW5NYXRjaGVyRGF0YSI6bnVsbCwiZGVwZW5kZW5jeU1hdGNoZXJEYXRhIjpudWxsLCJzdHJpbmdNYXRjaGVyRGF0YSI6bnVsbH1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib24iLCJzaXplIjoxMDB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJmcmVlIiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJjb250YSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); // workm with set_1 @@ -92,29 +92,10 @@ public void sdkWithoutSetsConfiguredDoesExcludeUpdates() throws IOException, Int assertEquals(1, mRoomDb.splitDao().getAll().size()); } - /** - * SDK initialization with config.sets=["a", "b"] : - *

- * if a SPLIT_UPDATE is received with {name:"test", "sets":["a", "b"]}, it should process it since is part of the config.Sets - *

- * if a SPLIT_UPDATE is received with {name:"test", "sets":["a"]}, it should process it since is still part of the config.Sets - *

- * if a SPLIT_UPDATE is received with {name:"test", "sets":[]} and the featureFlag is present in the storage, means that it was part of the config.Sets but not anymore. The featureFlag should be removed. - *

- * if a SPLIT_UPDATE is received with {name:"test", "sets":["x"]} and the featureFlag is present in the storage, that means that was part of the config.Sets but not anymore. The featureFlag should be removed. - *

- * if a SPLIT_UPDATE is received with {name:"test", "sets":["x", "y"]}, and the featureFlag is not part of the storage, the notification should be discarded since is NOT part of the config.Sets - *

- * if a SPLIT_KILL is received with {cn:2, name:"test", "defaultTreatment":"off"} , two scenarios possibles: - *

- * if featureFlag is present in the storage, the featureFlag should process the local kill behaviour. - *

- * if not, a fetch must be needed. - */ @Test public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, InterruptedException { /* - * Initialize a factory with a & b sets configured. + * Initialize a factory with set_1 & set_2 sets configured. * * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]}. It should process it since is part of the config.Sets * @@ -147,7 +128,7 @@ public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, Int // 3. Receive a SPLIT_UPDATE with {name:"test", "sets":[]} CountDownLatch thirdUpdate = new CountDownLatch(1); readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(thirdUpdate)); - pushToStreaming(streamingData, splitChange5None); + pushToStreaming(streamingData, splitChange4None); boolean thirdUpdateAwait = thirdUpdate.await(5, TimeUnit.SECONDS); entities = mRoomDb.splitDao().getAll(); boolean thirdUpdateStored = entities.isEmpty(); @@ -163,13 +144,15 @@ public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, Int @Test public void sdkWithSetsConfiguredDeletedDueToNonMatchingSets() throws IOException, InterruptedException { /* - * Initialize a factory with a & b sets configured. + * Initialize a factory with set_1 & set_2 sets configured. + * + * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]}. It should process it since is part of the config.Sets * - * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["a", "b"]}. It should process it since is part of the config.Sets + * 2. Receive a SPLIT_UPDATE with "sets":["set_1"]. The feature flag should be updated. * - * 2. Receive a SPLIT_UPDATE with {name:"test", "sets":["x"]}. The featureFlag should be removed. + * 3. Receive a SPLIT_UPDATE with "sets":["set_3"]. The feature flag should be removed. * - * 3. Receive a SPLIT_UPDATE with {name:"test", "sets":["x", "y"]}. No changes in storage. + * 4. Receive a SPLIT_UPDATE with "sets":["set_3", "set_4"] No changes in storage. */ LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); @@ -222,9 +205,9 @@ public void sdkWithSetsConfiguredDeletedDueToNonMatchingSets() throws IOExceptio @Test public void sdkWithSetsReceivesSplitKill() { /* - * Initialize a factory with a & b sets configured. + * Initialize a factory with set_1 & set_2 sets configured. * - * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["a", "b"]}. It should process it since is part of the config.Sets + * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]}. It should process it since is part of the config.Sets * * 2. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" }. The featureFlag should be removed and a fetch should be performed. */ From 9ee4b34a98c8bc80bc3135441b0902aa61ad6cdd Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Mon, 11 Sep 2023 19:53:44 -0300 Subject: [PATCH 10/16] Kill test --- .../java/helper/IntegrationHelper.java | 6 +++ .../sets/FlagSetsStreamingTest.java | 42 +++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/androidTest/java/helper/IntegrationHelper.java b/src/androidTest/java/helper/IntegrationHelper.java index 28378942d..92fcce547 100644 --- a/src/androidTest/java/helper/IntegrationHelper.java +++ b/src/androidTest/java/helper/IntegrationHelper.java @@ -265,6 +265,12 @@ public static String splitChangeV2(String changeNumber, String previousChangeNum "data: {\"id\":\"m2T85LA4fQ:0:0\",\"clientId\":\"pri:NzIyNjY1MzI4\",\"timestamp\":"+System.currentTimeMillis()+",\"encoding\":\"json\",\"channel\":\"NzM2MDI5Mzc0_MTgyNTg1MTgwNg==_splits\",\"data\":\"{\\\"type\\\":\\\"SPLIT_UPDATE\\\",\\\"changeNumber\\\":"+changeNumber+",\\\"pcn\\\":"+previousChangeNumber+",\\\"c\\\":"+compressionType+",\\\"d\\\":\\\""+compressedPayload+"\\\"}\"}\n"; } + public static String splitKill(String changeNumber, String splitName) { + return "id:cf74eb42-f687-48e4-ad18-af2125110aac\n" + + "event:message\n" + + "data:{\"id\":\"-OT-rGuSwz:0:0\",\"clientId\":\"NDEzMTY5Mzg0MA==:NDIxNjU0NTUyNw==\",\"timestamp\":"+System.currentTimeMillis()+",\"encoding\":\"json\",\"channel\":\"NzM2MDI5Mzc0_MTgyNTg1MTgwNg==_splits\",\"data\":\"{\\\"type\\\":\\\"SPLIT_KILL\\\",\\\"changeNumber\\\":" + changeNumber + ",\\\"defaultTreatment\\\":\\\"off\\\",\\\"splitName\\\":\\\"" + splitName + "\\\"}\"}\n"; + } + /** * Builds a dispatcher with the given responses. * diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java index 83f6daaab..3b89d0f58 100644 --- a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java +++ b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java @@ -22,6 +22,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import fake.HttpClientMock; import fake.HttpResponseMock; @@ -57,10 +58,12 @@ public class FlagSetsStreamingTest { private static final String noSetsSplitChange = splitChangeV2("2", "1", "0", "eyJ0cmFmZmljVHlwZU5hbWUiOiJ1c2VyIiwiaWQiOiJkNDMxY2RkMC1iMGJlLTExZWEtOGE4MC0xNjYwYWRhOWNlMzkiLCJuYW1lIjoibWF1cm9famF2YSIsInRyYWZmaWNBbGxvY2F0aW9uIjoxMDAsInRyYWZmaWNBbGxvY2F0aW9uU2VlZCI6LTkyMzkxNDkxLCJzZWVkIjotMTc2OTM3NzYwNCwic3RhdHVzIjoiQUNUSVZFIiwia2lsbGVkIjpmYWxzZSwiZGVmYXVsdFRyZWF0bWVudCI6Im9mZiIsImNoYW5nZU51bWJlciI6MTYwMjc5OTYzODM0NCwiYWxnbyI6MiwiY29uZmlndXJhdGlvbnMiOnt9LCJzZXRzIjpbXSwiY29uZGl0aW9ucyI6W3siY29uZGl0aW9uVHlwZSI6IldISVRFTElTVCIsIm1hdGNoZXJHcm91cCI6eyJjb21iaW5lciI6IkFORCIsIm1hdGNoZXJzIjpbeyJtYXRjaGVyVHlwZSI6IldISVRFTElTVCIsIm5lZ2F0ZSI6ZmFsc2UsIndoaXRlbGlzdE1hdGNoZXJEYXRhIjp7IndoaXRlbGlzdCI6WyJhZG1pbiIsIm1hdXJvIiwibmljbyJdfX1dfSwicGFydGl0aW9ucyI6W3sidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfV0sImxhYmVsIjoid2hpdGVsaXN0ZWQifSx7ImNvbmRpdGlvblR5cGUiOiJST0xMT1VUIiwibWF0Y2hlckdyb3VwIjp7ImNvbWJpbmVyIjoiQU5EIiwibWF0Y2hlcnMiOlt7ImtleVNlbGVjdG9yIjp7InRyYWZmaWNUeXBlIjoidXNlciJ9LCJtYXRjaGVyVHlwZSI6IklOX1NFR01FTlQiLCJuZWdhdGUiOmZhbHNlLCJ1c2VyRGVmaW5lZFNlZ21lbnRNYXRjaGVyRGF0YSI6eyJzZWdtZW50TmFtZSI6Im1hdXItMiJ9fV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6IlY0Iiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJ2NSIsInNpemUiOjB9XSwibGFiZWwiOiJpbiBzZWdtZW50IG1hdXItMiJ9LHsiY29uZGl0aW9uVHlwZSI6IlJPTExPVVQiLCJtYXRjaGVyR3JvdXAiOnsiY29tYmluZXIiOiJBTkQiLCJtYXRjaGVycyI6W3sia2V5U2VsZWN0b3IiOnsidHJhZmZpY1R5cGUiOiJ1c2VyIn0sIm1hdGNoZXJUeXBlIjoiQUxMX0tFWVMiLCJuZWdhdGUiOmZhbHNlfV19LCJwYXJ0aXRpb25zIjpbeyJ0cmVhdG1lbnQiOiJvbiIsInNpemUiOjB9LHsidHJlYXRtZW50Ijoib2ZmIiwic2l6ZSI6MTAwfSx7InRyZWF0bWVudCI6IlY0Iiwic2l6ZSI6MH0seyJ0cmVhdG1lbnQiOiJ2NSIsInNpemUiOjB9XSwibGFiZWwiOiJkZWZhdWx0IHJ1bGUifV19"); private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); + private final AtomicInteger mSplitChangesHits = new AtomicInteger(0); private SplitRoomDatabase mRoomDb; @Before public void setUp() { + mSplitChangesHits.set(0); mRoomDb = DatabaseHelper.getTestDatabase(mContext); mRoomDb.clearAllTables(); } @@ -203,14 +206,45 @@ public void sdkWithSetsConfiguredDeletedDueToNonMatchingSets() throws IOExceptio } @Test - public void sdkWithSetsReceivesSplitKill() { + public void sdkWithSetsReceivesSplitKill() throws IOException, InterruptedException { /* * Initialize a factory with set_1 & set_2 sets configured. * * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]}. It should process it since is part of the config.Sets * - * 2. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" }. The featureFlag should be removed and a fetch should be performed. + * 2. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" }. The featureFlag should be killed and a fetch should be performed. */ + + LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); + SplitClient readyClient = getReadyClient(mContext, mRoomDb, true, streamingData, "set_1", "set_2"); + + // 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]} + CountDownLatch firstUpdate = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(firstUpdate)); + pushToStreaming(streamingData, splitChange2); + boolean firstUpdateAwait = firstUpdate.await(5, TimeUnit.SECONDS); + List entities = mRoomDb.splitDao().getAll(); + boolean firstUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\",\"set_2\"]") && + entities.get(0).getBody().contains("\"killed\":false") && + entities.get(0).getBody().contains("\"name\":\"workm\""); + + // 2. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" } + CountDownLatch secondUpdate = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(secondUpdate)); + pushToStreaming(streamingData, IntegrationHelper.splitKill("5", "workm")); + boolean secondUpdateAwait = secondUpdate.await(5, TimeUnit.SECONDS); + entities = mRoomDb.splitDao().getAll(); + boolean secondUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"killed\":true") && + entities.get(0).getBody().contains("\"name\":\"workm\""); + + // 3. A fetch is triggered due to the SPLIT_KILL + boolean correctAmountOfChanges = mSplitChangesHits.get() == 3; + + assertTrue(firstUpdateAwait); + assertTrue(firstUpdateStored); + assertTrue(secondUpdateAwait); + assertTrue(secondUpdateStored); + assertTrue(correctAmountOfChanges); } @Test @@ -220,6 +254,7 @@ public void sdkWithSetsReceivesSplitKillForNonExistingFeatureFlag() { * * 1. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" }. No changes in storage, a fetch should be performed. */ + } @Nullable @@ -245,8 +280,7 @@ private SplitClient getReadyClient( CountDownLatch authLatch = new CountDownLatch(1); Map responses = new HashMap<>(); responses.put("splitChanges", (uri, httpMethod, body) -> { - String since = getSinceFromUri(uri); - + mSplitChangesHits.incrementAndGet(); return new HttpResponseMock(200, IntegrationHelper.emptySplitChanges(-1, 1)); }); responses.put("mySegments/CUSTOMER_ID", (uri, httpMethod, body) -> new HttpResponseMock(200, IntegrationHelper.emptyMySegments())); From 7138fcbc629b5e924df7fccc53c470ba49a02e79 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 12 Sep 2023 14:26:51 -0300 Subject: [PATCH 11/16] Kill test 2 --- .../sets/FlagSetsStreamingTest.java | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java index 3b89d0f58..736cd2ad5 100644 --- a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java +++ b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java @@ -1,8 +1,8 @@ package tests.integration.sets; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static helper.IntegrationHelper.ResponseClosure.getSinceFromUri; import static helper.IntegrationHelper.splitChangeV2; import android.content.Context; @@ -78,7 +78,7 @@ public void sdkWithoutSetsConfiguredDoesExcludeUpdates() throws IOException, Int * Verify that the feature flag is added. */ LinkedBlockingDeque mStreamingData = new LinkedBlockingDeque<>(); - SplitClient readyClient = getReadyClient(mContext, mRoomDb, true, mStreamingData); + SplitClient readyClient = getReadyClient(mContext, mRoomDb, mStreamingData); int initialSplitsSize = mRoomDb.splitDao().getAll().size(); @@ -108,7 +108,7 @@ public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, Int * */ LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); - SplitClient readyClient = getReadyClient(mContext, mRoomDb, true, streamingData, "set_1", "set_2"); + SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); // 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]} CountDownLatch firstUpdate = new CountDownLatch(1); @@ -159,7 +159,7 @@ public void sdkWithSetsConfiguredDeletedDueToNonMatchingSets() throws IOExceptio */ LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); - SplitClient readyClient = getReadyClient(mContext, mRoomDb, true, streamingData, "set_1", "set_2"); + SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); // 1. Receive a SPLIT_UPDATE with "sets":["set_1", "set_2"] CountDownLatch firstUpdate = new CountDownLatch(1); @@ -212,11 +212,11 @@ public void sdkWithSetsReceivesSplitKill() throws IOException, InterruptedExcept * * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]}. It should process it since is part of the config.Sets * - * 2. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" }. The featureFlag should be killed and a fetch should be performed. + * 2. Receive a SPLIT_KILL with {cn:2, name:"workm", "defaultTreatment":"off" }. The featureFlag should be killed and a fetch should be performed. */ LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); - SplitClient readyClient = getReadyClient(mContext, mRoomDb, true, streamingData, "set_1", "set_2"); + SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); // 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]} CountDownLatch firstUpdate = new CountDownLatch(1); @@ -248,20 +248,39 @@ public void sdkWithSetsReceivesSplitKill() throws IOException, InterruptedExcept } @Test - public void sdkWithSetsReceivesSplitKillForNonExistingFeatureFlag() { + public void sdkWithSetsReceivesSplitKillForNonExistingFeatureFlag() throws IOException, InterruptedException { /* - * Initialize a factory with a & b sets configured. + * Initialize a factory with set_1 & set_2 sets configured. * - * 1. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" }. No changes in storage, a fetch should be performed. + * 1. Receive a SPLIT_KILL with {cn:2, name:"workm", "defaultTreatment":"off" }. No changes in storage, a fetch should be performed. */ - + LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); + SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); + + int initialEntities = mRoomDb.splitDao().getAll().size(); + + // 1. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" } + CountDownLatch firstUpdate = new CountDownLatch(1); + readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(firstUpdate)); + int initialChangesHits = mSplitChangesHits.get(); + pushToStreaming(streamingData, IntegrationHelper.splitKill("2", "workm")); + boolean firstUpdateAwait = firstUpdate.await(5, TimeUnit.SECONDS); + List entities = mRoomDb.splitDao().getAll(); + boolean firstUpdateStored = entities.isEmpty(); + + // 2. A fetch is triggered due to the SPLIT_KILL + int finalChangesHits = mSplitChangesHits.get(); + + assertFalse(firstUpdateAwait); + assertTrue(firstUpdateStored); + assertEquals(initialEntities, 0); + assertTrue(finalChangesHits > initialChangesHits); } @Nullable private SplitClient getReadyClient( Context mContext, SplitRoomDatabase splitRoomDatabase, - boolean streamingEnabled, BlockingQueue streamingData, String... sets) throws IOException, InterruptedException { SplitClientConfig config = new TestableSplitConfigBuilder() @@ -274,7 +293,7 @@ private SplitClient getReadyClient( .addSplitFilter(SplitFilter.bySet(Arrays.asList(sets))) .build()) .featuresRefreshRate(2) - .streamingEnabled(streamingEnabled) + .streamingEnabled(true) .eventFlushInterval(1000) .build(); CountDownLatch authLatch = new CountDownLatch(1); From a16d8f48022cc6b0f5223ddf3c2be3d522077831 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 12 Sep 2023 14:27:07 -0300 Subject: [PATCH 12/16] Kill task improvement --- .../client/service/splits/SplitKillTask.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/split/android/client/service/splits/SplitKillTask.java b/src/main/java/io/split/android/client/service/splits/SplitKillTask.java index bdf91da04..06b8be469 100644 --- a/src/main/java/io/split/android/client/service/splits/SplitKillTask.java +++ b/src/main/java/io/split/android/client/service/splits/SplitKillTask.java @@ -31,18 +31,23 @@ public SplitKillTask(@NonNull SplitsStorage splitsStorage, Split split, public SplitTaskExecutionInfo execute() { try { if (mKilledSplit == null) { - logError("Split name to kill could not be null."); + logError("Feature flag name to kill could not be null."); return SplitTaskExecutionInfo.error(SplitTaskType.SPLIT_KILL); } long changeNumber = mSplitsStorage.getTill(); if (mKilledSplit.changeNumber <= changeNumber) { - Logger.d("Skipping killed split notification for old change number: " + Logger.d("Skipping killed feature flag notification for old change number: " + mKilledSplit.changeNumber); return SplitTaskExecutionInfo.success(SplitTaskType.SPLIT_KILL); } Split splitToKill = mSplitsStorage.get(mKilledSplit.name); + if (splitToKill == null) { + Logger.d("Skipping " + mKilledSplit.name + " since not in storage"); + return SplitTaskExecutionInfo.error(SplitTaskType.SPLIT_KILL); + } + splitToKill.killed = true; splitToKill.defaultTreatment = mKilledSplit.defaultTreatment; splitToKill.changeNumber = mKilledSplit.changeNumber; @@ -50,14 +55,14 @@ public SplitTaskExecutionInfo execute() { mSplitsStorage.updateWithoutChecks(splitToKill); mEventsManager.notifyInternalEvent(SplitInternalEvent.SPLIT_KILLED_NOTIFICATION); } catch (Exception e) { - logError("Unknown error while updating killed split: " + e.getLocalizedMessage()); + logError("Unknown error while updating killed feature flag: " + e.getLocalizedMessage()); return SplitTaskExecutionInfo.error(SplitTaskType.SPLIT_KILL); } - Logger.d("Killed split has been updated"); + Logger.d("Killed feature flag has been updated"); return SplitTaskExecutionInfo.success(SplitTaskType.SPLIT_KILL); } private void logError(String message) { - Logger.e("Error while executing Split kill task: " + message); + Logger.e("Error while executing feature flag kill task: " + message); } } From 14b311688621ea34492dcb7cfd9677d6e7f5a2fe Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 12 Sep 2023 16:44:37 -0300 Subject: [PATCH 13/16] Refactor --- .../sets/FlagSetsStreamingTest.java | 160 +++++------------- 1 file changed, 47 insertions(+), 113 deletions(-) diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java index 736cd2ad5..e4e60f0c3 100644 --- a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java +++ b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java @@ -69,24 +69,16 @@ public void setUp() { } @Test - public void sdkWithoutSetsConfiguredDoesExcludeUpdates() throws IOException, InterruptedException { - /* - * Initialize a factory with streaming enabled and no sets. - * - * Receive notification with new feature flag with no sets. - * - * Verify that the feature flag is added. - */ + public void sdkWithoutSetsConfiguredDoesNotExcludeUpdates() throws IOException, InterruptedException { + // 1. Initialize a factory with streaming enabled and no sets. LinkedBlockingDeque mStreamingData = new LinkedBlockingDeque<>(); SplitClient readyClient = getReadyClient(mContext, mRoomDb, mStreamingData); int initialSplitsSize = mRoomDb.splitDao().getAll().size(); - - // set up update listener CountDownLatch updateLatch = new CountDownLatch(1); readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(updateLatch)); - // push change + // 2. Receive notification with new feature flag with no sets. pushToStreaming(mStreamingData, noSetsSplitChange); boolean updateAwait = updateLatch.await(5, TimeUnit.SECONDS); @@ -97,128 +89,54 @@ public void sdkWithoutSetsConfiguredDoesExcludeUpdates() throws IOException, Int @Test public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, InterruptedException { - /* - * Initialize a factory with set_1 & set_2 sets configured. - * - * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]}. It should process it since is part of the config.Sets - * - * 2. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1"]}. It should process it since is still part of the config.Sets - * - * 3. Receive a SPLIT_UPDATE with {name:"test", "sets":[]}. The featureFlag should be removed. - * - */ LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); - // 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]} - CountDownLatch firstUpdate = new CountDownLatch(1); - readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(firstUpdate)); - pushToStreaming(streamingData, splitChange2); - boolean firstUpdateAwait = firstUpdate.await(5, TimeUnit.SECONDS); - List entities = mRoomDb.splitDao().getAll(); - boolean firstUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\",\"set_2\"]") && - entities.get(0).getBody().contains("\"name\":\"workm\""); + // 1. Receive a SPLIT_UPDATE with "sets":["set_1", "set_2"] + boolean firstChange = processUpdate(readyClient, streamingData, splitChange2, "\"sets\":[\"set_1\",\"set_2\"]", "\"name\":\"workm\""); - // 2. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1"]} - CountDownLatch secondUpdate = new CountDownLatch(1); - readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(secondUpdate)); - pushToStreaming(streamingData, splitChange3); - boolean secondUpdateAwait = secondUpdate.await(5, TimeUnit.SECONDS); - entities = mRoomDb.splitDao().getAll(); - boolean secondUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\"]") && - entities.get(0).getBody().contains("\"name\":\"workm\""); + // 2. Receive a SPLIT_UPDATE with "sets":["set_1"] + boolean secondChange = processUpdate(readyClient, streamingData, splitChange3, "\"sets\":[\"set_1\"]", "\"name\":\"workm\""); - // 3. Receive a SPLIT_UPDATE with {name:"test", "sets":[]} - CountDownLatch thirdUpdate = new CountDownLatch(1); - readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(thirdUpdate)); - pushToStreaming(streamingData, splitChange4None); - boolean thirdUpdateAwait = thirdUpdate.await(5, TimeUnit.SECONDS); - entities = mRoomDb.splitDao().getAll(); - boolean thirdUpdateStored = entities.isEmpty(); + // 3. Receive a SPLIT_UPDATE with "sets":[] + boolean thirdChange = processUpdate(readyClient, streamingData, splitChange4None); - assertTrue(firstUpdateAwait); - assertTrue(firstUpdateStored); - assertTrue(secondUpdateAwait); - assertTrue(secondUpdateStored); - assertTrue(thirdUpdateAwait); - assertTrue(thirdUpdateStored); + assertTrue(firstChange); + assertTrue(secondChange); + assertTrue(thirdChange); } @Test public void sdkWithSetsConfiguredDeletedDueToNonMatchingSets() throws IOException, InterruptedException { - /* - * Initialize a factory with set_1 & set_2 sets configured. - * - * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]}. It should process it since is part of the config.Sets - * - * 2. Receive a SPLIT_UPDATE with "sets":["set_1"]. The feature flag should be updated. - * - * 3. Receive a SPLIT_UPDATE with "sets":["set_3"]. The feature flag should be removed. - * - * 4. Receive a SPLIT_UPDATE with "sets":["set_3", "set_4"] No changes in storage. - */ - LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); // 1. Receive a SPLIT_UPDATE with "sets":["set_1", "set_2"] - CountDownLatch firstUpdate = new CountDownLatch(1); - readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(firstUpdate)); - pushToStreaming(streamingData, splitChange2); - boolean firstUpdateAwait = firstUpdate.await(5, TimeUnit.SECONDS); - List entities = mRoomDb.splitDao().getAll(); - boolean firstUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\",\"set_2\"]") && - entities.get(0).getBody().contains("\"name\":\"workm\""); + boolean firstChange = processUpdate(readyClient, streamingData, splitChange2, "\"sets\":[\"set_1\",\"set_2\"]", "\"name\":\"workm\""); // 2. Receive a SPLIT_UPDATE with "sets":["set_1"] - CountDownLatch secondUpdate = new CountDownLatch(1); - readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(secondUpdate)); - pushToStreaming(streamingData, splitChange3); - boolean secondUpdateAwait = secondUpdate.await(5, TimeUnit.SECONDS); - entities = mRoomDb.splitDao().getAll(); - boolean secondUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"sets\":[\"set_1\"]") && - entities.get(0).getBody().contains("\"name\":\"workm\""); + boolean secondChange = processUpdate(readyClient, streamingData, splitChange3, "\"sets\":[\"set_1\"]", "\"name\":\"workm\""); // 3. Receive a SPLIT_UPDATE with "sets":["set_3"] - CountDownLatch thirdUpdate = new CountDownLatch(1); - readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(thirdUpdate)); - pushToStreaming(streamingData, splitChange4); - boolean thirdUpdateAwait = thirdUpdate.await(5, TimeUnit.SECONDS); - entities = mRoomDb.splitDao().getAll(); - boolean thirdUpdateStored = entities.size() == 0; + boolean thirdChange = processUpdate(readyClient, streamingData, splitChange4); // 4. Receive a SPLIT_UPDATE with "sets":["set_3", "set_4"] - CountDownLatch fourthUpdate = new CountDownLatch(1); - readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(fourthUpdate)); - pushToStreaming(streamingData, splitChange5); - boolean fourthUpdateAwait = fourthUpdate.await(5, TimeUnit.SECONDS); - entities = mRoomDb.splitDao().getAll(); - boolean fourthUpdateStored = entities.size() == 0; + boolean fourthChange = processUpdate(readyClient, streamingData, splitChange5); - assertTrue(firstUpdateAwait); - assertTrue(firstUpdateStored); - assertTrue(secondUpdateAwait); - assertTrue(secondUpdateStored); - assertTrue(thirdUpdateAwait); - assertTrue(thirdUpdateStored); - assertTrue(fourthUpdateAwait); - assertTrue(fourthUpdateStored); + assertTrue(firstChange); + assertTrue(secondChange); + assertTrue(thirdChange); + assertTrue(fourthChange); } @Test public void sdkWithSetsReceivesSplitKill() throws IOException, InterruptedException { - /* - * Initialize a factory with set_1 & set_2 sets configured. - * - * 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]}. It should process it since is part of the config.Sets - * - * 2. Receive a SPLIT_KILL with {cn:2, name:"workm", "defaultTreatment":"off" }. The featureFlag should be killed and a fetch should be performed. - */ + // 1. Initialize a factory with set_1 & set_2 sets configured. LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); - // 1. Receive a SPLIT_UPDATE with {name:"test", "sets":["set_1", "set_2"]} + // 2. Receive a SPLIT_UPDATE with "sets":["set_1", "set_2"] CountDownLatch firstUpdate = new CountDownLatch(1); readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(firstUpdate)); pushToStreaming(streamingData, splitChange2); @@ -228,7 +146,7 @@ public void sdkWithSetsReceivesSplitKill() throws IOException, InterruptedExcept entities.get(0).getBody().contains("\"killed\":false") && entities.get(0).getBody().contains("\"name\":\"workm\""); - // 2. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" } + // 3. Receive a SPLIT_KILL for workm CountDownLatch secondUpdate = new CountDownLatch(1); readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(secondUpdate)); pushToStreaming(streamingData, IntegrationHelper.splitKill("5", "workm")); @@ -237,7 +155,7 @@ public void sdkWithSetsReceivesSplitKill() throws IOException, InterruptedExcept boolean secondUpdateStored = entities.size() == 1 && entities.get(0).getBody().contains("\"killed\":true") && entities.get(0).getBody().contains("\"name\":\"workm\""); - // 3. A fetch is triggered due to the SPLIT_KILL + // 4. A fetch is triggered due to the SPLIT_KILL boolean correctAmountOfChanges = mSplitChangesHits.get() == 3; assertTrue(firstUpdateAwait); @@ -249,17 +167,14 @@ public void sdkWithSetsReceivesSplitKill() throws IOException, InterruptedExcept @Test public void sdkWithSetsReceivesSplitKillForNonExistingFeatureFlag() throws IOException, InterruptedException { - /* - * Initialize a factory with set_1 & set_2 sets configured. - * - * 1. Receive a SPLIT_KILL with {cn:2, name:"workm", "defaultTreatment":"off" }. No changes in storage, a fetch should be performed. - */ + + // 1. Initialize a factory with set_1 & set_2 sets configured. LinkedBlockingDeque streamingData = new LinkedBlockingDeque<>(); SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); int initialEntities = mRoomDb.splitDao().getAll().size(); - // 1. Receive a SPLIT_KILL with {cn:2, name:"test", "defaultTreatment":"off" } + // 2. Receive a SPLIT_KILL; storage is not modified since flag is not present. CountDownLatch firstUpdate = new CountDownLatch(1); readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(firstUpdate)); int initialChangesHits = mSplitChangesHits.get(); @@ -268,7 +183,7 @@ public void sdkWithSetsReceivesSplitKillForNonExistingFeatureFlag() throws IOExc List entities = mRoomDb.splitDao().getAll(); boolean firstUpdateStored = entities.isEmpty(); - // 2. A fetch is triggered due to the SPLIT_KILL + // 3. A fetch is triggered due to the SPLIT_KILL int finalChangesHits = mSplitChangesHits.get(); assertFalse(firstUpdateAwait); @@ -342,4 +257,23 @@ private static void pushToStreaming(LinkedBlockingDeque streamingData, S } catch (InterruptedException ignored) { } } + + private boolean processUpdate(SplitClient client, LinkedBlockingDeque streamingData, String splitChange, String... expectedContents) throws InterruptedException { + CountDownLatch updateLatch = new CountDownLatch(1); + client.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(updateLatch)); + pushToStreaming(streamingData, splitChange); + boolean updateAwaited = updateLatch.await(5, TimeUnit.SECONDS); + List entities = mRoomDb.splitDao().getAll(); + + if (expectedContents == null || expectedContents.length == 0) { + return updateAwaited && entities.isEmpty(); + } + + boolean contentMatches = true; + for (String expected : expectedContents) { + contentMatches = contentMatches && entities.size() == 1 && entities.get(0).getBody().contains(expected); + } + + return updateAwaited && contentMatches; + } } From b9c31b15e49d4a669dfc2e7a45e304fe41c05cba Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Tue, 12 Sep 2023 18:06:05 -0300 Subject: [PATCH 14/16] Better comments --- .../integration/sets/FlagSetsPollingTest.java | 40 +++++++------------ .../sets/FlagSetsStreamingTest.java | 12 +++++- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java index dfc0a8b98..1458a4016 100644 --- a/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java +++ b/src/androidTest/java/tests/integration/sets/FlagSetsPollingTest.java @@ -64,31 +64,25 @@ public void setUp() throws Exception { @Test public void featureFlagIsUpdatedAccordingToSetsWhenTheyAreConfigured() throws IOException, InterruptedException { - /* - This test creates a factory with 2 configured sets. - - The first split change will have 2 splits (workm and workm_set_3), one that belongs to set_1 and set_2 and one that belongs to set_3; - -> it should be added to storage - - The second change will have 1 split (workm) that belongs to set_1 only. - -> it should remain in storage and be updated - - The third change will have 1 split (workm) that belongs to set_3 only. - -> it should be removed from storage - */ - + // 1. Initialize a factory with polling and sets set_1 & set_2 configured. createFactory(mContext, mRoomDb, false, "set_1", "set_2"); + // 2. Receive split change with 1 split belonging to set_1 & set_2 and one belonging to set_3 + // -> only one feature flag should be added boolean awaitFirst = firstChangeLatch.await(5, TimeUnit.SECONDS); Thread.sleep(200); int firstSize = mRoomDb.splitDao().getAll().size(); boolean firstSetsCorrect = mRoomDb.splitDao().getAll().get(0).getBody().contains("[\"set_1\",\"set_2\"]"); + // 3. Receive split change with 1 split belonging to set_1 only + // -> the feature flag should be updated boolean awaitSecond = secondChangeLatch.await(5, TimeUnit.SECONDS); Thread.sleep(200); int secondSize = mRoomDb.splitDao().getAll().size(); boolean secondSetsCorrect = mRoomDb.splitDao().getAll().get(0).getBody().contains("[\"set_1\"]"); + // 4. Receive split change with 1 split belonging to set_3 only + // -> the feature flag should be removed boolean awaitThird = thirdChangeLatch.await(5, TimeUnit.SECONDS); Thread.sleep(200); int thirdSize = mRoomDb.splitDao().getAll().size(); @@ -109,21 +103,11 @@ public void featureFlagIsUpdatedAccordingToSetsWhenTheyAreConfigured() throws IO @Test public void featureFlagSetsAreIgnoredWhenSetsAreNotConfigured() throws IOException, InterruptedException { - /* - This test creates a factory with no sets configured. - - The first split change will have 2 splits (workm and workm_set_3), one that belongs to set_1 and set_2 and one that belongs to set_3; - -> both should be added to storage. - - The second change will have 1 split (workm) that belongs to set_1 only. - -> that split should be updated. - - The third change will have 1 split (workm) that belongs to set_3 only. - -> that split should be updated. - */ - + // 1. Initialize a factory with polling and sets set_1 & set_2 configured. createFactory(mContext, mRoomDb, false); + // 2. Receive split change with 1 split belonging to set_1 & set_2 and one belonging to set_3 + // -> only one feature flag should be added boolean awaitFirst = firstChangeLatch.await(5, TimeUnit.SECONDS); Thread.sleep(500); int firstSize = mRoomDb.splitDao().getAll().size(); @@ -131,6 +115,8 @@ public void featureFlagSetsAreIgnoredWhenSetsAreNotConfigured() throws IOExcepti boolean firstSetsCorrect = firstEntities.get(0).getBody().contains("[\"set_1\",\"set_2\"]") && firstEntities.get(1).getBody().contains("[\"set_3\"]"); + // 3. Receive split change with 1 split belonging to set_1 only + // -> the feature flag should be updated boolean awaitSecond = secondChangeLatch.await(5, TimeUnit.SECONDS); Thread.sleep(500); int secondSize = mRoomDb.splitDao().getAll().size(); @@ -145,6 +131,8 @@ public void featureFlagSetsAreIgnoredWhenSetsAreNotConfigured() throws IOExcepti Logger.w("body0: " + body0); Logger.w("body1: " + body1); + // 4. Receive split change with 1 split belonging to set_3 only + // -> the feature flag should be removed boolean awaitThird = thirdChangeLatch.await(5, TimeUnit.SECONDS); Thread.sleep(500); List thirdEntities = mRoomDb.splitDao().getAll(); diff --git a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java index e4e60f0c3..d61a46e06 100644 --- a/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java +++ b/src/androidTest/java/tests/integration/sets/FlagSetsStreamingTest.java @@ -79,6 +79,7 @@ public void sdkWithoutSetsConfiguredDoesNotExcludeUpdates() throws IOException, readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(updateLatch)); // 2. Receive notification with new feature flag with no sets. + // 3. Assert that the update is processed and the split is stored. pushToStreaming(mStreamingData, noSetsSplitChange); boolean updateAwait = updateLatch.await(5, TimeUnit.SECONDS); @@ -93,12 +94,15 @@ public void sdkWithSetsConfiguredDeletedDueToEmptySets() throws IOException, Int SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); // 1. Receive a SPLIT_UPDATE with "sets":["set_1", "set_2"] + // -> flag is added to the storage boolean firstChange = processUpdate(readyClient, streamingData, splitChange2, "\"sets\":[\"set_1\",\"set_2\"]", "\"name\":\"workm\""); // 2. Receive a SPLIT_UPDATE with "sets":["set_1"] + // -> flag is updated in storage boolean secondChange = processUpdate(readyClient, streamingData, splitChange3, "\"sets\":[\"set_1\"]", "\"name\":\"workm\""); // 3. Receive a SPLIT_UPDATE with "sets":[] + // -> flag is removed from storage boolean thirdChange = processUpdate(readyClient, streamingData, splitChange4None); assertTrue(firstChange); @@ -112,15 +116,19 @@ public void sdkWithSetsConfiguredDeletedDueToNonMatchingSets() throws IOExceptio SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); // 1. Receive a SPLIT_UPDATE with "sets":["set_1", "set_2"] + // -> workm is added to the storage boolean firstChange = processUpdate(readyClient, streamingData, splitChange2, "\"sets\":[\"set_1\",\"set_2\"]", "\"name\":\"workm\""); // 2. Receive a SPLIT_UPDATE with "sets":["set_1"] + // -> workm sets are updated to set_1 only boolean secondChange = processUpdate(readyClient, streamingData, splitChange3, "\"sets\":[\"set_1\"]", "\"name\":\"workm\""); // 3. Receive a SPLIT_UPDATE with "sets":["set_3"] + // -> workm is removed from the storage boolean thirdChange = processUpdate(readyClient, streamingData, splitChange4); // 4. Receive a SPLIT_UPDATE with "sets":["set_3", "set_4"] + // -> workm is not added to the storage boolean fourthChange = processUpdate(readyClient, streamingData, splitChange5); assertTrue(firstChange); @@ -137,6 +145,7 @@ public void sdkWithSetsReceivesSplitKill() throws IOException, InterruptedExcept SplitClient readyClient = getReadyClient(mContext, mRoomDb, streamingData, "set_1", "set_2"); // 2. Receive a SPLIT_UPDATE with "sets":["set_1", "set_2"] + // -> flag is added to the storage CountDownLatch firstUpdate = new CountDownLatch(1); readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(firstUpdate)); pushToStreaming(streamingData, splitChange2); @@ -146,7 +155,8 @@ public void sdkWithSetsReceivesSplitKill() throws IOException, InterruptedExcept entities.get(0).getBody().contains("\"killed\":false") && entities.get(0).getBody().contains("\"name\":\"workm\""); - // 3. Receive a SPLIT_KILL for workm + // 3. Receive a SPLIT_KILL for flag + // -> flag is updated in storage CountDownLatch secondUpdate = new CountDownLatch(1); readyClient.on(SplitEvent.SDK_UPDATE, TestingHelper.testTask(secondUpdate)); pushToStreaming(streamingData, IntegrationHelper.splitKill("5", "workm")); From 3168519712016d513c83c2416a9d56545ae55401 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Wed, 13 Sep 2023 10:09:51 -0300 Subject: [PATCH 15/16] Minify json --- .../assets/split_changes_flag_set-0.json | 109 +-------- .../assets/split_changes_flag_set-1.json | 109 +-------- .../assets/split_changes_flag_set-2.json | 211 +----------------- 3 files changed, 3 insertions(+), 426 deletions(-) diff --git a/src/androidTest/assets/split_changes_flag_set-0.json b/src/androidTest/assets/split_changes_flag_set-0.json index b3c0556d1..93be5fda4 100644 --- a/src/androidTest/assets/split_changes_flag_set-0.json +++ b/src/androidTest/assets/split_changes_flag_set-0.json @@ -1,108 +1 @@ -{ - "splits": [ - { - "trafficTypeName": "client", - "name": "workm", - "trafficAllocation": 100, - "trafficAllocationSeed": 147392224, - "seed": 524417105, - "status": "ACTIVE", - "killed": false, - "defaultTreatment": "on", - "changeNumber": 1602798638344, - "algo": 2, - "configurations": {}, - "sets": ["set_3"], - "conditions": [ - { - "conditionType": "ROLLOUT", - "matcherGroup": { - "combiner": "AND", - "matchers": [ - { - "keySelector": { - "trafficType": "client", - "attribute": null - }, - "matcherType": "IN_SEGMENT", - "negate": false, - "userDefinedSegmentMatcherData": { - "segmentName": "new_segment" - }, - "whitelistMatcherData": null, - "unaryNumericMatcherData": null, - "betweenMatcherData": null, - "booleanMatcherData": null, - "dependencyMatcherData": null, - "stringMatcherData": null - } - ] - }, - "partitions": [ - { - "treatment": "on", - "size": 0 - }, - { - "treatment": "off", - "size": 0 - }, - { - "treatment": "free", - "size": 100 - }, - { - "treatment": "conta", - "size": 0 - } - ], - "label": "in segment new_segment" - }, - { - "conditionType": "ROLLOUT", - "matcherGroup": { - "combiner": "AND", - "matchers": [ - { - "keySelector": { - "trafficType": "client", - "attribute": null - }, - "matcherType": "ALL_KEYS", - "negate": false, - "userDefinedSegmentMatcherData": null, - "whitelistMatcherData": null, - "unaryNumericMatcherData": null, - "betweenMatcherData": null, - "booleanMatcherData": null, - "dependencyMatcherData": null, - "stringMatcherData": null - } - ] - }, - "partitions": [ - { - "treatment": "on", - "size": 100 - }, - { - "treatment": "off", - "size": 0 - }, - { - "treatment": "free", - "size": 0 - }, - { - "treatment": "conta", - "size": 0 - } - ], - "label": "default rule" - } - ] - } - ], - "since": 1602797638344, - "till": 1602798638344 -} +{"splits":[{"trafficTypeName":"client","name":"workm","trafficAllocation":100,"trafficAllocationSeed":147392224,"seed":524417105,"status":"ACTIVE","killed":false,"defaultTreatment":"on","changeNumber":1602798638344,"algo":2,"configurations":{},"sets":["set_3"],"conditions":[{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"client","attribute":null},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"new_segment"},"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null,"booleanMatcherData":null,"dependencyMatcherData":null,"stringMatcherData":null}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":0},{"treatment":"free","size":100},{"treatment":"conta","size":0}],"label":"in segment new_segment"},{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"client","attribute":null},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":null,"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null,"booleanMatcherData":null,"dependencyMatcherData":null,"stringMatcherData":null}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0},{"treatment":"free","size":0},{"treatment":"conta","size":0}],"label":"default rule"}]}],"since":1602797638344,"till":1602798638344} diff --git a/src/androidTest/assets/split_changes_flag_set-1.json b/src/androidTest/assets/split_changes_flag_set-1.json index 6ed91ced6..67f617712 100644 --- a/src/androidTest/assets/split_changes_flag_set-1.json +++ b/src/androidTest/assets/split_changes_flag_set-1.json @@ -1,108 +1 @@ -{ - "splits": [ - { - "trafficTypeName": "client", - "name": "workm", - "trafficAllocation": 100, - "trafficAllocationSeed": 147392224, - "seed": 524417105, - "status": "ACTIVE", - "killed": false, - "defaultTreatment": "on", - "changeNumber": 1602797638344, - "algo": 2, - "configurations": {}, - "sets": ["set_1"], - "conditions": [ - { - "conditionType": "ROLLOUT", - "matcherGroup": { - "combiner": "AND", - "matchers": [ - { - "keySelector": { - "trafficType": "client", - "attribute": null - }, - "matcherType": "IN_SEGMENT", - "negate": false, - "userDefinedSegmentMatcherData": { - "segmentName": "new_segment" - }, - "whitelistMatcherData": null, - "unaryNumericMatcherData": null, - "betweenMatcherData": null, - "booleanMatcherData": null, - "dependencyMatcherData": null, - "stringMatcherData": null - } - ] - }, - "partitions": [ - { - "treatment": "on", - "size": 0 - }, - { - "treatment": "off", - "size": 0 - }, - { - "treatment": "free", - "size": 100 - }, - { - "treatment": "conta", - "size": 0 - } - ], - "label": "in segment new_segment" - }, - { - "conditionType": "ROLLOUT", - "matcherGroup": { - "combiner": "AND", - "matchers": [ - { - "keySelector": { - "trafficType": "client", - "attribute": null - }, - "matcherType": "ALL_KEYS", - "negate": false, - "userDefinedSegmentMatcherData": null, - "whitelistMatcherData": null, - "unaryNumericMatcherData": null, - "betweenMatcherData": null, - "booleanMatcherData": null, - "dependencyMatcherData": null, - "stringMatcherData": null - } - ] - }, - "partitions": [ - { - "treatment": "on", - "size": 100 - }, - { - "treatment": "off", - "size": 0 - }, - { - "treatment": "free", - "size": 0 - }, - { - "treatment": "conta", - "size": 0 - } - ], - "label": "default rule" - } - ] - } - ], - "since": 1602796638344, - "till": 1602797638344 -} +{"splits":[{"trafficTypeName":"client","name":"workm","trafficAllocation":100,"trafficAllocationSeed":147392224,"seed":524417105,"status":"ACTIVE","killed":false,"defaultTreatment":"on","changeNumber":1602797638344,"algo":2,"configurations":{},"sets":["set_1"],"conditions":[{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"client","attribute":null},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"new_segment"},"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null,"booleanMatcherData":null,"dependencyMatcherData":null,"stringMatcherData":null}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":0},{"treatment":"free","size":100},{"treatment":"conta","size":0}],"label":"in segment new_segment"},{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"client","attribute":null},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":null,"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null,"booleanMatcherData":null,"dependencyMatcherData":null,"stringMatcherData":null}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0},{"treatment":"free","size":0},{"treatment":"conta","size":0}],"label":"default rule"}]}],"since":1602796638344,"till":1602797638344} diff --git a/src/androidTest/assets/split_changes_flag_set-2.json b/src/androidTest/assets/split_changes_flag_set-2.json index 2d28b7582..a96e3e209 100644 --- a/src/androidTest/assets/split_changes_flag_set-2.json +++ b/src/androidTest/assets/split_changes_flag_set-2.json @@ -1,210 +1 @@ -{ - "splits": [ - { - "trafficTypeName": "client", - "name": "workm", - "trafficAllocation": 100, - "trafficAllocationSeed": 147392224, - "seed": 524417105, - "status": "ACTIVE", - "killed": false, - "defaultTreatment": "on", - "changeNumber": 1602796638344, - "algo": 2, - "configurations": {}, - "sets": ["set_1", "set_2"], - "conditions": [ - { - "conditionType": "ROLLOUT", - "matcherGroup": { - "combiner": "AND", - "matchers": [ - { - "keySelector": { - "trafficType": "client", - "attribute": null - }, - "matcherType": "IN_SEGMENT", - "negate": false, - "userDefinedSegmentMatcherData": { - "segmentName": "new_segment" - }, - "whitelistMatcherData": null, - "unaryNumericMatcherData": null, - "betweenMatcherData": null, - "booleanMatcherData": null, - "dependencyMatcherData": null, - "stringMatcherData": null - } - ] - }, - "partitions": [ - { - "treatment": "on", - "size": 0 - }, - { - "treatment": "off", - "size": 0 - }, - { - "treatment": "free", - "size": 100 - }, - { - "treatment": "conta", - "size": 0 - } - ], - "label": "in segment new_segment" - }, - { - "conditionType": "ROLLOUT", - "matcherGroup": { - "combiner": "AND", - "matchers": [ - { - "keySelector": { - "trafficType": "client", - "attribute": null - }, - "matcherType": "ALL_KEYS", - "negate": false, - "userDefinedSegmentMatcherData": null, - "whitelistMatcherData": null, - "unaryNumericMatcherData": null, - "betweenMatcherData": null, - "booleanMatcherData": null, - "dependencyMatcherData": null, - "stringMatcherData": null - } - ] - }, - "partitions": [ - { - "treatment": "on", - "size": 100 - }, - { - "treatment": "off", - "size": 0 - }, - { - "treatment": "free", - "size": 0 - }, - { - "treatment": "conta", - "size": 0 - } - ], - "label": "default rule" - } - ] - }, - { - "trafficTypeName": "client", - "name": "workm_set_3", - "trafficAllocation": 100, - "trafficAllocationSeed": 147392224, - "seed": 524417105, - "status": "ACTIVE", - "killed": false, - "defaultTreatment": "on", - "changeNumber": 1602796638344, - "algo": 2, - "configurations": {}, - "sets": ["set_3"], - "conditions": [ - { - "conditionType": "ROLLOUT", - "matcherGroup": { - "combiner": "AND", - "matchers": [ - { - "keySelector": { - "trafficType": "client", - "attribute": null - }, - "matcherType": "IN_SEGMENT", - "negate": false, - "userDefinedSegmentMatcherData": { - "segmentName": "new_segment" - }, - "whitelistMatcherData": null, - "unaryNumericMatcherData": null, - "betweenMatcherData": null, - "booleanMatcherData": null, - "dependencyMatcherData": null, - "stringMatcherData": null - } - ] - }, - "partitions": [ - { - "treatment": "on", - "size": 0 - }, - { - "treatment": "off", - "size": 0 - }, - { - "treatment": "free", - "size": 100 - }, - { - "treatment": "conta", - "size": 0 - } - ], - "label": "in segment new_segment" - }, - { - "conditionType": "ROLLOUT", - "matcherGroup": { - "combiner": "AND", - "matchers": [ - { - "keySelector": { - "trafficType": "client", - "attribute": null - }, - "matcherType": "ALL_KEYS", - "negate": false, - "userDefinedSegmentMatcherData": null, - "whitelistMatcherData": null, - "unaryNumericMatcherData": null, - "betweenMatcherData": null, - "booleanMatcherData": null, - "dependencyMatcherData": null, - "stringMatcherData": null - } - ] - }, - "partitions": [ - { - "treatment": "on", - "size": 100 - }, - { - "treatment": "off", - "size": 0 - }, - { - "treatment": "free", - "size": 0 - }, - { - "treatment": "conta", - "size": 0 - } - ], - "label": "default rule" - } - ] - } - ], - "since": -1, - "till": 1602796638344 -} +{"splits":[{"trafficTypeName":"client","name":"workm","trafficAllocation":100,"trafficAllocationSeed":147392224,"seed":524417105,"status":"ACTIVE","killed":false,"defaultTreatment":"on","changeNumber":1602796638344,"algo":2,"configurations":{},"sets":["set_1","set_2"],"conditions":[{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"client","attribute":null},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"new_segment"},"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null,"booleanMatcherData":null,"dependencyMatcherData":null,"stringMatcherData":null}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":0},{"treatment":"free","size":100},{"treatment":"conta","size":0}],"label":"in segment new_segment"},{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"client","attribute":null},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":null,"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null,"booleanMatcherData":null,"dependencyMatcherData":null,"stringMatcherData":null}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0},{"treatment":"free","size":0},{"treatment":"conta","size":0}],"label":"default rule"}]},{"trafficTypeName":"client","name":"workm_set_3","trafficAllocation":100,"trafficAllocationSeed":147392224,"seed":524417105,"status":"ACTIVE","killed":false,"defaultTreatment":"on","changeNumber":1602796638344,"algo":2,"configurations":{},"sets":["set_3"],"conditions":[{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"client","attribute":null},"matcherType":"IN_SEGMENT","negate":false,"userDefinedSegmentMatcherData":{"segmentName":"new_segment"},"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null,"booleanMatcherData":null,"dependencyMatcherData":null,"stringMatcherData":null}]},"partitions":[{"treatment":"on","size":0},{"treatment":"off","size":0},{"treatment":"free","size":100},{"treatment":"conta","size":0}],"label":"in segment new_segment"},{"conditionType":"ROLLOUT","matcherGroup":{"combiner":"AND","matchers":[{"keySelector":{"trafficType":"client","attribute":null},"matcherType":"ALL_KEYS","negate":false,"userDefinedSegmentMatcherData":null,"whitelistMatcherData":null,"unaryNumericMatcherData":null,"betweenMatcherData":null,"booleanMatcherData":null,"dependencyMatcherData":null,"stringMatcherData":null}]},"partitions":[{"treatment":"on","size":100},{"treatment":"off","size":0},{"treatment":"free","size":0},{"treatment":"conta","size":0}],"label":"default rule"}]}],"since":-1,"till":1602796638344} From 95c88ee4f3a99876463bd3f6acd787c847f99875 Mon Sep 17 00:00:00 2001 From: Gaston Thea Date: Wed, 13 Sep 2023 11:34:34 -0300 Subject: [PATCH 16/16] Fix name --- .../client/service/splits/FeatureFlagProcessStrategy.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/io/split/android/client/service/splits/FeatureFlagProcessStrategy.java b/src/main/java/io/split/android/client/service/splits/FeatureFlagProcessStrategy.java index fafc48806..2f50f6bbb 100644 --- a/src/main/java/io/split/android/client/service/splits/FeatureFlagProcessStrategy.java +++ b/src/main/java/io/split/android/client/service/splits/FeatureFlagProcessStrategy.java @@ -6,7 +6,6 @@ import io.split.android.client.dtos.Split; import io.split.android.client.dtos.Status; -import io.split.android.client.utils.logger.Logger; interface FeatureFlagProcessStrategy { @@ -37,7 +36,6 @@ class NamesProcessStrategy implements FeatureFlagProcessStrategy { @Override public void process(List activeFeatureFlags, List archivedFeatureFlags, Split featureFlag) { - Logger.v("Processing with names"); // If the feature flag name is in the filter, we process it according to its status. Otherwise it is ignored if (mConfiguredValues.contains(featureFlag.name)) { mStatusProcessStrategy.process(activeFeatureFlags, archivedFeatureFlags, featureFlag); @@ -57,7 +55,6 @@ class SetsProcessStrategy implements FeatureFlagProcessStrategy { @Override public void process(List activeFeatureFlags, List archivedFeatureFlags, Split featureFlag) { - Logger.v("Processing with sets"); if (featureFlag.sets == null || featureFlag.sets.isEmpty()) { archivedFeatureFlags.add(featureFlag); return;