Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public Audience deserialize(JsonParser parser, DeserializationContext context) t
JsonNode conditionsJson = node.get("conditions");
conditionsJson = objectMapper.readTree(conditionsJson.textValue());

Condition conditions = ConditionJacksonDeserializer.<UserAttribute>parseConditions(UserAttribute.class, objectMapper, conditionsJson);
Condition conditions = ConditionJacksonDeserializer.<UserAttribute>parseCondition(UserAttribute.class, objectMapper, conditionsJson);

return new Audience(id, name, conditions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.optimizely.ab.config.audience.NullCondition;
import com.optimizely.ab.config.audience.OrCondition;
import com.optimizely.ab.config.audience.UserAttribute;
import com.optimizely.ab.internal.ConditionUtils;
import com.optimizely.ab.internal.InvalidAudienceCondition;

import java.io.IOException;
Expand All @@ -50,7 +51,7 @@ public ConditionJacksonDeserializer() {
@Override
public Condition deserialize(JsonParser parser, DeserializationContext context) throws IOException {
JsonNode node = parser.getCodec().readTree(parser);
Condition conditions = ConditionJacksonDeserializer.<AudienceIdCondition>parseConditions(AudienceIdCondition.class, objectMapper, node);
Condition conditions = ConditionJacksonDeserializer.<AudienceIdCondition>parseCondition(AudienceIdCondition.class, objectMapper, node);

return conditions;
}
Expand All @@ -69,10 +70,33 @@ private static String operand(JsonNode opNode) {
}
return null;
}

protected static <T> Condition parseCondition(Class<T> clazz, ObjectMapper objectMapper,JsonNode conditionNode)
throws JsonProcessingException, InvalidAudienceCondition {

if (conditionNode.isArray()) {
return ConditionJacksonDeserializer.<T>parseConditions(clazz, objectMapper, conditionNode);
} else if (conditionNode.isTextual()) {
if (clazz != AudienceIdCondition.class) {
throw new InvalidAudienceCondition(String.format("Expected AudienceIdCondition got %s", clazz.getCanonicalName()));

}
return objectMapper.treeToValue(conditionNode, AudienceIdCondition.class);
}
else if (conditionNode.isObject()) {
if (clazz != UserAttribute.class) {
throw new InvalidAudienceCondition(String.format("Expected UserAttributes got %s", clazz.getCanonicalName()));

}
return objectMapper.treeToValue(conditionNode, UserAttribute.class);
}

return null;
}
protected static <T> Condition parseConditions(Class<T> clazz, ObjectMapper objectMapper, JsonNode conditionNode)
throws JsonProcessingException, InvalidAudienceCondition {

if (conditionNode.size() == 0) {
if (conditionNode.isArray() && conditionNode.size() == 0) {
return new EmptyCondition();
}

Expand All @@ -89,22 +113,7 @@ protected static <T> Condition parseConditions(Class<T> clazz, ObjectMapper obje

for (int i = startingParsingIndex; i < conditionNode.size(); i++) {
JsonNode subNode = conditionNode.get(i);
if (subNode.isArray()) {
conditions.add(ConditionJacksonDeserializer.<T>parseConditions(clazz, objectMapper, subNode));
} else if (subNode.isTextual()) {
if (clazz != AudienceIdCondition.class) {
throw new InvalidAudienceCondition(String.format("Expected AudienceIdCondition got %s", clazz.getCanonicalName()));

}
conditions.add(objectMapper.treeToValue(subNode, AudienceIdCondition.class));
}
else if (subNode.isObject()) {
if (clazz != UserAttribute.class) {
throw new InvalidAudienceCondition(String.format("Expected UserAttributes got %s", clazz.getCanonicalName()));

}
conditions.add(objectMapper.treeToValue(subNode, UserAttribute.class));
}
conditions.add(ConditionJacksonDeserializer.<T>parseCondition(clazz, objectMapper, subNode));
}

Condition condition;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,11 @@ static Condition parseAudienceConditions(JsonObject experimentJson) {
List<Object> rawObjectList = gson.fromJson(conditionsElement, List.class);
return ConditionUtils.<AudienceIdCondition>parseConditions(AudienceIdCondition.class, rawObjectList);
}
else if (conditionsElement.isJsonObject()) {
else {
Object jsonObject = gson.fromJson(conditionsElement,Object.class);
return ConditionUtils.<AudienceIdCondition>parseConditions(AudienceIdCondition.class, jsonObject);
}

return null;
}

static Experiment parseExperiment(JsonObject experimentJson, String groupId, JsonDeserializationContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public TypedAudience deserialize(JsonParser parser, DeserializationContext conte

JsonNode conditionsJson = node.get("conditions");

Condition conditions = ConditionJacksonDeserializer.<UserAttribute>parseConditions(UserAttribute.class, objectMapper, conditionsJson);
Condition conditions = ConditionJacksonDeserializer.<UserAttribute>parseCondition(UserAttribute.class, objectMapper, conditionsJson);

return new TypedAudience(id, name, conditions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
public class ConditionUtils {

static public <T> Condition parseConditions(Class<T> clazz, Object object) throws InvalidAudienceCondition {

if (object instanceof List) {
List<Object> objectList = (List<Object>)object;
return ConditionUtils.<T>parseConditions(clazz, objectList);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ public class ValidProjectConfigV4 {
new AudienceIdCondition(AUDIENCE_INT_ID),
new AudienceIdCondition(AUDIENCE_DOUBLE_ID)));

// audienceConditions
private static final Condition AUDIENCE_COMBINATION_LEAF_CONDITION =
new AudienceIdCondition(AUDIENCE_BOOL_ID);

// audienceConditions
private static final Condition AUDIENCE_COMBINATION =
new OrCondition(Arrays.<Condition>asList(
Expand Down Expand Up @@ -556,6 +560,47 @@ public class ValidProjectConfigV4 {
)
)
);
private static final String LAYER_TYPEDAUDIENCE_LEAF_EXPERIMENT_ID = "1630555629";
private static final String EXPERIMENT_TYPEDAUDIENCE_LEAF_EXPERIMENT_ID = "1323241599";
public static final String EXPERIMENT_TYPEDAUDIENCE_LEAF_EXPERIMENT_KEY = "typed_audience_experiment_leaf_condition";
private static final String VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_A_ID = "1423767505";
private static final String VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_A_KEY = "A";
private static final Variation VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_A = new Variation(
VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_A_ID,
VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_A_KEY,
Collections.<LiveVariableUsageInstance>emptyList()
);
private static final String VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_B_ID = "3433458317";
private static final String VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_B_KEY = "B";
private static final Variation VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_B = new Variation(
VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_B_ID,
VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_B_KEY,
Collections.<LiveVariableUsageInstance>emptyList()
);

private static final Experiment EXPERIMENT_TYPEDAUDIENCE_LEAF_EXPERIMENT = new Experiment(
EXPERIMENT_TYPEDAUDIENCE_LEAF_EXPERIMENT_ID,
EXPERIMENT_TYPEDAUDIENCE_LEAF_EXPERIMENT_KEY,
Experiment.ExperimentStatus.RUNNING.toString(),
LAYER_TYPEDAUDIENCE_LEAF_EXPERIMENT_ID,
Collections.<String>emptyList(),
AUDIENCE_COMBINATION_LEAF_CONDITION,
ProjectConfigTestUtils.createListOfObjects(
VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_A,
VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_B
),
Collections.EMPTY_MAP,
ProjectConfigTestUtils.createListOfObjects(
new TrafficAllocation(
VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_A_ID,
5000
),
new TrafficAllocation(
VARIATION_TYPEDAUDIENCE_LEAF_EXPERIMENT_VARIATION_B_ID,
10000
)
)
);
private static final String LAYER_FIRST_GROUPED_EXPERIMENT_ID = "3301900159";
private static final String EXPERIMENT_FIRST_GROUPED_EXPERIMENT_ID = "2738374745";
private static final String EXPERIMENT_FIRST_GROUPED_EXPERIMENT_KEY = "first_grouped_experiment";
Expand Down Expand Up @@ -1282,6 +1327,7 @@ public static ProjectConfig generateValidProjectConfigV4() {
experiments.add(EXPERIMENT_BASIC_EXPERIMENT);
experiments.add(EXPERIMENT_TYPEDAUDIENCE_EXPERIMENT);
experiments.add(EXPERIMENT_TYPEDAUDIENCE_WITH_AND_EXPERIMENT);
experiments.add(EXPERIMENT_TYPEDAUDIENCE_LEAF_EXPERIMENT);
experiments.add(EXPERIMENT_MULTIVARIATE_EXPERIMENT);
experiments.add(EXPERIMENT_DOUBLE_FEATURE_EXPERIMENT);
experiments.add(EXPERIMENT_PAUSED_EXPERIMENT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
*/
package com.optimizely.ab.config.parser;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.optimizely.ab.config.ProjectConfig;
import com.optimizely.ab.config.audience.Audience;
import com.optimizely.ab.config.audience.Condition;
import com.optimizely.ab.config.audience.TypedAudience;
import com.optimizely.ab.internal.InvalidAudienceCondition;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.junit.Rule;
Expand Down Expand Up @@ -82,7 +84,7 @@ public void parseAudience() throws Exception {
jsonObject.addProperty("id", "123");
jsonObject.addProperty("name","blah");
jsonObject.addProperty("conditions",
"[\"and\", [\"or\", [\"or\", {\"name\": \"doubleKey\", \"type\": \"custom_attribute\", \"match\":\"lt\", \"value\":100.0}]]]");
"[\"and\", [\"or\", [\"or\", {\"name\": \"doubleKey\", \"type\": \"custom_attribute\", \"match\":\"exact\", \"value\":100.0}]]]");

AudienceGsonDeserializer deserializer = new AudienceGsonDeserializer();
Type audienceType = new TypeToken<List<Audience>>() {}.getType();
Expand All @@ -93,6 +95,46 @@ public void parseAudience() throws Exception {
assertNotNull(audience.getConditions());
}

@Test
public void parseAudienceLeaf() throws Exception {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("id", "123");
jsonObject.addProperty("name","blah");
jsonObject.addProperty("conditions",
"{\"name\": \"doubleKey\", \"type\": \"custom_attribute\", \"match\":\"exact\", \"value\":100.0}");

AudienceGsonDeserializer deserializer = new AudienceGsonDeserializer();
Type audienceType = new TypeToken<List<Audience>>() {}.getType();

Audience audience = deserializer.deserialize(jsonObject, audienceType, null);

assertNotNull(audience);
assertNotNull(audience.getConditions());
}

@Test
public void parseTypedAudienceLeaf() throws Exception {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("id", "123");
jsonObject.addProperty("name","blah");

JsonObject userAttribute = new JsonObject();
userAttribute.addProperty("name","doubleKey");
userAttribute.addProperty("type", "custom_attribute");
userAttribute.addProperty("match", "lt");
userAttribute.addProperty("value", 100.0);

jsonObject.add("conditions", userAttribute);

AudienceGsonDeserializer deserializer = new AudienceGsonDeserializer();
Type audienceType = new TypeToken<List<TypedAudience>>() {}.getType();

Audience audience = deserializer.deserialize(jsonObject, audienceType, null);

assertNotNull(audience);
assertNotNull(audience.getConditions());
}

@Test
public void parseInvalidAudience() throws Exception {
thrown.expect(InvalidAudienceCondition.class);
Expand Down Expand Up @@ -126,6 +168,21 @@ public void parseAudienceConditions() throws Exception {
assertNotNull(condition);
}

@Test
public void parseAudienceCondition() throws Exception {
JsonObject jsonObject = new JsonObject();

Gson gson = new Gson();


JsonElement leaf = gson.toJsonTree("1");

jsonObject.add("audienceConditions", leaf);
Condition condition = GsonHelpers.parseAudienceConditions(jsonObject);

assertNotNull(condition);
}

@Test
public void parseInvalidAudienceConditions() throws Exception {
thrown.expect(InvalidAudienceCondition.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.optimizely.ab.config.ProjectConfig;
import com.optimizely.ab.config.audience.Audience;
import com.optimizely.ab.config.audience.Condition;
import com.optimizely.ab.config.audience.TypedAudience;
import com.optimizely.ab.internal.InvalidAudienceCondition;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.junit.Rule;
Expand Down Expand Up @@ -91,6 +92,46 @@ public void parseAudience() throws Exception {
assertNotNull(audience.getConditions());
}

@Test
public void parseAudienceLeaf() throws Exception {
String audienceString =
"{" +
"\"id\": \"3468206645\"," +
"\"name\": \"DOUBLE\"," +
"\"conditions\": \"{\\\"name\\\": \\\"doubleKey\\\", \\\"type\\\": \\\"custom_attribute\\\", \\\"match\\\":\\\"lt\\\", \\\"value\\\":100.0}\"" +
"},";

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Audience.class, new AudienceJacksonDeserializer(objectMapper));
module.addDeserializer(Condition.class, new ConditionJacksonDeserializer(objectMapper));
objectMapper.registerModule(module);

Audience audience = objectMapper.readValue(audienceString, Audience.class);
assertNotNull(audience);
assertNotNull(audience.getConditions());
}

@Test
public void parseTypedAudienceLeaf() throws Exception {
String audienceString =
"{" +
"\"id\": \"3468206645\"," +
"\"name\": \"DOUBLE\"," +
"\"conditions\": {\"name\": \"doubleKey\", \"type\": \"custom_attribute\", \"match\":\"lt\", \"value\":100.0}" +
"},";

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(TypedAudience.class, new TypedAudienceJacksonDeserializer(objectMapper));
module.addDeserializer(Condition.class, new ConditionJacksonDeserializer(objectMapper));
objectMapper.registerModule(module);

Audience audience = objectMapper.readValue(audienceString, TypedAudience.class);
assertNotNull(audience);
assertNotNull(audience.getConditions());
}

@Test
public void parseInvalidAudience() throws Exception {
thrown.expect(InvalidAudienceCondition.class);
Expand All @@ -113,6 +154,20 @@ public void parseInvalidAudience() throws Exception {
assertNotNull(audience.getConditions());
}

@Test
public void parseAudienceCondition() throws Exception {
String conditionString = "\"123\"";

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Audience.class, new AudienceJacksonDeserializer(objectMapper));
module.addDeserializer(Condition.class, new ConditionJacksonDeserializer(objectMapper));
objectMapper.registerModule(module);

Condition condition = objectMapper.readValue(conditionString, Condition.class);
assertNotNull(condition);
}

@Test
public void parseAudienceConditions() throws Exception {
String conditionString =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,20 @@ public void parseAudience() throws Exception {
assertNotNull(condition);
}

@Test
public void parseAudienceLeaf() throws Exception {
JSONObject jsonObject = new JSONObject();

jsonObject.append("id", "123");
jsonObject.append("name","blah");
jsonObject.append("conditions",
"{\"name\": \"doubleKey\", \"type\": \"custom_attribute\", \"match\":\"lt\", \"value\":100.0}");

Condition<UserAttribute> condition = ConditionUtils.parseConditions(UserAttribute.class, new JSONObject("{\"name\": \"doubleKey\", \"type\": \"custom_attribute\", \"match\":\"lt\", \"value\":100.0}"));

assertNotNull(condition);
}

@Test
public void parseInvalidAudience() throws Exception {
thrown.expect(InvalidAudienceCondition.class);
Expand All @@ -100,6 +114,14 @@ public void parseInvalidAudience() throws Exception {
ConditionUtils.parseConditions(UserAttribute.class, new JSONArray("[\"and\", [\"or\", [\"or\", \"123\"]]]"));
}

@Test
public void parseAudienceCondition() throws Exception {
String conditions = "1";

Condition condition = ConditionUtils.parseConditions(AudienceIdCondition.class, conditions);
assertNotNull(condition);
}

@Test
public void parseAudienceConditions() throws Exception {
JSONArray conditions = new JSONArray();
Expand Down
Loading