Skip to content

Commit

Permalink
feature flagging on client (#245)
Browse files Browse the repository at this point in the history
* feature flagging and tests on client

* remove uneeded line

* remove getEnabledFeatureFlags method

* add tests for parsing and break down enabled flag tests

* add should parse counters and feature flag tests

* move setCounters and setFeatureFlags out of parse methods

* remove unneeded comments

* remove unneeded comments

* redefine HashSet as Set, add one test, featureFlagManager and countAggregator package private, loop returns set instead of list
  • Loading branch information
gg4race authored Oct 1, 2018
1 parent b2aa0cf commit d644c98
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 24 deletions.
34 changes: 28 additions & 6 deletions AndroidSDKCore/src/main/java/com/leanplum/Leanplum.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import android.content.Context;
import android.location.Location;
import android.os.AsyncTask;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;

import com.leanplum.ActionContext.ContextualValues;
Expand All @@ -37,6 +38,7 @@
import com.leanplum.internal.FileManager;
import com.leanplum.internal.JsonConverter;
import com.leanplum.internal.CountAggregator;
import com.leanplum.internal.FeatureFlagManager;
import com.leanplum.internal.LeanplumEventDataManager;
import com.leanplum.internal.LeanplumInternal;
import com.leanplum.internal.LeanplumMessageMatchFilter;
Expand Down Expand Up @@ -818,7 +820,10 @@ protected Void doInBackground(Void... params) {
Constants.loggingEnabled = true;
}

parseSdkCounters(response);
Set<String> enabledCounters = parseSdkCounters(response);
CountAggregator.INSTANCE.setEnabledCounters(enabledCounters);
Set<String> enabledFeatureFlags = parseFeatureFlags(response);
FeatureFlagManager.INSTANCE.setEnabledFeatureFlags((enabledFeatureFlags));
parseVariantDebugInfo(response);

// Allow bidirectional realtime variable updates.
Expand Down Expand Up @@ -2164,12 +2169,29 @@ public static void clearUserContent() {
VarCache.clearUserContent();
}

private static void parseSdkCounters(JSONObject response) {
@VisibleForTesting
public static Set<String> parseSdkCounters(JSONObject response) {
JSONArray enabledCounters = response.optJSONArray(
Constants.Keys.ENABLED_COUNTERS);
if (enabledCounters != null) {
HashSet counterSet = new HashSet<>(Arrays.asList(enabledCounters));
CountAggregator.INSTANCE.setEnabledCounters(counterSet);
}
Set<String> counterSet = toSet(enabledCounters);
return counterSet;
}

@VisibleForTesting
public static Set<String> parseFeatureFlags(JSONObject response) {
JSONArray enabledFeatureFlags = response.optJSONArray(
Constants.Keys.ENABLED_FEATURE_FLAGS);
Set<String> featureFlagSet = toSet(enabledFeatureFlags);
return featureFlagSet;
}

private static Set<String> toSet(JSONArray array) {
Set<String> set = new HashSet<>();
if (array != null) {
for (int i = 0; i < array.length(); i++) {
set.add(array.optString(i));
}
}
return set;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ public static class Keys {
public static final String SYNC_INBOX = "syncNewsfeed";
public static final String LOGGING_ENABLED = "loggingEnabled";
public static final String ENABLED_COUNTERS = "enabledSdkCounters";
public static final String ENABLED_FEATURE_FLAGS = "enabledFeatureFlags";
public static final String TIMEZONE = "timezone";
public static final String TIMEZONE_OFFSET_SECONDS = "timezoneOffsetSeconds";
public static final String TITLE = "Title";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@
import java.util.HashSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class CountAggregator {
public static final CountAggregator INSTANCE = new CountAggregator();

private HashSet<String> enabledCounters = new HashSet<>();
private final HashMap<String, Integer> counts = new HashMap<>();
private Set<String> enabledCounters = new HashSet<>();
private final Map<String, Integer> counts = new HashMap<>();

public void setEnabledCounters(HashSet<String> enabledCounters) {
@VisibleForTesting
CountAggregator() {
super();
}

public void setEnabledCounters(Set<String> enabledCounters) {
this.enabledCounters = enabledCounters;
}

Expand All @@ -33,16 +39,16 @@ public void incrementCount(@NonNull String name, int incrementCount) {
}

@VisibleForTesting
public HashMap<String, Integer> getAndClearCounts() {
HashMap<String, Integer> previousCounts = new HashMap<>();
public Map<String, Integer> getAndClearCounts() {
Map<String, Integer> previousCounts = new HashMap<>();
previousCounts.putAll(counts);
counts.clear();
return previousCounts;
}

@VisibleForTesting
public HashMap<String, Object> makeParams(@NonNull String name, int count) {
HashMap<String, Object> params = new HashMap<>();
public Map<String, Object> makeParams(@NonNull String name, int count) {
Map<String, Object> params = new HashMap<>();

params.put(Constants.Params.TYPE, Constants.Values.SDK_COUNT);
params.put(Constants.Params.MESSAGE, name);
Expand All @@ -52,12 +58,12 @@ public HashMap<String, Object> makeParams(@NonNull String name, int count) {
}

public void sendAllCounts() {
HashMap<String, Integer> counts = getAndClearCounts();
Map<String, Integer> counts = getAndClearCounts();

for(Map.Entry<String, Integer> entry : counts.entrySet()) {
String name = entry.getKey();
Integer count = entry.getValue();
HashMap<String, Object> params = makeParams(name, count);
Map<String, Object> params = makeParams(name, count);
try {
Request.post(Constants.Methods.LOG, params).sendEventually();
} catch (Throwable t) {
Expand All @@ -66,7 +72,7 @@ public void sendAllCounts() {
}
}

public HashMap<String, Integer> getCounts() {
public Map<String, Integer> getCounts() {
return counts;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.leanplum.internal;

import android.support.annotation.VisibleForTesting;

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

public class FeatureFlagManager {
public static final FeatureFlagManager INSTANCE = new FeatureFlagManager();

private Set<String> enabledFeatureFlags = new HashSet<>();

@VisibleForTesting
FeatureFlagManager() {
super();
}

public void setEnabledFeatureFlags(Set<String> enabledFeatureFlags) {
this.enabledFeatureFlags = enabledFeatureFlags;
}

public Boolean isFeatureFlagEnabled(String featureFlagName) {
return this.enabledFeatureFlags.contains(featureFlagName);
}
}
66 changes: 66 additions & 0 deletions AndroidSDKTests/src/test/java/com/leanplum/LeanplumTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import com.leanplum.callbacks.VariablesChangedCallback;
import com.leanplum.internal.CollectionUtil;
import com.leanplum.internal.Constants;
import com.leanplum.internal.CountAggregator;
import com.leanplum.internal.FeatureFlagManager;
import com.leanplum.internal.FileManager;
import com.leanplum.internal.JsonConverter;
import com.leanplum.internal.LeanplumEventDataManager;
Expand All @@ -44,6 +46,9 @@
import com.leanplum.internal.Util;
import com.leanplum.internal.VarCache;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;
import org.mockito.Mockito;
import org.robolectric.RuntimeEnvironment;
Expand All @@ -53,6 +58,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
Expand All @@ -78,6 +84,7 @@
import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.verifyStatic;
import static org.powermock.api.mockito.PowerMockito.whenNew;
import java.util.Set;

/**
* Tests Leanplum SDK calls and general functionality.
Expand Down Expand Up @@ -1267,4 +1274,63 @@ public void testGetDeviceId() {
deviceId = Leanplum.getDeviceId();
assertNotNull(deviceId);
}

/**
* Tests for parsing counters
*/
@Test
public void testStartResponseShouldParseCounters() {
// Setup sdk.
setupSDK(mContext, "/responses/simple_start_response.json");

// check that incrementing counters work
CountAggregator.INSTANCE.incrementCount("testCounter1");
assertEquals(1, CountAggregator.INSTANCE.getCounts().get("testCounter1").intValue());
CountAggregator.INSTANCE.incrementCount("testCounter2");
assertEquals(1, CountAggregator.INSTANCE.getCounts().get("testCounter2").intValue());
}

@Test
public void testParseEmptySdkCounters() throws JSONException {
JSONObject response = new JSONObject();
Set<String> parsedCounters = Leanplum.parseSdkCounters(response);
assertEquals(new HashSet<String>(), parsedCounters);
}

@Test
public void testParseSdkCounters() throws JSONException {
JSONObject response = new JSONObject();
response.put(Constants.Keys.ENABLED_COUNTERS, new JSONArray("[\"test\"]"));
Set<String> parsedCounters = Leanplum.parseSdkCounters(response);
assertEquals(new HashSet<>(Arrays.asList("test")), parsedCounters);
}


/**
* Tests for parsing feature flags
*/
@Test
public void testStartResponseShouldParseFeatureFlags() {
// Setup sdk.
setupSDK(mContext, "/responses/simple_start_response.json");

assertEquals(true, FeatureFlagManager.INSTANCE.isFeatureFlagEnabled("testFeatureFlag1"));
assertEquals(true, FeatureFlagManager.INSTANCE.isFeatureFlagEnabled("testFeatureFlag2"));
assertEquals(false, FeatureFlagManager.INSTANCE.isFeatureFlagEnabled("missingFeatureFlag"));
}

@Test
public void testParseEmptyFeatureFlags() {
JSONObject response = new JSONObject();
Set<String> parsedFeatureFlags = Leanplum.parseFeatureFlags(response);
assertEquals(new HashSet<String>(), parsedFeatureFlags);
}

@Test
public void testParseFeatureFlags() throws JSONException {
JSONObject response = new JSONObject();
response.put(Constants.Keys.ENABLED_FEATURE_FLAGS, new JSONArray("[\"test\"]"));
Set<String> parsedFeatureFlags = Leanplum.parseFeatureFlags(response);
assertEquals(new HashSet<>(Arrays.asList("test")), parsedFeatureFlags);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Arrays;
import java.util.Set;
import java.util.Map;

import static org.junit.Assert.assertEquals;

Expand All @@ -40,7 +42,7 @@ public void testIncrementDisabledCount() {
String testString = "test";

countAggregator.incrementCount(testString);
HashMap<String, Integer> counts = countAggregator.getCounts();
Map<String, Integer> counts = countAggregator.getCounts();
assertEquals(null, counts.get(testString));

countAggregator.incrementCount(testString);
Expand All @@ -52,11 +54,11 @@ public void testIncrementDisabledCount() {
public void testIncrementCount() {
CountAggregator countAggregator = new CountAggregator();
String testString = "test";
HashSet<String> testSet = new HashSet<String>(Arrays.asList(testString));
Set<String> testSet = new HashSet<String>(Arrays.asList(testString));
countAggregator.setEnabledCounters(testSet);

countAggregator.incrementCount(testString);
HashMap<String, Integer> counts = countAggregator.getCounts();
Map<String, Integer> counts = countAggregator.getCounts();
assertEquals(1, counts.get(testString).intValue());

countAggregator.incrementCount(testString);
Expand All @@ -70,7 +72,7 @@ public void testIncrementDisabledCountMultiple() {
String testString = "test";

countAggregator.incrementCount(testString, 2);
HashMap<String, Integer> counts = countAggregator.getCounts();
Map<String, Integer> counts = countAggregator.getCounts();
assertEquals(null, counts.get(testString));

countAggregator.incrementCount(testString, 15);
Expand All @@ -86,7 +88,7 @@ public void testIncrementCountMultiple() {
countAggregator.setEnabledCounters(testSet);

countAggregator.incrementCount(testString, 2);
HashMap<String, Integer> counts = countAggregator.getCounts();
Map<String, Integer> counts = countAggregator.getCounts();
assertEquals(2, counts.get(testString).intValue());

countAggregator.incrementCount(testString, 15);
Expand All @@ -105,8 +107,8 @@ public void testGetAndClearCounts() {
countAggregator.incrementCount(testString, 2);
countAggregator.incrementCount(testString2, 15);

HashMap<String, Integer> previousCounts = countAggregator.getAndClearCounts();
HashMap<String, Integer> counts = countAggregator.getCounts();
Map<String, Integer> previousCounts = countAggregator.getAndClearCounts();
Map<String, Integer> counts = countAggregator.getCounts();

//check counts is empty after clearing
assertEquals(true, counts.isEmpty());
Expand All @@ -119,7 +121,7 @@ public void testGetAndClearCounts() {
public void testMakeParams() {
CountAggregator countAggregator = new CountAggregator();
String testString = "test";
HashMap<String, Object> params = countAggregator.makeParams(testString, 2);
Map<String, Object> params = countAggregator.makeParams(testString, 2);

assertEquals(Constants.Values.SDK_COUNT, params.get(Constants.Params.TYPE));
assertEquals(testString, params.get(Constants.Params.MESSAGE));
Expand Down
Loading

0 comments on commit d644c98

Please sign in to comment.