8000 feat(api): Accepting all type of attributes (#229) · optimizely/android-sdk@6d36538 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6d36538

Browse files
msohailhussainmikeproeng37
authored andcommitted
feat(api): Accepting all type of attributes (#229)
1 parent 864ec84 commit 6d36538

File tree

7 files changed

+128
-43
lines changed

7 files changed

+128
-43
lines changed

android-sdk/src/androidTest/java/com/optimizely/ab/android/sdk/OptimizelyClientTest.java

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,11 @@
2626
import com.optimizely.ab.config.Experiment;
2727
import com.optimizely.ab.config.ProjectConfig;
2828
import com.optimizely.ab.config.Variation;
29-
import com.optimizely.ab.config.parser.ConfigParseException;
3029
import com.optimizely.ab.event.EventHandler;
3130
import com.optimizely.ab.event.LogEvent;
3231
import com.optimizely.ab.internal.ReservedEventKey;
3332
import com.optimizely.ab.notification.ActivateNotificationListener;
3433
import com.optimizely.ab.notification.NotificationCenter;
35-
import com.optimizely.ab.notification.NotificationListener;
3634
import com.optimizely.ab.notification.TrackNotificationListener;
3735

3836
import org.junit.Assert;
@@ -59,6 +57,8 @@
5957
import static junit.framework.Assert.assertNotNull;
6058
import static junit.framework.Assert.assertNull;
6159
import static junit.framework.Assert.assertTrue;
60+
import static org.hamcrest.Matchers.hasEntry;
61+
import static org.junit.Assert.assertThat;
6262
import static org.junit.Assume.assumeTrue;
6363
import static org.mockito.Mockito.mock;
6464
import static org.mockito.Mockito.spy;
@@ -115,7 +115,7 @@ public OptimizelyClientTest(int datafileVersion,String datafile){
115115
when(bucketer.bucket(optimizely.getProjectConfig().getExperimentKeyMapping().get(FEATURE_MULTI_VARIATE_EXPERIMENT_KEY), GENERIC_USER_ID)).thenReturn(optimizely.getProjectConfig().getExperimentKeyMapping().get(FEATURE_MULTI_VARIATE_EXPERIMENT_KEY).getVariations().get(1));
116116
}
117117
spyOnConfig();
118-
}catch (ConfigParseException configException){
118+
} catch (Exception configException) {
119119
logger.error("Error in parsing config",configException);
120120
}
121121
}
@@ -192,7 +192,7 @@ public void testGoodActivationWithListener() {
192192
callbackCalled[0] = false;
193193
int notificationId = optimizelyClient.getNotificationCenter().addNotificationListener(NotificationCenter.NotificationType.Activate, new ActivateNotificationListener() {
194194
@Override
195-
public void onActivate(@Nonnull Experiment experiment, @Nonnull String userId, @Nonnull Map<String, String> attributes, @Nonnull Variation variation, @Nonnull LogEvent event) {
195+
public void onActivate(@Nonnull Experiment experiment, @Nonnull String userId, @Nonnull Map<String, ?> attributes, @Nonnull Variation variation, @Nonnull LogEvent event) {
196196
callbackCalled[0] = true;
197197
callbackVariation[0] = variation;
198198
}
@@ -224,7 +224,7 @@ public void testBadActivationWithListener() {
224224
callbackCalled[0] = false;
225225
int notificationId = optimizelyClient.getNotificationCenter().addNotificationListener(NotificationCenter.NotificationType.Activate, new TrackNotificationListener() {
226226
@Override
227-
public void onTrack(@Nonnull String eventKey, @Nonnull String userId, @Nonnull Map<String, String> attributes, @Nonnull Map<String, ?> eventTags, @Nonnull LogEvent event) {
227+
public void onTrack(@Nonnull String eventKey, @Nonnull String userId, @Nonnull Map<String, ?> attributes, @Nonnull Map<String, ?> eventTags, @Nonnull LogEvent event) {
228228
callbackCalled[0] = true;
229229
}
230230
});
@@ -307,6 +307,42 @@ public void testGoodActivationAttribute() {
307307
}
308308
}
309309

310+
private Map<String, ?> expectedAttributes;
311+
312+
@Test
313+
public void testGoodActivationWithTypedAttribute() {
314+
assumeTrue(datafileVersion == Integer.parseInt(ProjectConfig.Version.V4.toString()));
315+
String attributeString = "house";
316+
String attributeBoolean = "booleanKey";
317+
String attributeInteger = "integerKey";
318+
String attributeDouble = "doubleKey";
319+
320+
OptimizelyClient optimizelyClient = new OptimizelyClient(optimizely,
321+
logger);
322+
final HashMap<String, Object> attributes = new HashMap<>();
323+
attributes.put(attributeString, "Gryffindor");
324+
attributes.put(attributeBoolean, true);
325+
attributes.put(attributeInteger, 3);
326+
attributes.put(attributeDouble, 3.123);
327+
328+
329+
int notificationId = optimizelyClient.getNotificationCenter().addNotificationListener(NotificationCenter.NotificationType.Activate, new ActivateNotificationListener() {
330+
@Override
331+
public void onActivate(@Nonnull Experiment experiment, @Nonnull String userId, @Nonnull Map<String, ?> attributes, @Nonnull Variation variation, @Nonnull LogEvent event) {
332+
expectedAttributes = new HashMap<>(attributes);
333+
}
334+
});
335+
336+
Variation v = optimizelyClient.activate(FEATURE_MULTI_VARIATE_EXPERIMENT_KEY, GENERIC_USER_ID, attributes);
337+
338+
assertThat((Map<String,? extends String>)expectedAttributes, hasEntry(attributeString, "Gryffindor"));
339+
assertThat((Map<String,? extends Boolean>)expectedAttributes, hasEntry(attributeBoolean, true));
340+
assertThat((Map<String,? extends Integer>)expectedAttributes, hasEntry(attributeInteger, 3));
341+
assertThat((Map<String,? extends Double>)expectedAttributes, hasEntry(attributeDouble, 3.123));
342+
assertNotNull(v);
343+
344+
}
345+
310346
@Test
311347
public void testGoodActivationBucketingId() {
312348
OptimizelyClient optimizelyClient = new OptimizelyClient(optimizely, logger);
@@ -409,7 +445,7 @@ public void testBadTrackWithListener() {
409445
int notificationId = optimizelyClient.getNotificationCenter().addNotificationListener(NotificationCenter.NotificationType.Activate,
410446
new TrackNotificationListener() {
411447
@Override
412-
public void onTrack(@Nonnull String eventKey, @Nonnull String userId, @Nonnull Map<String, String> attributes, @Nonnull Map<String, ?> eventTags, @Nonnull LogEvent event) {
448+
public void onTrack(@Nonnull String eventKey, @Nonnull String userId, @Nonnull Map<String, ?> attributes, @Nonnull Map<String, ?> eventTags, @Nonnull LogEvent event) {
413449
numberOfCalls[0] = true;
414450
}
415451
});
@@ -432,7 +468,7 @@ public void testGoodTrackWithListener() {
432468
int notificationId = optimizelyClient.getNotificationCenter().addNotificationListener(NotificationCenter.NotificationType.Track,
433469
new TrackNotificationListener() {
434470
@Override
435-
public void onTrack(@Nonnull String eventKey, @Nonnull String userId, @Nonnull Map<String, String> attributes, @Nonnull Map<String, ?> eventTags, @Nonnull LogEvent event) {
471+
public void onTrack(@Nonnull String eventKey, @Nonnull String userId, @Nonnull Map<String, ?> attributes, @Nonnull Map<String, ?> eventTags, @Nonnull LogEvent event) {
436472
numberOfCalls[0] = true;
437473
}
438474
});
@@ -1049,7 +1085,7 @@ public void testDefaultAttributes() {
10491085
OptimizelyClient optimizelyClient = new OptimizelyClient(null, logger);
10501086
optimizelyClient.setDefaultAttributes(OptimizelyDefaultAttributes.buildDefaultAttributesMap(context, logger));
10511087

1052-
Map<String, String> map = optimizelyClient.getDefaultAttributes();
1088+
Map<String, ?> map = optimizelyClient.getDefaultAttributes();
10531089
Assert.assertEquals(map.size(), 4);
10541090
}
10551091

android-sdk/src/androidTest/java/com/optimizely/ab/android/sdk/OptimizelyManagerTest.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import com.optimizely.ab.android.user_profile.DefaultUserProfileService;
3939
import com.optimizely.ab.bucketing.UserProfileService;
4040
import com.optimizely.ab.config.Variation;
41-
import com.optimizely.ab.config.parser.ConfigParseException;
4241
import com.optimizely.ab.event.EventHandler;
4342

4443
import org.junit.Before;
@@ -171,7 +170,6 @@ public void initializeSyncWithEmptyDatafile() {
171170
when(context.getApplicationContext()).thenReturn(appContext);
172171
when(appContext.getPackageName()).thenReturn("com.optly");
173172
optimizelyManager.initialize(InstrumentationRegistry.getTargetContext(), R.raw.emptydatafile);
174-
verify(logger).error(eq("Unable to parse compiled data file"), any(ConfigParseException.class));
175173
assertFalse(optimizelyManager.getOptimizely().isValid());
176174
}
177175
@Test
@@ -267,7 +265,7 @@ public void initializeWithEmptyDatafile() {
267265
String emptyString = "";
268266

269267
optimizelyManager.initialize(context, emptyString);
270-
verify(logger).error(eq("Unable to parse compiled data file"), any(ConfigParseException.class));
268+
assertFalse(optimizelyManager.getOptimizely().isValid());
271269
}
272270

273271
@Test
@@ -280,7 +278,7 @@ public void initializeWithMalformedDatafile() {
280278
String emptyString = "malformed data";
281279

282280
optimizelyManager.initialize(context, emptyString);
283-
verify(logger).error(eq("Unable to parse compiled data file"), any(ConfigParseException.class));
281+
assertFalse(optimizelyManager.getOptimizely().isValid());
284282
}
285283

286284
@Test
@@ -444,9 +442,7 @@ public F438 void injectOptimizelyHandlesInvalidDatafile() {
444442
} catch (InterruptedException e) {
445443
fail("Timed out");
446444
}
447-
448-
verify(logger).error(eq("Unable to build OptimizelyClient instance"), any(Exception.class));
449-
445+
assertFalse(optimizelyManager.getOptimizely().isValid());
450446
}
451447

452448
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)

android-sdk/src/debug/res/raw/validprojectconfigv4

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,59 @@
2121
"name": "audience_with_missing_value",
2222
"conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"nationality\", \"type\": \"custom_dimension\", \"value\": \"English\"}, {\"name\": \"nationality\", \"type\": \"custom_dimension\"}]]]"
2323
}],
24+
"typedAudiences": [
25+
{
26+
"id": "3468206643",
27+
"name": "BOOL",
28+
"conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"booleanKey\", \"type\": \"custom_attribute\", \"match\":\"exact\", \"value\":true}]]]"
29+
},
30+
{
31+
"id": "3468206644",
32+
"name": "INT",
33+
"conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"integerKey\", \"type\": \"custom_attribute\", \"match\":\"gt\", \"value\":1.0}]]]"
34+
},
35+
{
36+
"id": "3468206645",
37+
"name": "DOUBLE",
38+
"conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"doubleKey\", \"type\": \"custom_attribute\", \"match\":\"lt\", \"value\":100.0}]]]"
39+
},
40+
{
41+
"id": "3468206642",
42+
"name": "Gryffindors",
43+
"conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"house\", \"type\": \"custom_attribute\", \"match\":\"exact\", \"value\":\"Gryffindor\"}]]]"
44+
},
45+
{
46+
"id": "3988293898",
47+
"name": "Slytherins",
48+
"conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"house\", \"type\": \"custom_attribute\", \"match\":\"substring\", \"value\":\"Slytherin\"}]]]"
49+
},
50+
{
51+
"id": "4194404272",
52+
"name": "english_citizens",
53+
"conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"nationality\", \"type\": \"custom_attribute\", \"match\":\"exact\", \"value\":\"English\"}]]]"
54+
},
55+
{
56+
"id": "2196265320",
57+
"name": "audience_with_missing_value",
58+
"conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"nationality\", \"type\": \"custom_attribute\", \"value\": \"English\"}, {\"name\": \"nationality\", \"type\": \"custom_attribute\"}]]]"
59+
}
60+
],
2461
"attributes": [{
2562
"id": "553339214",
2663
"key": "house"
2764
}, {
2865
"id": "58339410",
2966
"key": "nationality"
30-
}],
67+
}, {
68+
"id": "323434545",
69+
"key": "booleanKey"
70+
}, {
71+
"id": "616727838",
72+
"key": "integerKey"
73+
}, {
74+
"id": "808797686",
75+
"key": "doubleKey"
76+
}],
3177
"events": [{
3278
"experimentIds": ["8509139139"],
3379
"id": "8505434668",

android-sdk/src/main/java/com/optimizely/ab/android/sdk/OptimizelyClient.java

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public class OptimizelyClient {
5353
private final Logger logger;
5454

5555
@Nullable private Optimizely optimizely;
56-
@NonNull private Map<String, String> defaultAttributes = new HashMap<>();
56+
@NonNull private Map<String, ?> defaultAttributes = new HashMap<>();
5757

5858
OptimizelyClient(@Nullable Optimizely optimizely, @NonNull Logger logger) {
5959
this.optimizely = optimizely;
@@ -72,15 +72,15 @@ public class OptimizelyClient {
7272
* This is set by the Optimizely manager and includes things like os version and sdk version.
7373
* @param attrs a map of default attributes.
7474
*/
75-
protected void setDefaultAttributes(@NonNull Map<String, String> attrs) {
75+
protected void setDefaultAttributes(@NonNull Map<String, ?> attrs) {
7676
this.defaultAttributes = attrs;
7777
}
7878

7979
/**
8080
* Return the default attributes map
8181
* @return the map of default attributes
8282
*/
83-
public @NonNull Map<String, String> getDefaultAttributes() {
83+
public @NonNull Map<String, ?> getDefaultAttributes() {
8484
return this.defaultAttributes;
8585
}
8686

@@ -90,11 +90,15 @@ protected void setDefaultAttributes(@NonNull Map<String, String> attrs) {
9090
* @param attrs attributes that will be combined with default attributes.
9191
* @return a new map of both the default attributes and attributes passed in.
9292
*/
93-
private Map<String, String> getAllAttributes(@NonNull Map<String, String> attrs) {
94-
Map<String,String> combinedMap = new HashMap<>(defaultAttributes);
93+
private Map<String, ?> getAllAttributes(@NonNull Map<String, ?> attrs) {
94+
Map<String, Object> combinedMap = new HashMap<>(defaultAttributes);
9595

9696
// this essentially overrides defaultAttributes if the attrs passed in have the same key.
97-
combinedMap.putAll(attrs);
97+
if (attrs != null) {
98+
combinedMap.putAll(attrs);
99+
} else if (combinedMap.isEmpty()) {
100+
combinedMap = null;
101+
}
98102

99103
return combinedMap;
100104
}
@@ -128,7 +132,7 @@ private Map<String, String> getAllAttributes(@NonNull Map<String, String> attrs)
128132
@SuppressWarnings("WeakerAccess")
129133
public @Nullable Variation activate(@NonNull String experimentKey,
130134
@NonNull String userId,
131-
@NonNull Map<String, String> attributes) {
135+
@NonNull Map<String, ?> attributes) {
132136
if (isValid()) {
133137
return optimizely.activate(experimentKey, userId, getAllAttributes(attributes));
134138
} else {
@@ -156,7 +160,10 @@ private Map<String, String> getAllAttributes(@NonNull Map<String, String> attrs)
156160
* @return True if the OptimizelyClient instance was instantiated correctly
157161
*/
158162
public boolean isValid() {
159-
return optimizely != null;
163+
if (optimizely != null)
164+
return optimizely.isValid();
165+
else
166+
return false;
160167
}
161168

162169
/**
@@ -185,7 +192,7 @@ public void track(@NonNull String eventName,
185192
*/
186193
public void track(@NonNull String eventName,
187194
@NonNull String userId,
188-
@NonNull Map<String, String> attributes) throws UnknownEventTypeException {
195+
@NonNull Map<String, ?> attributes) throws UnknownEventTypeException {
189196
if (isValid()) {
190197
optimizely.track(eventName, userId, getAllAttributes(attributes));
191198

@@ -204,7 +211,7 @@ public void track(@NonNull String eventName,
204211
*/
205212
public void track(@NonNull String eventName,
206213
@NonNull String userId,
207-
@NonNull Map<String, String> attributes,
214+
@NonNull Map<String, ?> attributes,
208215
@NonNull Map<String, ?> eventTags) throws UnknownEventTypeException {
209216
if (isValid()) {
210217
optimizely.track(eventName, userId, getAllAttributes(attributes), eventTags);
@@ -245,7 +252,7 @@ public void track(@NonNull String eventName,
245252
@SuppressWarnings("WeakerAccess")
246253
public @Nullable Variation getVariation(@NonNull String experimentKey,
247254
@NonNull String userId,
248-
@NonNull Map<String, String> attributes) {
255+
@NonNull Map<String, ?> attributes) {
249256
if (isValid()) {
250257
return optimizely.getVariation(experimentKey, userId, getAllAttributes(attributes));
251258
} else {
@@ -310,7 +317,7 @@ public boolean setForcedVariation(@NonNull String experimentKey,
310317
* @return List of the feature keys that are enabled for the user if the userId is empty it will
311318
* return Empty List.
312319
*/
313-
public List<String> getEnabledFeatures(@NonNull String userId, @NonNull Map<String, String> attributes) {
320+
public List<String> getEnabledFeatures(@NonNull String userId, @NonNull Map<String, ?> attributes) {
314321
if (isValid()) {
315322
return optimizely.getEnabledFeatures(userId, attributes);
316323
} else {
@@ -355,7 +362,7 @@ Boolean isFeatureEnabled(@NonNull String featureKey,
355362
*/
356363
public @NonNull Boolean isFeatureEnabled(@NonNull String featureKey,
357364
@NonNull String userId,
358-
@NonNull Map<String, String> attributes) {
365+
@NonNull Map<String, ?> attributes) {
359366
if (isValid()) {
360367
return optimizely.isFeatureEnabled(featureKey, userId, attributes);
361368
} else {
@@ -401,7 +408,7 @@ Boolean getFeatureVariableBoolean(@NonNull String featureKey,
401408
Boolean getFeatureVariableBoolean(@NonNull String featureKey,
402409
@NonNull String variableKey,
403410
@NonNull String userId,
404-
@NonNull Map<String, String> attributes) {
411+
@NonNull Map<String, ?> attributes) {
405412
if (isValid()) {
406413
return optimizely.getFeatureVariableBoolean(featureKey, variableKey, userId, attributes);
407414
} else {
@@ -445,7 +452,7 @@ Double getFeatureVariableDouble(@NonNull String featureKey,
445452
Double getFeatureVariableDouble(@NonNull String featureKey,
446453
@NonNull String variableKey,
447454
@NonNull String userId,
448-
@NonNull Map<String, String> attributes) {
455+
@NonNull Map<String, ?> attributes) {
449456
if (isValid()) {
450457
return optimizely.getFeatureVariableDouble(featureKey, variableKey, userId, attributes);
451458
} else {
@@ -489,7 +496,7 @@ Integer getFeatureVariableInteger(@NonNull String featureKey,
489496
Integer getFeatureVariableInteger(@NonNull String featureKey,
490497
@NonNull String variableKey,
491498
@NonNull String userId,
492-
@NonNull Map<String, String> attributes) {
499+
@NonNull Map<String, ?> attributes) {
493500
if (isValid()) {
494501
return optimizely.getFeatureVariableInteger(featureKey, variableKey, userId, attributes);
495502
} else {
@@ -533,7 +540,7 @@ String getFeatureVariableString(@NonNull String featureKey,
533540
String getFeatureVariableString(@NonNull String featureKey,
534541
@NonNull String variableKey,
535542
@NonNull String userId,
536-
@NonNull Map<String, String> attributes) {
543+
@NonNull Map<String, ?> attributes) {
537544
if (isValid()) {
538545
return optimizely.getFeatureVariableString(featureKey, variableKey, userId, attributes);
539546
} else {

0 commit comments

Comments
 (0)
0