|
40 | 40 |
|
41 | 41 | import javax.annotation.Nullable;
|
42 | 42 | import java.io.IOException;
|
43 |
| -import java.util.ArrayList; |
44 |
| -import java.util.Arrays; |
45 |
| -import java.util.Collection; |
46 |
| -import java.util.Collections; |
47 |
| -import java.util.HashMap; |
48 |
| -import java.util.List; |
49 |
| -import java.util.Map; |
| 43 | +import java.math.BigDecimal; |
| 44 | +import java.math.BigInteger; |
| 45 | +import java.util.*; |
50 | 46 |
|
51 | 47 | import static com.optimizely.ab.config.ProjectConfigTestUtils.validProjectConfigV2;
|
52 | 48 | import static com.optimizely.ab.config.ProjectConfigTestUtils.validProjectConfigV4;
|
53 | 49 | import static com.optimizely.ab.config.ValidProjectConfigV4.*;
|
54 | 50 | import static junit.framework.Assert.assertNotNull;
|
| 51 | +import static junit.framework.Assert.assertNotSame; |
55 | 52 | import static org.hamcrest.CoreMatchers.is;
|
56 | 53 | import static org.hamcrest.Matchers.closeTo;
|
57 | 54 | import static org.hamcrest.Matchers.containsInAnyOrder;
|
|
60 | 57 | import static org.junit.Assert.assertNull;
|
61 | 58 | import static org.junit.Assert.assertThat;
|
62 | 59 | import static org.junit.Assert.assertTrue;
|
| 60 | +import static org.junit.Assume.assumeTrue; |
63 | 61 | import static org.mockito.Mockito.mock;
|
64 | 62 | import static org.mockito.Mockito.never;
|
65 | 63 | import static org.mockito.Mockito.spy;
|
@@ -249,6 +247,196 @@ public void createImpressionEventIgnoresUnknownAttributes() throws Exception {
|
249 | 247 | }
|
250 | 248 | }
|
251 | 249 |
|
| 250 | + /** |
| 251 | + * Verify that passing through an list value attribute causes that attribute to be ignored, rather than |
| 252 | + * causing an exception to be thrown and passing only the valid attributes. |
| 253 | + */ |
| 254 | + @Test |
| 255 | + public void createConversionEventIgnoresInvalidAndAcceptsValidAttributes() { |
| 256 | + assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())); |
| 257 | + |
| 258 | + Bucketer mockBucketAlgorithm = mock(Bucketer.class); |
| 259 | + EventType eventType = validProjectConfig.getEventTypes().get(0); |
| 260 | + |
| 261 | + List<Experiment> allExperiments = validProjectConfig.getExperiments(); |
| 262 | + |
| 263 | + // Bucket to the first variation for all experiments. However, only a subset of the experiments will actually |
| 264 | + // call the bucket function. |
| 265 | + for (Experiment experiment : allExperiments) { |
| 266 | + when(mockBucketAlgorithm.bucket(experiment, userId)) |
| 267 | + .thenReturn(experiment.getVariations().get(0)); |
| 268 | + } |
| 269 | + Attribute attribute1 = validProjectConfig.getAttributes().get(0); |
| 270 | + Attribute attribute2 = validProjectConfig.getAttributes().get(1); |
| 271 | + Attribute doubleAttribute = validProjectConfig.getAttributes().get(5); |
| 272 | + Attribute integerAttribute = validProjectConfig.getAttributes().get(4); |
| 273 | + Attribute boolAttribute = validProjectConfig.getAttributes().get(3); |
| 274 | + |
| 275 | + BigInteger bigInteger = new BigInteger("12323"); |
| 276 | + BigDecimal bigDecimal = new BigDecimal("123"); |
| 277 | + double validDoubleAttribute = 13.1; |
| 278 | + int validIntegerAttribute = 12; |
| 279 | + boolean validBoolAttribute = true; |
| 280 | + |
| 281 | + Map<String, Object> eventTagMap = new HashMap<>(); |
| 282 | + eventTagMap.put("boolean_param", false); |
| 283 | + eventTagMap.put("string_param", "123"); |
| 284 | + |
| 285 | + HashMap<String, Object> attributes = new HashMap<>(); |
| 286 | + attributes.put(attribute1.getKey(), bigInteger); |
| 287 | + attributes.put(attribute2.getKey(), bigDecimal); |
| 288 | + attributes.put(doubleAttribute.getKey(), validDoubleAttribute); |
| 289 | + attributes.put(integerAttribute.getKey(), validIntegerAttribute); |
| 290 | + attributes.put(boolAttribute.getKey(), validBoolAttribute); |
| 291 | + |
| 292 | + DecisionService decisionService = new DecisionService( |
| 293 | + mockBucketAlgorithm, |
| 294 | + mock(ErrorHandler.class), |
| 295 | + validProjectConfig, |
| 296 | + mock(UserProfileService.class) |
| 297 | + ); |
| 298 | + Map<Experiment, Variation> experimentVariationMap = createExperimentVariationMap( |
| 299 | + validProjectConfig, |
| 300 | + decisionService, |
| 301 | + eventType.getKey(), |
| 302 | + userId, |
| 303 | + attributes); |
| 304 | + LogEvent conversionEvent = factory.createConversionEvent( |
| 305 | + validProjectConfig, |
| 306 | + experimentVariationMap, |
| 307 | + userId, |
| 308 | + eventType.getId(), |
| 309 | + eventType.getKey(), |
| 310 | + attributes, |
| 311 | + eventTagMap); |
| 312 | + |
| 313 | + EventBatch impression = gson.fromJson(conversionEvent.getBody(), EventBatch.class); |
| 314 | + |
| 315 | + //Check valid attributes are getting passed. |
| 316 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(0).getKey(), boolAttribute.getKey()); |
| 317 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(0).getValue(), validBoolAttribute); |
| 318 | + |
| 319 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(1).getKey(), doubleAttribute.getKey()); |
| 320 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(1).getValue(), validDoubleAttribute); |
| 321 | + |
| 322 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(2).getKey(), integerAttribute.getKey()); |
| 323 | + assertEquals((int) ((double) impression.getVisitors().get(0).getAttributes().get(2).getValue()), validIntegerAttribute); |
| 324 | + |
| 325 | + // verify that no Feature is created for attribute.getKey() -> invalidAttribute |
| 326 | + for (com.optimizely.ab.event.internal.payload.Attribute feature : impression.getVisitors().get(0).getAttributes()) { |
| 327 | + assertNotSame(feature.getKey(), attribute1.getKey()); |
| 328 | + assertNotSame(feature.getValue(), bigInteger); |
| 329 | + assertNotSame(feature.getKey(), attribute2.getKey()); |
| 330 | + assertNotSame(feature.getValue(), bigDecimal); |
| 331 | + } |
| 332 | + } |
| 333 | + |
| 334 | + /** |
| 335 | + * Verify that passing through an list value attribute causes that attribute to be ignored, rather than |
| 336 | + * causing an exception to be thrown. |
| 337 | + */ |
| 338 | + @Test |
| 339 | + public void createImpressionEventIgnoresInvalidAttributes() { |
| 340 | + assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())); |
| 341 | + // use the "valid" project config and its associated experiment, variation, and attributes |
| 342 | + ProjectConfig projectConfig = validProjectConfig; |
| 343 | + Experiment activatedExperiment = projectConfig.getExperiments().get(0); |
| 344 | + Variation bucketedVariation = activatedExperiment.getVariations().get(0); |
| 345 | + Attribute attribute1 = validProjectConfig.getAttributes().get(0); |
| 346 | + Attribute attribute2 = validProjectConfig.getAttributes().get(1); |
| 347 | + BigInteger bigInteger = new BigInteger("12323"); |
| 348 | + BigDecimal bigDecimal = new BigDecimal("123"); |
| 349 | + |
| 350 | + HashMap<String, Object> attributes = new HashMap<>(); |
| 351 | + attributes.put(attribute1.getKey(), bigInteger); |
| 352 | + attributes.put(attribute2.getKey(), bigDecimal); |
| 353 | + |
| 354 | + LogEvent impressionEvent = |
| 355 | + factory.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, "userId", |
| 356 | + attributes); |
| 357 | + |
| 358 | + EventBatch impression = gson.fromJson(impressionEvent.getBody(), EventBatch.class); |
| 359 | + |
| 360 | + // verify that no Feature is created for attribute.getKey() -> invalidAttribute |
| 361 | + for (com.optimizely.ab.event.internal.payload.Attribute feature : impression.getVisitors().get(0).getAttributes()) { |
| 362 | + assertNotSame(feature.getKey(), attribute1.getKey()); |
| 363 | + assertNotSame(feature.getValue(), bigInteger); |
| 364 | + assertNotSame(feature.getKey(), attribute2.getKey()); |
| 365 | + assertNotSame(feature.getValue(), bigDecimal); |
| 366 | + } |
| 367 | + } |
| 368 | + |
| 369 | + /** |
| 370 | + * Verify that Integer, Decimal, Bool and String variables are allowed to pass. |
| 371 | + */ |
| 372 | + @Test |
| 373 | + public void createImpressionEventWithIntegerDecimalBoolAndStringAttributes() { |
| 374 | + assumeTrue(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())); |
| 375 | + // use the "valid" project config and its associated experiment, variation, and attributes |
| 376 | + ProjectConfig projectConfig = validProjectConfig; |
| 377 | + Experiment activatedExperiment = projectConfig.getExperiments().get(0); |
| 378 | + Variation bucketedVariation = activatedExperiment.getVariations().get(0); |
| 379 | + Attribute doubleAttribute = validProjectConfig.getAttributes().get(5); |
| 380 | + Attribute integerAttribute = validProjectConfig.getAttributes().get(4); |
| 381 | + Attribute boolAttribute = validProjectConfig.getAttributes().get(3); |
| 382 | + Attribute stringAttribute = validProjectConfig.getAttributes().get(0); |
| 383 | + double validDoubleAttribute = 13.1; |
| 384 | + int validIntegerAttribute = 12; |
| 385 | + boolean validBoolAttribute = true; |
| 386 | + String validStringAttribute = "grayfindor"; |
| 387 | + |
| 388 | + HashMap<String, Object> attributes = new HashMap<>(); |
| 389 | + attributes.put(doubleAttribute.getKey(), validDoubleAttribute); |
| 390 | + attributes.put(integerAttribute.getKey(), validIntegerAttribute); |
| 391 | + attributes.put(boolAttribute.getKey(), validBoolAttribute); |
| 392 | + attributes.put(stringAttribute.getKey(), validStringAttribute); |
| 393 | + |
| 394 | + LogEvent impressionEvent = |
| 395 | + factory.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, "userId", |
| 396 | + attributes); |
| 397 | + |
| 398 | + EventBatch impression = gson.fromJson(impressionEvent.getBody(), EventBatch.class); |
| 399 | + |
| 400 | + |
| 401 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(0).getKey(), boolAttribute.getKey()); |
| 402 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(0).getValue(), validBoolAttribute); |
| 403 | + |
| 404 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(1).getKey(), doubleAttribute.getKey()); |
| 405 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(1).getValue(), validDoubleAttribute); |
| 406 | + |
| 407 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(2).getKey(), integerAttribute.getKey()); |
| 408 | + assertEquals((int) ((double) impression.getVisitors().get(0).getAttributes().get(2).getValue()), validIntegerAttribute); |
| 409 | + |
| 410 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(3).getKey(), stringAttribute.getKey()); |
| 411 | + assertEquals(impression.getVisitors().get(0).getAttributes().get(3).getValue(), validStringAttribute); |
| 412 | + |
| 413 | + } |
| 414 | + |
| 415 | + /** |
| 416 | + * Verify that passing through an null value attribute causes that attribute to be ignored, rather than |
| 417 | + * causing an exception to be thrown. |
| 418 | + */ |
| 419 | + @Test |
| 420 | + public void createImpressionEventIgnoresNullAttributes() { |
| 421 | + // use the "valid" project config and its associated experiment, variation, and attributes |
| 422 | + ProjectConfig projectConfig = validProjectConfig; |
| 423 | + Experiment activatedExperiment = projectConfig.getExperiments().get(0); |
| 424 | + Variation bucketedVariation = activatedExperiment.getVariations().get(0); |
| 425 | + Attribute attribute = validProjectConfig.getAttributes().get(0); |
| 426 | + |
| 427 | + LogEvent impressionEvent = |
| 428 | + factory.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, "userId", |
| 429 | + Collections.singletonMap(attribute.getKey(), null)); |
| 430 | + |
| 431 | + EventBatch impression = gson.fromJson(impressionEvent.getBody(), EventBatch.class); |
| 432 | + |
| 433 | + // verify that no Feature is created for attribute.getKey() -> null |
| 434 | + for (com.optimizely.ab.event.internal.payload.Attribute feature : impression.getVisitors().get(0).getAttributes()) { |
| 435 | + assertNotSame(feature.getKey(), attribute.getKey()); |
| 436 | + assertNotSame(feature.getValue(), null); |
| 437 | + } |
| 438 | + } |
| 439 | + |
252 | 440 | /**
|
253 | 441 | * Verify that supplying {@link EventFactory} with a custom client engine and client version results in impression
|
254 | 442 | * events being sent with the overriden values.
|
@@ -946,7 +1134,7 @@ public static Map<Experiment, Variation> createExperimentVariationMap(ProjectCon
|
946 | 1134 | DecisionService decisionService,
|
947 | 1135 | String eventName,
|
948 | 1136 | String userId,
|
949 |
| - @Nullable Map<String, String> attributes) { |
| 1137 | + @Nullable Map<String, ?> attributes) { |
950 | 1138 |
|
951 | 1139 | List<Experiment> eventExperiments = projectConfig.getExperimentsForEventKey(eventName);
|
952 | 1140 | Map<Experiment, Variation> experimentVariationMap = new HashMap<Experiment, Variation>(eventExperiments.size());
|
|
0 commit comments