Skip to content

Commit

Permalink
FlagSetsFilter component (#542)
Browse files Browse the repository at this point in the history
FlagSetsFilter component
  • Loading branch information
gthea authored Sep 21, 2023
2 parents 776e30b + ee1d73c commit 5e93c2d
Show file tree
Hide file tree
Showing 34 changed files with 393 additions and 188 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
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.AtomicReference;

import fake.HttpClientMock;
import fake.HttpResponseMock;
Expand Down Expand Up @@ -46,6 +48,7 @@ public class FlagSetsPollingTest {
private CountDownLatch secondChangeLatch;
private CountDownLatch thirdChangeLatch;
private SplitRoomDatabase mRoomDb;
private volatile String mSplitChangesUri;

@Before
public void setUp() throws Exception {
Expand Down Expand Up @@ -157,6 +160,18 @@ public void featureFlagSetsAreIgnoredWhenSetsAreNotConfigured() throws IOExcepti
assertTrue(awaitHits);
}

@Test
public void queryStringIsBuiltCorrectlyWhenSetsAreConfigured() throws IOException, InterruptedException {
createFactory(mContext, mRoomDb, "set_x", "set_x", "set_3", "set_2", "set_3", "set_ww", "invalid+");

boolean awaitFirst = firstChangeLatch.await(5, TimeUnit.SECONDS);

String uri = mSplitChangesUri;

assertTrue(awaitFirst);
assertEquals("https://sdk.split.io/api/splitChanges?since=-1&sets=set_2,set_3,set_ww,set_x", uri);
}

private SplitFactory createFactory(
Context mContext,
SplitRoomDatabase splitRoomDatabase,
Expand All @@ -169,6 +184,8 @@ private SplitFactory createFactory(
.impressionsCountersRefreshRate(1000)
.syncConfig(SyncConfig.builder()
.addSplitFilter(SplitFilter.bySet(Arrays.asList(sets)))
.addSplitFilter(SplitFilter.byName(Arrays.asList("workm", "workm_set_3"))) // added to test that this filter is ignored
.addSplitFilter(SplitFilter.byPrefix(Collections.singletonList("pref"))) // added to test that this filter is ignored
.build())
.featuresRefreshRate(2)
.streamingEnabled(false)
Expand All @@ -177,8 +194,8 @@ private SplitFactory createFactory(

Map<String, IntegrationHelper.ResponseClosure> responses = new HashMap<>();
responses.put("splitChanges", (uri, httpMethod, body) -> {
mSplitChangesUri = uri.toString();
String since = getSinceFromUri(uri);

hitsLatch.countDown();
if (since.equals("-1")) {
firstChangeLatch.countDown();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ class UserConsentModeDebugTest {
} else if (uri.path.contains("/splitChanges")) {
if (mChangeHit == 0) {
mChangeHit+=1
return getSplitsMockResponse("", "")
return getSplitsMockResponse("")
}
return HttpResponseMock(200, IntegrationHelper.emptySplitChanges(99999999, 99999999))
} else if (uri.path.contains("/testImpressions/bulk")) {
Expand Down Expand Up @@ -259,7 +259,7 @@ class UserConsentModeDebugTest {
}
}

private fun getSplitsMockResponse(since: String, till: String): HttpResponseMock {
private fun getSplitsMockResponse(since: String): HttpResponseMock {
return HttpResponseMock(200, loadSplitChanges())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ class UserConsentModeNoneTest {
} else if (uri.path.contains("/splitChanges")) {
if (mChangeHit == 0) {
mChangeHit+=1
return getSplitsMockResponse("", "")
return getSplitsMockResponse("")
}
return HttpResponseMock(200, IntegrationHelper.emptySplitChanges(99999999, 99999999))
} else if (uri.path.contains("/testImpressions/bulk")) {
Expand Down Expand Up @@ -260,7 +260,7 @@ class UserConsentModeNoneTest {
}
}

private fun getSplitsMockResponse(since: String, till: String): HttpResponseMock {
private fun getSplitsMockResponse(since: String): HttpResponseMock {
return HttpResponseMock(200, loadSplitChanges())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ class UserConsentModeOptimizedTest {
} else if (uri.path.contains("/splitChanges")) {
if (mChangeHit == 0) {
mChangeHit+=1
return getSplitsMockResponse("", "")
return getSplitsMockResponse("")
}
return HttpResponseMock(200, IntegrationHelper.emptySplitChanges(99999999, 99999999))
} else if (uri.path.contains("/testImpressions/bulk")) {
Expand Down Expand Up @@ -270,7 +270,7 @@ class UserConsentModeOptimizedTest {
}
}

private fun getSplitsMockResponse(since: String, till: String): HttpResponseMock {
private fun getSplitsMockResponse(since: String): HttpResponseMock {
return HttpResponseMock(200, loadSplitChanges())
}

Expand Down
10 changes: 10 additions & 0 deletions src/main/java/io/split/android/client/FeatureFlagFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.split.android.client;

import java.util.Set;

interface FeatureFlagFilter {

boolean intersect(Set<String> values);

boolean intersect(String values);
}
6 changes: 6 additions & 0 deletions src/main/java/io/split/android/client/FlagSetsFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.split.android.client;

import java.util.Set;

public interface FlagSetsFilter extends FeatureFlagFilter {
}
48 changes: 48 additions & 0 deletions src/main/java/io/split/android/client/FlagSetsFilterImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.split.android.client;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class FlagSetsFilterImpl implements FlagSetsFilter {

private final boolean mShouldFilter;
private final Set<String> mFlagSets;

public FlagSetsFilterImpl(Collection<String> flagSets) {
mFlagSets = new HashSet<>(flagSets);
mShouldFilter = !mFlagSets.isEmpty();
}

@Override
public boolean intersect(Set<String> sets) {
if (!mShouldFilter) {
return true;
}

if (sets == null) {
return false;
}

for (String set : sets) {
if (mFlagSets.contains(set)) {
return true;
}
}

return false;
}

@Override
public boolean intersect(String set) {
if (!mShouldFilter) {
return true;
}

if (set == null) {
return false;
}

return mFlagSets.contains(set);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.google.common.base.Preconditions.checkNotNull;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.Set;

Expand Down Expand Up @@ -59,7 +60,7 @@ public SplitClientFactoryImpl(@NonNull SplitFactory splitFactory,
@NonNull KeyValidator keyValidator,
@NonNull EventsTracker eventsTracker,
@NonNull ImpressionListener customerImpressionListener,
@NonNull Set<String> configuredFlagSets) {
@Nullable FlagSetsFilter flagSetsFilter) {
mSplitFactory = checkNotNull(splitFactory);
mClientContainer = checkNotNull(clientContainer);
mConfig = checkNotNull(config);
Expand All @@ -85,7 +86,7 @@ public SplitClientFactoryImpl(@NonNull SplitFactory splitFactory,
new AttributesMergerImpl(),
mStorageContainer.getTelemetryStorage(),
mSplitParser,
configuredFlagSets,
flagSetsFilter,
splitsStorage
);
}
Expand Down
17 changes: 6 additions & 11 deletions src/main/java/io/split/android/client/SplitFactoryHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
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;

Expand Down Expand Up @@ -429,16 +427,13 @@ Pair<Map<SplitFilter.Type, SplitFilter>, String> getFilterConfiguration(SyncConf
return new Pair<>(groupedFilters, splitsFilterQueryString);
}

@NonNull
Set<String> getConfiguredFlagSets(Map<SplitFilter.Type, SplitFilter> filters) {
Set<String> configuredFlagSets;
SplitFilter flagSetSplitFilter = filters.get(SplitFilter.Type.BY_SET);
if (flagSetSplitFilter != null) {
configuredFlagSets = new HashSet<>(flagSetSplitFilter.getValues());
} else {
configuredFlagSets = new HashSet<>();
@Nullable
FlagSetsFilter getFlagSetsFilter(Map<SplitFilter.Type, SplitFilter> filters) {
if (filters.get(SplitFilter.Type.BY_SET) != null) {
return new FlagSetsFilterImpl(filters.get(SplitFilter.Type.BY_SET).getValues());
}
return configuredFlagSets;

return null;
}

private TelemetryStorage getTelemetryStorage(boolean shouldRecordTelemetry, TelemetryStorage telemetryStorage) {
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/io/split/android/client/SplitFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@

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;
import io.split.android.client.common.CompressionUtilProvider;
Expand Down Expand Up @@ -180,9 +178,11 @@ public void taskExecuted(@NonNull SplitTaskExecutionInfo taskInfo) {
SplitApiFacade splitApiFacade = factoryHelper.buildApiFacade(
config, defaultHttpClient, splitsFilterQueryStringFromConfig);

FlagSetsFilter flagSetsFilter = factoryHelper.getFlagSetsFilter(filters);

SplitTaskFactory splitTaskFactory = new SplitTaskFactoryImpl(
config, splitApiFacade, mStorageContainer, splitsFilterQueryStringFromConfig, mEventsManagerCoordinator,
filters, testingConfig);
filters, flagSetsFilter, testingConfig);

cleanUpDabase(splitTaskExecutor, splitTaskFactory);
WorkManagerWrapper workManagerWrapper = factoryHelper.buildWorkManagerWrapper(context, config, apiToken, databaseName, filters);
Expand Down Expand Up @@ -270,7 +270,7 @@ public void taskExecuted(@NonNull SplitTaskExecutionInfo taskInfo) {
telemetrySynchronizer, mStorageContainer, splitTaskExecutor, splitApiFacade,
validationLogger, keyValidator, customerImpressionListener,
streamingComponents.getPushNotificationManager(), componentsRegister, workManagerWrapper,
eventsTracker, factoryHelper.getConfiguredFlagSets(filters));
eventsTracker, flagSetsFilter);
mDestroyer = new Runnable() {
public void run() {
Logger.w("Shutdown called for split");
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/split/android/client/SplitFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public static SplitFilter bySet(@NonNull List<String> values) {

SplitFilter(Type type, List<String> values, SplitFilterValidator validator) {
mType = type;
SplitFilterValidator.ValidationResult validationResult = validator.cleanup(values);
SplitFilterValidator.ValidationResult validationResult = validator.cleanup("SDK config", values);
mValues = validationResult.getValues();
mInvalidValueCount = validationResult.getInvalidValueCount();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
import java.util.Map;
import java.util.Set;

import io.split.android.client.Evaluator;
import io.split.android.client.EvaluatorImpl;
import io.split.android.client.FlagSetsFilter;
import io.split.android.client.SplitClient;
import io.split.android.client.SplitClientConfig;
import io.split.android.client.SplitFactory;
Expand Down Expand Up @@ -61,7 +61,7 @@ public LocalhostSplitClient(@NonNull LocalhostSplitFactory container,
@NonNull AttributesManager attributesManager,
@NonNull AttributesMerger attributesMerger,
@NonNull TelemetryStorageProducer telemetryStorageProducer,
@NonNull Set<String> configuredFlagSets) {
@Nullable FlagSetsFilter flagSetsFilter) {

mFactoryRef = new WeakReference<>(checkNotNull(container));
mClientContainer = new WeakReference<>(checkNotNull(clientContainer));
Expand All @@ -72,7 +72,7 @@ public LocalhostSplitClient(@NonNull LocalhostSplitFactory container,
new EvaluatorImpl(splitsStorage, splitParser), new KeyValidatorImpl(),
new SplitValidatorImpl(), getImpressionsListener(splitClientConfig),
splitClientConfig.labelsEnabled(), eventsManager, attributesManager, attributesMerger,
telemetryStorageProducer, configuredFlagSets, splitsStorage);
telemetryStorageProducer, flagSetsFilter, splitsStorage);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import java.util.Set;

import io.split.android.client.FilterBuilder;
import io.split.android.client.FlagSetsFilter;
import io.split.android.client.FlagSetsFilterImpl;
import io.split.android.client.SplitClient;
import io.split.android.client.SplitClientConfig;
import io.split.android.client.SplitFactory;
Expand Down Expand Up @@ -75,15 +77,15 @@ public LocalhostSplitFactory(String key, Context context,

mManager = new SplitManagerImpl(splitsStorage, new SplitValidatorImpl(), splitParser);

Set<String> configuredSets = new HashSet<>();
FlagSetsFilter flagSetsFilter = null;
if (config.syncConfig() != null) {
Map<SplitFilter.Type, SplitFilter> groupedFilters = new FilterBuilder(config.syncConfig().getFilters())
.getGroupedFilter();

if (!groupedFilters.isEmpty()) {
SplitFilter bySetFilter = groupedFilters.get(SplitFilter.Type.BY_SET);
if (bySetFilter != null) {
configuredSets.addAll(bySetFilter.getValues());
flagSetsFilter = new FlagSetsFilterImpl(bySetFilter.getValues());
}
}
}
Expand All @@ -97,7 +99,7 @@ public LocalhostSplitFactory(String key, Context context,
new NoOpTelemetryStorage(),
eventsManagerCoordinator,
taskExecutor,
configuredSets);
flagSetsFilter);

mSynchronizer = new LocalhostSynchronizer(taskExecutor, config, splitsStorage, buildQueryString(config.syncConfig()));
mSynchronizer.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -126,7 +127,7 @@ public void clear() {

@NonNull
@Override
public Set<String> getNamesByFlagSets(List<String> sets) {
public Set<String> getNamesByFlagSets(Collection<String> sets) {
Set<String> namesToReturn = new HashSet<>();
if (sets == null || sets.isEmpty()) {
return namesToReturn;
Expand Down
Loading

0 comments on commit 5e93c2d

Please sign in to comment.