Skip to content

Commit d644c98

Browse files
authored
feature flagging on client (#245)
* 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
1 parent b2aa0cf commit d644c98

File tree

8 files changed

+219
-24
lines changed

8 files changed

+219
-24
lines changed

AndroidSDKCore/src/main/java/com/leanplum/Leanplum.java

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import android.content.Context;
2626
import android.location.Location;
2727
import android.os.AsyncTask;
28+
import android.support.annotation.VisibleForTesting;
2829
import android.text.TextUtils;
2930

3031
import com.leanplum.ActionContext.ContextualValues;
@@ -37,6 +38,7 @@
3738
import com.leanplum.internal.FileManager;
3839
import com.leanplum.internal.JsonConverter;
3940
import com.leanplum.internal.CountAggregator;
41+
import com.leanplum.internal.FeatureFlagManager;
4042
import com.leanplum.internal.LeanplumEventDataManager;
4143
import com.leanplum.internal.LeanplumInternal;
4244
import com.leanplum.internal.LeanplumMessageMatchFilter;
@@ -818,7 +820,10 @@ protected Void doInBackground(Void... params) {
818820
Constants.loggingEnabled = true;
819821
}
820822

821-
parseSdkCounters(response);
823+
Set<String> enabledCounters = parseSdkCounters(response);
824+
CountAggregator.INSTANCE.setEnabledCounters(enabledCounters);
825+
Set<String> enabledFeatureFlags = parseFeatureFlags(response);
826+
FeatureFlagManager.INSTANCE.setEnabledFeatureFlags((enabledFeatureFlags));
822827
parseVariantDebugInfo(response);
823828

824829
// Allow bidirectional realtime variable updates.
@@ -2164,12 +2169,29 @@ public static void clearUserContent() {
21642169
VarCache.clearUserContent();
21652170
}
21662171

2167-
private static void parseSdkCounters(JSONObject response) {
2172+
@VisibleForTesting
2173+
public static Set<String> parseSdkCounters(JSONObject response) {
21682174
JSONArray enabledCounters = response.optJSONArray(
21692175
Constants.Keys.ENABLED_COUNTERS);
2170-
if (enabledCounters != null) {
2171-
HashSet counterSet = new HashSet<>(Arrays.asList(enabledCounters));
2172-
CountAggregator.INSTANCE.setEnabledCounters(counterSet);
2173-
}
2176+
Set<String> counterSet = toSet(enabledCounters);
2177+
return counterSet;
2178+
}
2179+
2180+
@VisibleForTesting
2181+
public static Set<String> parseFeatureFlags(JSONObject response) {
2182+
JSONArray enabledFeatureFlags = response.optJSONArray(
2183+
Constants.Keys.ENABLED_FEATURE_FLAGS);
2184+
Set<String> featureFlagSet = toSet(enabledFeatureFlags);
2185+
return featureFlagSet;
21742186
}
2187+
2188+
private static Set<String> toSet(JSONArray array) {
2189+
Set<String> set = new HashSet<>();
2190+
if (array != null) {
2191+
for (int i = 0; i < array.length(); i++) {
2192+
set.add(array.optString(i));
2193+
}
2194+
}
2195+
return set;
2196+
}
21752197
}

AndroidSDKCore/src/main/java/com/leanplum/internal/Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ public static class Keys {
208208
public static final String SYNC_INBOX = "syncNewsfeed";
209209
public static final String LOGGING_ENABLED = "loggingEnabled";
210210
public static final String ENABLED_COUNTERS = "enabledSdkCounters";
211+
public static final String ENABLED_FEATURE_FLAGS = "enabledFeatureFlags";
211212
public static final String TIMEZONE = "timezone";
212213
public static final String TIMEZONE_OFFSET_SECONDS = "timezoneOffsetSeconds";
213214
public static final String TITLE = "Title";

AndroidSDKCore/src/main/java/com/leanplum/internal/CountAggregator.java

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,20 @@
66
import java.util.HashSet;
77
import java.util.HashMap;
88
import java.util.Map;
9+
import java.util.Set;
910

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

13-
private HashSet<String> enabledCounters = new HashSet<>();
14-
private final HashMap<String, Integer> counts = new HashMap<>();
14+
private Set<String> enabledCounters = new HashSet<>();
15+
private final Map<String, Integer> counts = new HashMap<>();
1516

16-
public void setEnabledCounters(HashSet<String> enabledCounters) {
17+
@VisibleForTesting
18+
CountAggregator() {
19+
super();
20+
}
21+
22+
public void setEnabledCounters(Set<String> enabledCounters) {
1723
this.enabledCounters = enabledCounters;
1824
}
1925

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

3541
@VisibleForTesting
36-
public HashMap<String, Integer> getAndClearCounts() {
37-
HashMap<String, Integer> previousCounts = new HashMap<>();
42+
public Map<String, Integer> getAndClearCounts() {
43+
Map<String, Integer> previousCounts = new HashMap<>();
3844
previousCounts.putAll(counts);
3945
counts.clear();
4046
return previousCounts;
4147
}
4248

4349
@VisibleForTesting
44-
public HashMap<String, Object> makeParams(@NonNull String name, int count) {
45-
HashMap<String, Object> params = new HashMap<>();
50+
public Map<String, Object> makeParams(@NonNull String name, int count) {
51+
Map<String, Object> params = new HashMap<>();
4652

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

5460
public void sendAllCounts() {
55-
HashMap<String, Integer> counts = getAndClearCounts();
61+
Map<String, Integer> counts = getAndClearCounts();
5662

5763
for(Map.Entry<String, Integer> entry : counts.entrySet()) {
5864
String name = entry.getKey();
5965
Integer count = entry.getValue();
60-
HashMap<String, Object> params = makeParams(name, count);
66+
Map<String, Object> params = makeParams(name, count);
6167
try {
6268
Request.post(Constants.Methods.LOG, params).sendEventually();
6369
} catch (Throwable t) {
@@ -66,7 +72,7 @@ public void sendAllCounts() {
6672
}
6773
}
6874

69-
public HashMap<String, Integer> getCounts() {
75+
public Map<String, Integer> getCounts() {
7076
return counts;
7177
}
7278
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.leanplum.internal;
2+
3+
import android.support.annotation.VisibleForTesting;
4+
5+
import java.util.HashSet;
6+
import java.util.Set;
7+
8+
public class FeatureFlagManager {
9+
public static final FeatureFlagManager INSTANCE = new FeatureFlagManager();
10+
11+
private Set<String> enabledFeatureFlags = new HashSet<>();
12+
13+
@VisibleForTesting
14+
FeatureFlagManager() {
15+
super();
16+
}
17+
18+
public void setEnabledFeatureFlags(Set<String> enabledFeatureFlags) {
19+
this.enabledFeatureFlags = enabledFeatureFlags;
20+
}
21+
22+
public Boolean isFeatureFlagEnabled(String featureFlagName) {
23+
return this.enabledFeatureFlags.contains(featureFlagName);
24+
}
25+
}

AndroidSDKTests/src/test/java/com/leanplum/LeanplumTest.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import com.leanplum.callbacks.VariablesChangedCallback;
3737
import com.leanplum.internal.CollectionUtil;
3838
import com.leanplum.internal.Constants;
39+
import com.leanplum.internal.CountAggregator;
40+
import com.leanplum.internal.FeatureFlagManager;
3941
import com.leanplum.internal.FileManager;
4042
import com.leanplum.internal.JsonConverter;
4143
import com.leanplum.internal.LeanplumEventDataManager;
@@ -44,6 +46,9 @@
4446
import com.leanplum.internal.Util;
4547
import com.leanplum.internal.VarCache;
4648

49+
import org.json.JSONArray;
50+
import org.json.JSONException;
51+
import org.json.JSONObject;
4752
import org.junit.Test;
4853
import org.mockito.Mockito;
4954
import org.robolectric.RuntimeEnvironment;
@@ -53,6 +58,7 @@
5358
import java.util.ArrayList;
5459
import java.util.Arrays;
5560
import java.util.HashMap;
61+
import java.util.HashSet;
5662
import java.util.List;
5763
import java.util.Locale;
5864
import java.util.Map;
@@ -78,6 +84,7 @@
7884
import static org.powermock.api.mockito.PowerMockito.doReturn;
7985
import static org.powermock.api.mockito.PowerMockito.verifyStatic;
8086
import static org.powermock.api.mockito.PowerMockito.whenNew;
87+
import java.util.Set;
8188

8289
/**
8390
* Tests Leanplum SDK calls and general functionality.
@@ -1267,4 +1274,63 @@ public void testGetDeviceId() {
12671274
deviceId = Leanplum.getDeviceId();
12681275
assertNotNull(deviceId);
12691276
}
1277+
1278+
/**
1279+
* Tests for parsing counters
1280+
*/
1281+
@Test
1282+
public void testStartResponseShouldParseCounters() {
1283+
// Setup sdk.
1284+
setupSDK(mContext, "/responses/simple_start_response.json");
1285+
1286+
// check that incrementing counters work
1287+
CountAggregator.INSTANCE.incrementCount("testCounter1");
1288+
assertEquals(1, CountAggregator.INSTANCE.getCounts().get("testCounter1").intValue());
1289+
CountAggregator.INSTANCE.incrementCount("testCounter2");
1290+
assertEquals(1, CountAggregator.INSTANCE.getCounts().get("testCounter2").intValue());
1291+
}
1292+
1293+
@Test
1294+
public void testParseEmptySdkCounters() throws JSONException {
1295+
JSONObject response = new JSONObject();
1296+
Set<String> parsedCounters = Leanplum.parseSdkCounters(response);
1297+
assertEquals(new HashSet<String>(), parsedCounters);
1298+
}
1299+
1300+
@Test
1301+
public void testParseSdkCounters() throws JSONException {
1302+
JSONObject response = new JSONObject();
1303+
response.put(Constants.Keys.ENABLED_COUNTERS, new JSONArray("[\"test\"]"));
1304+
Set<String> parsedCounters = Leanplum.parseSdkCounters(response);
1305+
assertEquals(new HashSet<>(Arrays.asList("test")), parsedCounters);
1306+
}
1307+
1308+
1309+
/**
1310+
* Tests for parsing feature flags
1311+
*/
1312+
@Test
1313+
public void testStartResponseShouldParseFeatureFlags() {
1314+
// Setup sdk.
1315+
setupSDK(mContext, "/responses/simple_start_response.json");
1316+
1317+
assertEquals(true, FeatureFlagManager.INSTANCE.isFeatureFlagEnabled("testFeatureFlag1"));
1318+
assertEquals(true, FeatureFlagManager.INSTANCE.isFeatureFlagEnabled("testFeatureFlag2"));
1319+
assertEquals(false, FeatureFlagManager.INSTANCE.isFeatureFlagEnabled("missingFeatureFlag"));
1320+
}
1321+
1322+
@Test
1323+
public void testParseEmptyFeatureFlags() {
1324+
JSONObject response = new JSONObject();
1325+
Set<String> parsedFeatureFlags = Leanplum.parseFeatureFlags(response);
1326+
assertEquals(new HashSet<String>(), parsedFeatureFlags);
1327+
}
1328+
1329+
@Test
1330+
public void testParseFeatureFlags() throws JSONException {
1331+
JSONObject response = new JSONObject();
1332+
response.put(Constants.Keys.ENABLED_FEATURE_FLAGS, new JSONArray("[\"test\"]"));
1333+
Set<String> parsedFeatureFlags = Leanplum.parseFeatureFlags(response);
1334+
assertEquals(new HashSet<>(Arrays.asList("test")), parsedFeatureFlags);
1335+
}
12701336
}

AndroidSDKTests/src/test/java/com/leanplum/internal/CountAggregatorTest.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import java.util.HashMap;
2828
import java.util.HashSet;
2929
import java.util.Arrays;
30+
import java.util.Set;
31+
import java.util.Map;
3032

3133
import static org.junit.Assert.assertEquals;
3234

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

4244
countAggregator.incrementCount(testString);
43-
HashMap<String, Integer> counts = countAggregator.getCounts();
45+
Map<String, Integer> counts = countAggregator.getCounts();
4446
assertEquals(null, counts.get(testString));
4547

4648
countAggregator.incrementCount(testString);
@@ -52,11 +54,11 @@ public void testIncrementDisabledCount() {
5254
public void testIncrementCount() {
5355
CountAggregator countAggregator = new CountAggregator();
5456
String testString = "test";
55-
HashSet<String> testSet = new HashSet<String>(Arrays.asList(testString));
57+
Set<String> testSet = new HashSet<String>(Arrays.asList(testString));
5658
countAggregator.setEnabledCounters(testSet);
5759

5860
countAggregator.incrementCount(testString);
59-
HashMap<String, Integer> counts = countAggregator.getCounts();
61+
Map<String, Integer> counts = countAggregator.getCounts();
6062
assertEquals(1, counts.get(testString).intValue());
6163

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

7274
countAggregator.incrementCount(testString, 2);
73-
HashMap<String, Integer> counts = countAggregator.getCounts();
75+
Map<String, Integer> counts = countAggregator.getCounts();
7476
assertEquals(null, counts.get(testString));
7577

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

8890
countAggregator.incrementCount(testString, 2);
89-
HashMap<String, Integer> counts = countAggregator.getCounts();
91+
Map<String, Integer> counts = countAggregator.getCounts();
9092
assertEquals(2, counts.get(testString).intValue());
9193

9294
countAggregator.incrementCount(testString, 15);
@@ -105,8 +107,8 @@ public void testGetAndClearCounts() {
105107
countAggregator.incrementCount(testString, 2);
106108
countAggregator.incrementCount(testString2, 15);
107109

108-
HashMap<String, Integer> previousCounts = countAggregator.getAndClearCounts();
109-
HashMap<String, Integer> counts = countAggregator.getCounts();
110+
Map<String, Integer> previousCounts = countAggregator.getAndClearCounts();
111+
Map<String, Integer> counts = countAggregator.getCounts();
110112

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

124126
assertEquals(Constants.Values.SDK_COUNT, params.get(Constants.Params.TYPE));
125127
assertEquals(testString, params.get(Constants.Params.MESSAGE));

0 commit comments

Comments
 (0)