Skip to content

Commit 1e90b56

Browse files
msohailhussainmikeproeng37
authored andcommitted
fix(NaN/Ifinity): Don't target/track NaN, Infinity, or -Infinity (#228)
1 parent 6a0ace3 commit 1e90b56

File tree

3 files changed

+82
-7
lines changed

3 files changed

+82
-7
lines changed

core-api/src/main/java/com/optimizely/ab/config/audience/match/MatchType.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,9 @@ public static MatchType getMatchType(String matchType, Object conditionValue) {
3737
case "exact":
3838
if (conditionValue instanceof String) {
3939
return new MatchType(matchType, new ExactMatch<String>((String) conditionValue));
40-
}
41-
else if (conditionValue instanceof Integer || conditionValue instanceof Double) {
40+
} else if (isValidNumber(conditionValue)) {
4241
return new MatchType(matchType, new ExactMatch<Number>((Number) conditionValue));
43-
}
44-
else if (conditionValue instanceof Boolean) {
42+
} else if (conditionValue instanceof Boolean) {
4543
return new MatchType(matchType, new ExactMatch<Boolean>((Boolean) conditionValue));
4644
}
4745
break;
@@ -51,12 +49,12 @@ else if (conditionValue instanceof Boolean) {
5149
}
5250
break;
5351
case "gt":
54-
if (conditionValue instanceof Integer || conditionValue instanceof Double) {
52+
if (isValidNumber(conditionValue)) {
5553
return new MatchType(matchType, new GTMatch((Number) conditionValue));
5654
}
5755
break;
5856
case "lt":
59-
if (conditionValue instanceof Integer || conditionValue instanceof Double) {
57+
if (isValidNumber(conditionValue)) {
6058
return new MatchType(matchType, new LTMatch((Number) conditionValue));
6159
}
6260
break;
@@ -72,6 +70,15 @@ else if (conditionValue instanceof Boolean) {
7270
return new MatchType(matchType, new NullMatch());
7371
}
7472

73+
private static boolean isValidNumber(Object conditionValue) {
74+
if (conditionValue instanceof Integer) {
75+
return Math.abs((Integer) conditionValue) <= 1e53;
76+
} else if (conditionValue instanceof Double) {
77+
Double value = ((Number) conditionValue).doubleValue();
78+
return !(value.isNaN() || value.isInfinite());
79+
}
80+
return false;
81+
}
7582

7683
private MatchType(String type, Match matcher) {
7784
this.matchType = type;

core-api/src/main/java/com/optimizely/ab/internal/EventTagUtils.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ public static Double getNumericValue(@Nonnull Map<String, ?> eventTags) {
5757
Object rawValue = eventTags.get(ReservedEventKey.VALUE.toString());
5858
if (rawValue instanceof Number) {
5959
eventValue = ((Number) rawValue).doubleValue();
60+
if(eventValue.isInfinite() || eventValue.isNaN()) {
61+
eventValue = null;
62+
logger.warn("Failed to parse numeric metric value \"{}\" from event tags.", rawValue);
63+
}
6064
logger.info("Parsed numeric metric value \"{}\" from event tags.", eventValue);
6165
} else {
6266
logger.warn("Failed to parse numeric metric value \"{}\" from event tags.", rawValue);

core-api/src/test/java/com/optimizely/ab/config/audience/AudienceConditionEvaluationTest.java

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
*
3-
* Copyright 2016-2017, Optimizely and contributors
3+
* Copyright 2016-2018, Optimizely and contributors
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020
import org.junit.Before;
2121
import org.junit.Test;
2222

23+
import java.math.BigInteger;
2324
import java.util.ArrayList;
2425
import java.util.Collections;
2526
import java.util.HashMap;
@@ -172,6 +173,27 @@ public void exactMatchConditionEvaluatesTrue() throws Exception {
172173
assertTrue(testInstanceDouble.evaluate(testTypedUserAttributes));
173174
}
174175

176+
177+
/**
178+
* Verify that UserAttribute.evaluate for EXACT match type returns null if the UserAttribute's
179+
* value type is invalid number.
180+
*/
181+
@Test
182+
public void invalidExactMatchConditionEvaluatesNull() throws Exception {
183+
BigInteger bigInteger = new BigInteger("33221312312312312");
184+
Double infinitePositiveInfiniteDouble = Double.POSITIVE_INFINITY;
185+
Double infiniteNegativeInfiniteDouble = Double.NEGATIVE_INFINITY;
186+
Double infiniteNANDouble = Double.NaN;
187+
UserAttribute testInstanceInteger = new UserAttribute("num_size", "custom_attribute","exact", bigInteger);
188+
UserAttribute testInstancePositiveInfinite = new UserAttribute("num_counts", "custom_attribute","exact", infinitePositiveInfiniteDouble);
189+
UserAttribute testInstanceNegativeInfiniteDouble = new UserAttribute("num_counts", "custom_attribute","exact", infiniteNegativeInfiniteDouble);
190+
UserAttribute testInstanceNANDouble = new UserAttribute("num_counts", "custom_attribute","exact", infiniteNANDouble);
191+
192+
assertNull(testInstanceInteger.evaluate(testTypedUserAttributes));
193+
assertNull(testInstancePositiveInfinite.evaluate(testTypedUserAttributes));
194+
assertNull(testInstanceNegativeInfiniteDouble.evaluate(testTypedUserAttributes));
195+
assertNull(testInstanceNANDouble.evaluate(testTypedUserAttributes));
196+
}
175197
/**
176198
* Verify that UserAttribute.evaluate for EXACT match type returns false for known visitor
177199
* attributes where the value's type are the same, but the values are different
@@ -228,6 +250,27 @@ public void gtMatchConditionEvaluatesTrue() throws Exception {
228250
assertNull(testInstanceInteger.evaluate(badAttributes));
229251
}
230252

253+
/**
254+
* Verify that UserAttribute.evaluate for GT match type returns null if the UserAttribute's
255+
* value type is invalid number.
256+
*/
257+
@Test
258+
public void gtMatchConditionEvaluatesNullWithInvalidAttr() throws Exception {
259+
BigInteger bigInteger = new BigInteger("33221312312312312");
260+
Double infinitePositiveInfiniteDouble = Double.POSITIVE_INFINITY;
261+
Double infiniteNegativeInfiniteDouble = Double.NEGATIVE_INFINITY;
262+
Double infiniteNANDouble = Double.NaN;
263+
UserAttribute testInstanceInteger = new UserAttribute("num_size", "custom_attribute","gt", bigInteger);
264+
UserAttribute testInstancePositiveInfinite = new UserAttribute("num_counts", "custom_attribute","gt", infinitePositiveInfiniteDouble);
265+
UserAttribute testInstanceNegativeInfiniteDouble = new UserAttribute("num_counts", "custom_attribute","gt", infiniteNegativeInfiniteDouble);
266+
UserAttribute testInstanceNANDouble = new UserAttribute("num_counts", "custom_attribute","gt", infiniteNANDouble);
267+
268+
assertNull(testInstanceInteger.evaluate(testTypedUserAttributes));
269+
assertNull(testInstancePositiveInfinite.evaluate(testTypedUserAttributes));
270+
assertNull(testInstanceNegativeInfiniteDouble.evaluate(testTypedUserAttributes));
271+
assertNull(testInstanceNANDouble.evaluate(testTypedUserAttributes));
272+
}
273+
231274
/**
232275
* Verify that UserAttribute.evaluate for GT match type returns false for known visitor
233276
* attributes where the value's type is a number, and the UserAttribute's value is not greater
@@ -304,6 +347,27 @@ public void ltMatchConditionEvaluatesNull() throws Exception {
304347
assertNull(testInstanceNull.evaluate(testTypedUserAttributes));
305348
}
306349

350+
/**
351+
* Verify that UserAttribute.evaluate for LT match type returns null if the UserAttribute's
352+
* value type is not a number.
353+
*/
354+
@Test
355+
public void ltMatchConditionEvaluatesNullWithInvalidAttributes() {
356+
BigInteger bigInteger = new BigInteger("33221312312312312");
357+
Double infinitePositiveInfiniteDouble = Double.POSITIVE_INFINITY;
358+
Double infiniteNegativeInfiniteDouble = Double.NEGATIVE_INFINITY;
359+
Double infiniteNANDouble = Double.NaN;
360+
UserAttribute testInstanceInteger = new UserAttribute("num_size", "custom_attribute","lt", bigInteger);
361+
UserAttribute testInstancePositiveInfinite = new UserAttribute("num_counts", "custom_attribute","lt", infinitePositiveInfiniteDouble);
362+
UserAttribute testInstanceNegativeInfiniteDouble = new UserAttribute("num_counts", "custom_attribute","lt", infiniteNegativeInfiniteDouble);
363+
UserAttribute testInstanceNANDouble = new UserAttribute("num_counts", "custom_attribute","lt", infiniteNANDouble);
364+
365+
assertNull(testInstanceInteger.evaluate(testTypedUserAttributes));
366+
assertNull(testInstancePositiveInfinite.evaluate(testTypedUserAttributes));
367+
assertNull(testInstanceNegativeInfiniteDouble.evaluate(testTypedUserAttributes));
368+
assertNull(testInstanceNANDouble.evaluate(testTypedUserAttributes));
369+
}
370+
307371
/**
308372
* Verify that UserAttribute.evaluate for SUBSTRING match type returns true if the
309373
* UserAttribute's value is a substring of the condition's value.

0 commit comments

Comments
 (0)