From e3c2c39b260c95d6c198c2c7eb69504fa799f389 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Sat, 19 Aug 2017 19:29:50 -0700 Subject: [PATCH 01/16] add rollouts list to v4 json --- core-api/src/test/resources/config/valid-project-config-v4.json | 1 + 1 file changed, 1 insertion(+) diff --git a/core-api/src/test/resources/config/valid-project-config-v4.json b/core-api/src/test/resources/config/valid-project-config-v4.json index 165704d20..4bd44d876 100644 --- a/core-api/src/test/resources/config/valid-project-config-v4.json +++ b/core-api/src/test/resources/config/valid-project-config-v4.json @@ -469,5 +469,6 @@ ] } ], + "rollouts": [], "variables": [] } From 0d1945bfe0f8ac55b7efbe83bd7ac17c3ec53875 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Sat, 19 Aug 2017 19:30:22 -0700 Subject: [PATCH 02/16] add list of rollouts to ProjectConfig and constructor. Add to all usages of ProjectConfig v4 constructor to allow compilation --- .../com/optimizely/ab/config/ProjectConfig.java | 13 +++++++++++-- .../ab/config/parser/JsonConfigParser.java | 6 +++++- .../ab/config/parser/JsonSimpleConfigParser.java | 6 +++++- .../parser/ProjectConfigGsonDeserializer.java | 6 +++++- .../parser/ProjectConfigJacksonDeserializer.java | 6 +++++- .../optimizely/ab/config/ValidProjectConfigV4.java | 7 ++++++- 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java b/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java index ffb891e29..69de84315 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java +++ b/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java @@ -66,6 +66,7 @@ public String toString() { private final List featureFlags; private final List groups; private final List liveVariables; + private final List rollouts; // key to entity mappings private final Map attributeKeyMapping; @@ -108,7 +109,8 @@ public ProjectConfig(String accountId, String projectId, String version, String experiments, null, groups, - liveVariables + liveVariables, + null ); } @@ -124,7 +126,8 @@ public ProjectConfig(String accountId, List experiments, List featureFlags, List groups, - List liveVariables) { + List liveVariables, + List rollouts) { this.accountId = accountId; this.projectId = projectId; @@ -141,6 +144,12 @@ public ProjectConfig(String accountId, else { this.featureFlags = Collections.unmodifiableList(featureFlags); } + if (rollouts == null) { + this.rollouts = Collections.emptyList(); + } + else { + this.rollouts = Collections.unmodifiableList(rollouts); + } this.groups = Collections.unmodifiableList(groups); diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java index 79d486f09..a3e14d9dc 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java @@ -27,6 +27,7 @@ import com.optimizely.ab.config.LiveVariable.VariableType; import com.optimizely.ab.config.LiveVariableUsageInstance; import com.optimizely.ab.config.ProjectConfig; +import com.optimizely.ab.config.Rollout; import com.optimizely.ab.config.TrafficAllocation; import com.optimizely.ab.config.Variation; import com.optimizely.ab.config.audience.AndCondition; @@ -79,8 +80,10 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse } List featureFlags = null; + List rollouts = null; if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { featureFlags = parseFeatureFlags(rootObject.getJSONArray("featureFlags")); + //TODO: Josh W. parse rollouts } return new ProjectConfig( @@ -95,7 +98,8 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse experiments, featureFlags, groups, - liveVariables + liveVariables, + rollouts ); } catch (Exception e) { throw new ConfigParseException("Unable to parse datafile: " + json, e); diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java index 736ab80ad..17354c18b 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java @@ -27,6 +27,7 @@ import com.optimizely.ab.config.LiveVariable.VariableType; import com.optimizely.ab.config.LiveVariableUsageInstance; import com.optimizely.ab.config.ProjectConfig; +import com.optimizely.ab.config.Rollout; import com.optimizely.ab.config.TrafficAllocation; import com.optimizely.ab.config.Variation; import com.optimizely.ab.config.audience.AndCondition; @@ -81,8 +82,10 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse } List featureFlags = null; + List rollouts = null; if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { featureFlags = parseFeatureFlags((JSONArray) rootObject.get("featureFlags")); + //TODO: Josh W. parse rollouts } return new ProjectConfig( @@ -97,7 +100,8 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse experiments, featureFlags, groups, - liveVariables + liveVariables, + rollouts ); } catch (Exception e) { throw new ConfigParseException("Unable to parse datafile: " + json, e); diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java index 3f4df5210..e692806fd 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java @@ -29,6 +29,7 @@ import com.optimizely.ab.config.Group; import com.optimizely.ab.config.LiveVariable; import com.optimizely.ab.config.ProjectConfig; +import com.optimizely.ab.config.Rollout; import com.optimizely.ab.config.audience.Audience; import java.lang.reflect.Type; @@ -80,9 +81,11 @@ public ProjectConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializa } List featureFlags = null; + List rollouts = null; if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { Type featureFlagsType = new TypeToken>() {}.getType(); featureFlags = context.deserialize(jsonObject.getAsJsonArray("featureFlags"), featureFlagsType); + //TODO: Josh W. parse rollouts } return new ProjectConfig( @@ -97,7 +100,8 @@ public ProjectConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializa experiments, featureFlags, groups, - liveVariables + liveVariables, + rollouts ); } } diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java index 04503c150..12f189d03 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java @@ -30,6 +30,7 @@ import com.optimizely.ab.config.Group; import com.optimizely.ab.config.LiveVariable; import com.optimizely.ab.config.ProjectConfig; +import com.optimizely.ab.config.Rollout; import com.optimizely.ab.config.audience.Audience; import java.io.IOException; @@ -74,9 +75,11 @@ public ProjectConfig deserialize(JsonParser parser, DeserializationContext conte } List featureFlags = null; + List rollouts = null; if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { featureFlags = mapper.readValue(node.get("featureFlags").toString(), new TypeReference>() {}); + //TODO: Josh W. parse rollouts } return new ProjectConfig( @@ -91,7 +94,8 @@ public ProjectConfig deserialize(JsonParser parser, DeserializationContext conte experiments, featureFlags, groups, - liveVariables + liveVariables, + rollouts ); } } \ No newline at end of file diff --git a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java index e163abd52..fe2ee3722 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java +++ b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java @@ -23,6 +23,7 @@ import com.optimizely.ab.config.audience.UserAttribute; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -705,6 +706,9 @@ public static ProjectConfig generateValidProjectConfigV4() { groups.add(GROUP_1); groups.add(GROUP_2); + // list rollouts + List rollouts = new ArrayList(); + return new ProjectConfig( ACCOUNT_ID, ANONYMIZE_IP, @@ -717,7 +721,8 @@ public static ProjectConfig generateValidProjectConfigV4() { experiments, featureFlags, groups, - Collections.emptyList() + Collections.emptyList(), + rollouts ); } } From ae158aeea4de50bc5067ee4e429a8fd461f2ee03 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Sat, 19 Aug 2017 22:23:12 -0700 Subject: [PATCH 03/16] add basic rollout to v4 json --- .../config/valid-project-config-v4.json | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/core-api/src/test/resources/config/valid-project-config-v4.json b/core-api/src/test/resources/config/valid-project-config-v4.json index 4bd44d876..ccd428d48 100644 --- a/core-api/src/test/resources/config/valid-project-config-v4.json +++ b/core-api/src/test/resources/config/valid-project-config-v4.json @@ -423,7 +423,7 @@ { "id": "2079378557", "key": "string_single_variable_feature", - "rolloutId": "", + "rolloutId": "1058508303", "experimentIds": [], "variables": [ { @@ -469,6 +469,38 @@ ] } ], - "rollouts": [], + "rollouts": [ + { + "id": "1058508303", // mmh3.hash("rollout_1") + "policy": "rollout", + "experiments": [ + { + "id": "1785077004", + "key": "rollout_1_everyone_else_rule", + "status": "Running", + "layerId": "1058508303", + "audienceIds": [], + "variations": [ + { + "id": "1566407342", + "key": "rollout_1_everyone_else_rule_enabled_variation", + "variables": [ + { + "id": "2077511132", + "value": "lumos" + } + ] + } + ], + "trafficAllocation": [ + { + "entityId": "1566407342", + "endOfRange": 5000 + } + ] + } + ] + } + ], "variables": [] } From 9b13dc93c7e5fa908e3c740a318f335b332fa622 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 10:14:35 -0700 Subject: [PATCH 04/16] parse 1 rollout --- .../com/optimizely/ab/config/Rollout.java | 14 ++++++ .../ab/config/ValidProjectConfigV4.java | 44 ++++++++++++++++++- .../config/valid-project-config-v4.json | 2 +- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/core-api/src/main/java/com/optimizely/ab/config/Rollout.java b/core-api/src/main/java/com/optimizely/ab/config/Rollout.java index 06b8af1b3..5805b02ce 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/Rollout.java +++ b/core-api/src/main/java/com/optimizely/ab/config/Rollout.java @@ -27,6 +27,20 @@ @Immutable public class Rollout extends Layer implements IdMapped { + public enum RolloutPolicy { + ROLLOUT ("rollout"); + + private final String rolloutPolicy; + + RolloutPolicy(String rolloutPolicy) { + this.rolloutPolicy = rolloutPolicy; + } + + public String toString() { + return rolloutPolicy; + } + } + public Rollout(String id, String policy, List experiments) { diff --git a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java index fe2ee3722..3db48fc6c 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java +++ b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java @@ -23,7 +23,6 @@ import com.optimizely.ab.config.audience.UserAttribute; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -144,7 +143,7 @@ public class ValidProjectConfigV4 { private static final FeatureFlag FEATURE_FLAG_SINGLE_VARIABLE_STRING = new FeatureFlag( FEATURE_SINGLE_VARIABLE_STRING_ID, FEATURE_SINGLE_VARIABLE_STRING_KEY, - "", + "1058508303", Collections.emptyList(), Collections.singletonList( VARIABLE_STRING_VARIABLE @@ -668,6 +667,46 @@ public class ValidProjectConfigV4 { ) ); + private static final String ROLLOUT_1_ID = "1058508303"; + private static final String ROLLOUT_1_EVERYONE_ELSE_EXPERIMENT_ID = "1785077004"; + private static final String ROLLOUT_1_EVERYONE_ELSE_EXPERIMENT_KEY = "rollout_1_everyone_else_rule"; + private static final String ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_ID = "1566407342"; + private static final String ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_KEY = "rollout_1_everyone_else_rule_enabled_variation"; + private static final String ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_STRING_VALUE = "lumos"; + private static final Variation ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION = new Variation( + ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_ID, + ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_KEY, + Collections.singletonList( + new LiveVariableUsageInstance( + FEATURE_SINGLE_VARIABLE_STRING_ID, + ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_STRING_VALUE + ) + ) + ); + private static final Experiment ROLLOUT_1_EVERYONE_ELSE_RULE = new Experiment( + ROLLOUT_1_EVERYONE_ELSE_EXPERIMENT_ID, + ROLLOUT_1_EVERYONE_ELSE_EXPERIMENT_KEY, + Experiment.ExperimentStatus.RUNNING.toString(), + ROLLOUT_1_ID, + Collections.emptyList(), + Collections.singletonList( + ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION + ), + Collections.emptyMap(), + Collections.singletonList( + new TrafficAllocation( + ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_ID, + 5000 + ) + ) + ); + private static final Rollout ROLLOUT_1 = new Rollout( + ROLLOUT_1_ID, + Rollout.RolloutPolicy.ROLLOUT.toString(), + Collections.singletonList( + ROLLOUT_1_EVERYONE_ELSE_RULE + ) + ); public static ProjectConfig generateValidProjectConfigV4() { @@ -708,6 +747,7 @@ public static ProjectConfig generateValidProjectConfigV4() { // list rollouts List rollouts = new ArrayList(); + rollouts.add(ROLLOUT_1); return new ProjectConfig( ACCOUNT_ID, diff --git a/core-api/src/test/resources/config/valid-project-config-v4.json b/core-api/src/test/resources/config/valid-project-config-v4.json index ccd428d48..d9d4078cc 100644 --- a/core-api/src/test/resources/config/valid-project-config-v4.json +++ b/core-api/src/test/resources/config/valid-project-config-v4.json @@ -471,7 +471,7 @@ ], "rollouts": [ { - "id": "1058508303", // mmh3.hash("rollout_1") + "id": "1058508303", "policy": "rollout", "experiments": [ { From 75b61c45fcb008807b35f7d5f382b6df93807b05 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 11:44:36 -0700 Subject: [PATCH 05/16] add rollout policy enum to layer.java --- .../main/java/com/optimizely/ab/config/Layer.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core-api/src/main/java/com/optimizely/ab/config/Layer.java b/core-api/src/main/java/com/optimizely/ab/config/Layer.java index dc4c476b4..6bf5dc7b5 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/Layer.java +++ b/core-api/src/main/java/com/optimizely/ab/config/Layer.java @@ -36,8 +36,20 @@ public class Layer implements IdMapped { protected final String id; protected final String policy; protected final List experiments; + public enum LayerPolicy { + ROLLOUT ("rollout"), + SINGLE_EXPERIMENT ("single_experiment"); - public static final String SINGLE_EXPERIMENT_POLICY = "single_experiment"; + private final String layerPolicy; + + LayerPolicy(String layerPolicy) { + this.layerPolicy = layerPolicy; + } + + public String toString() { + return layerPolicy; + } + } @JsonCreator public Layer(@JsonProperty("id") String id, From 9cc41080f4c8edebeb19ea0d0e7335dfc86e5acc Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 11:46:04 -0700 Subject: [PATCH 06/16] fix some mistakes in expected v4 project config --- .../java/com/optimizely/ab/config/ValidProjectConfigV4.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java index 3db48fc6c..e10045df6 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java +++ b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java @@ -678,7 +678,7 @@ public class ValidProjectConfigV4 { ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_KEY, Collections.singletonList( new LiveVariableUsageInstance( - FEATURE_SINGLE_VARIABLE_STRING_ID, + VARIABLE_STRING_VARIABLE_ID, ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_STRING_VALUE ) ) @@ -692,7 +692,7 @@ public class ValidProjectConfigV4 { Collections.singletonList( ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION ), - Collections.emptyMap(), + null, Collections.singletonList( new TrafficAllocation( ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_ID, @@ -702,7 +702,7 @@ public class ValidProjectConfigV4 { ); private static final Rollout ROLLOUT_1 = new Rollout( ROLLOUT_1_ID, - Rollout.RolloutPolicy.ROLLOUT.toString(), + Layer.LayerPolicy.ROLLOUT.toString(), Collections.singletonList( ROLLOUT_1_EVERYONE_ELSE_RULE ) From cfcb4fba6f421b8d68049c12fe15e9c60e540cea Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 11:46:28 -0700 Subject: [PATCH 07/16] add rollouts getter and update toString of ProjectConfig --- .../optimizely/ab/config/ProjectConfig.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java b/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java index 69de84315..77e69ad2e 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java +++ b/core-api/src/main/java/com/optimizely/ab/config/ProjectConfig.java @@ -252,6 +252,10 @@ public List getFeatureFlags() { return featureFlags; } + public List getRollouts() { + return rollouts; + } + public List getAttributes() { return attributes; } @@ -321,22 +325,26 @@ public String toString() { ", projectId='" + projectId + '\'' + ", revision='" + revision + '\'' + ", version='" + version + '\'' + - ", anonymizeIP='" + anonymizeIP + '\'' + - ", groups=" + groups + - ", experiments=" + experiments + + ", anonymizeIP=" + anonymizeIP + ", attributes=" + attributes + - ", events=" + events + ", audiences=" + audiences + + ", events=" + events + + ", experiments=" + experiments + + ", featureFlags=" + featureFlags + + ", groups=" + groups + ", liveVariables=" + liveVariables + - ", experimentKeyMapping=" + experimentKeyMapping + + ", rollouts=" + rollouts + ", attributeKeyMapping=" + attributeKeyMapping + - ", liveVariableKeyMapping=" + liveVariableKeyMapping + ", eventNameMapping=" + eventNameMapping + + ", experimentKeyMapping=" + experimentKeyMapping + + ", featureKeyMapping=" + featureKeyMapping + + ", liveVariableKeyMapping=" + liveVariableKeyMapping + ", audienceIdMapping=" + audienceIdMapping + ", experimentIdMapping=" + experimentIdMapping + ", groupIdMapping=" + groupIdMapping + ", liveVariableIdToExperimentsMapping=" + liveVariableIdToExperimentsMapping + ", variationToLiveVariableUsageInstanceMapping=" + variationToLiveVariableUsageInstanceMapping + + ", variationIdToExperimentMapping=" + variationIdToExperimentMapping + '}'; } } From 02c92bbc3cf512143f3ff001651028d5b7094ca0 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 11:46:53 -0700 Subject: [PATCH 08/16] add method to verify rollouts in parsing --- .../ab/config/ProjectConfigTestUtils.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java b/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java index fa4a43a25..e9ab52a23 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java +++ b/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java @@ -457,6 +457,7 @@ public static void verifyProjectConfig(@CheckForNull ProjectConfig actual, @Nonn verifyFeatureFlags(actual.getFeatureFlags(), expected.getFeatureFlags()); verifyLiveVariables(actual.getLiveVariables(), expected.getLiveVariables()); verifyGroups(actual.getGroups(), expected.getGroups()); + verifyRollouts(actual.getRollouts(), expected.getRollouts()); } /** @@ -617,6 +618,24 @@ private static void verifyLiveVariables(List actual, List actual, List expected) { + if (expected == null) { + assertNull(actual); + } + else { + assertEquals(expected.size(), actual.size()); + + for (int i = 0; i < actual.size(); i++) { + Rollout actualRollout = actual.get(i); + Rollout expectedRollout = expected.get(i); + + assertEquals(expectedRollout.getId(), actualRollout.getId()); + assertEquals(expectedRollout.getPolicy(), actualRollout.getPolicy()); + verifyExperiments(actualRollout.getExperiments(), expectedRollout.getExperiments()); + } + } + } + /** * Verify that the provided variation-level live variable usage instances are equivalent. */ From 1ca08bdb3f9a41c797dc665291ccd15e51c52aff Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 11:47:08 -0700 Subject: [PATCH 09/16] add json properties to rollout for parsing --- .../com/optimizely/ab/config/Rollout.java | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/core-api/src/main/java/com/optimizely/ab/config/Rollout.java b/core-api/src/main/java/com/optimizely/ab/config/Rollout.java index 5805b02ce..27428a381 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/Rollout.java +++ b/core-api/src/main/java/com/optimizely/ab/config/Rollout.java @@ -16,6 +16,9 @@ */ package com.optimizely.ab.config; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + import javax.annotation.concurrent.Immutable; import java.util.List; @@ -27,23 +30,10 @@ @Immutable public class Rollout extends Layer implements IdMapped { - public enum RolloutPolicy { - ROLLOUT ("rollout"); - - private final String rolloutPolicy; - - RolloutPolicy(String rolloutPolicy) { - this.rolloutPolicy = rolloutPolicy; - } - - public String toString() { - return rolloutPolicy; - } - } - - public Rollout(String id, - String policy, - List experiments) { + @JsonCreator + public Rollout(@JsonProperty("id") String id, + @JsonProperty("policy") String policy, + @JsonProperty("experiments") List experiments) { super(id, policy, experiments); } From ed65577e4901f00d23d8dd87df9e504cdeb30d72 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 11:47:33 -0700 Subject: [PATCH 10/16] enable Jackson to parse rollouts --- .../ab/config/parser/ProjectConfigJacksonDeserializer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java index 12f189d03..6ebd3c4ec 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigJacksonDeserializer.java @@ -79,7 +79,8 @@ public ProjectConfig deserialize(JsonParser parser, DeserializationContext conte if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { featureFlags = mapper.readValue(node.get("featureFlags").toString(), new TypeReference>() {}); - //TODO: Josh W. parse rollouts + rollouts = mapper.readValue(node.get("rollouts").toString(), + new TypeReference>(){}); } return new ProjectConfig( From f8205f607d8a3a0ef0f43186fb02d6e884709c09 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 11:57:52 -0700 Subject: [PATCH 11/16] add empty forcedVariations map to datafile --- .../ab/config/parser/ProjectConfigGsonDeserializer.java | 3 ++- .../java/com/optimizely/ab/config/ValidProjectConfigV4.java | 2 +- .../src/test/resources/config/valid-project-config-v4.json | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java index e692806fd..c9718d851 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/ProjectConfigGsonDeserializer.java @@ -85,7 +85,8 @@ public ProjectConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializa if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { Type featureFlagsType = new TypeToken>() {}.getType(); featureFlags = context.deserialize(jsonObject.getAsJsonArray("featureFlags"), featureFlagsType); - //TODO: Josh W. parse rollouts + Type rolloutsType = new TypeToken>() {}.getType(); + rollouts = context.deserialize(jsonObject.get("rollouts").getAsJsonArray(), rolloutsType); } return new ProjectConfig( diff --git a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java index e10045df6..36b97ee13 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java +++ b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java @@ -692,7 +692,7 @@ public class ValidProjectConfigV4 { Collections.singletonList( ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION ), - null, + Collections.emptyMap(), Collections.singletonList( new TrafficAllocation( ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_ID, diff --git a/core-api/src/test/resources/config/valid-project-config-v4.json b/core-api/src/test/resources/config/valid-project-config-v4.json index d9d4078cc..5a4499e4e 100644 --- a/core-api/src/test/resources/config/valid-project-config-v4.json +++ b/core-api/src/test/resources/config/valid-project-config-v4.json @@ -480,6 +480,7 @@ "status": "Running", "layerId": "1058508303", "audienceIds": [], + "forcedVariations": {}, "variations": [ { "id": "1566407342", From fe4bef2b784eac9307be621e4fb149996ccf9114 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 12:01:34 -0700 Subject: [PATCH 12/16] enable parsing for org.JSON --- .../ab/config/parser/JsonConfigParser.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java index a3e14d9dc..414e14bdf 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java @@ -83,7 +83,7 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse List rollouts = null; if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { featureFlags = parseFeatureFlags(rootObject.getJSONArray("featureFlags")); - //TODO: Josh W. parse rollouts + rollouts = parseRollouts(rootObject.getJSONArray("rollouts")); } return new ProjectConfig( @@ -348,4 +348,19 @@ private List parseLiveVariableInstances(JSONArray liv return liveVariableUsageInstances; } + + private List parseRollouts(JSONArray rolloutsJson) { + List rollouts = new ArrayList(rolloutsJson.length()); + + for (Object obj : rolloutsJson) { + JSONObject rolloutObject = (JSONObject) obj; + String id = rolloutObject.getString("id"); + String policy = rolloutObject.getString("policy"); + List experiments = parseExperiments(rolloutObject.getJSONArray("experiments")); + + rollouts.add(new Rollout(id, policy, experiments)); + } + + return rollouts; + } } From d2280eccbedf960b77a1491555302b1ff59b2298 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 17:45:19 -0700 Subject: [PATCH 13/16] enable json simple parsing --- .../config/parser/JsonSimpleConfigParser.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java index 17354c18b..18f4f0c5c 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java @@ -85,7 +85,7 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse List rollouts = null; if (datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { featureFlags = parseFeatureFlags((JSONArray) rootObject.get("featureFlags")); - //TODO: Josh W. parse rollouts + rollouts = parseRollouts((JSONArray) rootObject.get("rollouts")); } return new ProjectConfig( @@ -352,5 +352,20 @@ private List parseLiveVariableInstances(JSONArray liv return liveVariableUsageInstances; } + + private List parseRollouts(JSONArray rolloutsJson) { + List rollouts = new ArrayList(rolloutsJson.size()); + + for (Object obj : rolloutsJson) { + JSONObject rolloutObject = (JSONObject) obj; + String id = (String) rolloutObject.get("id"); + String policy = (String) rolloutObject.get("policy"); + List experiments = parseExperiments((JSONArray) rolloutObject.get("experiments")); + + rollouts.add(new Rollout(id, policy, experiments)); + } + + return rollouts; + } } From ef7a88661492330f317c641c3a84b17bd5ce884b Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Mon, 21 Aug 2017 17:53:22 -0700 Subject: [PATCH 14/16] remove Layer.java class and remove 'policy' property of a Rollout --- .../java/com/optimizely/ab/config/Layer.java | 83 ------------------- .../com/optimizely/ab/config/Rollout.java | 21 ++++- .../ab/config/parser/JsonConfigParser.java | 3 +- .../config/parser/JsonSimpleConfigParser.java | 3 +- .../ab/config/ProjectConfigTestUtils.java | 1 - .../ab/config/ValidProjectConfigV4.java | 1 - .../config/valid-project-config-v4.json | 1 - 7 files changed, 19 insertions(+), 94 deletions(-) delete mode 100644 core-api/src/main/java/com/optimizely/ab/config/Layer.java diff --git a/core-api/src/main/java/com/optimizely/ab/config/Layer.java b/core-api/src/main/java/com/optimizely/ab/config/Layer.java deleted file mode 100644 index 6bf5dc7b5..000000000 --- a/core-api/src/main/java/com/optimizely/ab/config/Layer.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * - * Copyright 2017, Optimizely and contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.optimizely.ab.config; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -import javax.annotation.concurrent.Immutable; - -/** - * Represents a Optimizely Layer configuration - * - * @see Project JSON - */ -@Immutable -@JsonIgnoreProperties(ignoreUnknown = true) -public class Layer implements IdMapped { - - protected final String id; - protected final String policy; - protected final List experiments; - public enum LayerPolicy { - ROLLOUT ("rollout"), - SINGLE_EXPERIMENT ("single_experiment"); - - private final String layerPolicy; - - LayerPolicy(String layerPolicy) { - this.layerPolicy = layerPolicy; - } - - public String toString() { - return layerPolicy; - } - } - - @JsonCreator - public Layer(@JsonProperty("id") String id, - @JsonProperty("policy") String policy, - @JsonProperty("experiments") List experiments) { - this.id = id; - this.policy = policy; - this.experiments = experiments; - } - - public String getId() { - return id; - } - - public String getPolicy() { - return policy; - } - - public List getExperiments() { - return experiments; - } - - @Override - public String toString() { - return "Layer{" + - "id='" + id + '\'' + - ", policy='" + policy + '\'' + - ", experiments=" + experiments + - '}'; - } -} diff --git a/core-api/src/main/java/com/optimizely/ab/config/Rollout.java b/core-api/src/main/java/com/optimizely/ab/config/Rollout.java index 27428a381..b36f33838 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/Rollout.java +++ b/core-api/src/main/java/com/optimizely/ab/config/Rollout.java @@ -17,6 +17,7 @@ package com.optimizely.ab.config; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import javax.annotation.concurrent.Immutable; @@ -28,20 +29,32 @@ * @see Project JSON */ @Immutable -public class Rollout extends Layer implements IdMapped { +@JsonIgnoreProperties(ignoreUnknown = true) +public class Rollout implements IdMapped { + + private final String id; + private final List experiments; @JsonCreator public Rollout(@JsonProperty("id") String id, - @JsonProperty("policy") String policy, @JsonProperty("experiments") List experiments) { - super(id, policy, experiments); + this.id = id; + this.experiments = experiments; + } + + @Override + public String getId() { + return id; + } + + public List getExperiments() { + return experiments; } @Override public String toString() { return "Rollout{" + "id='" + id + '\'' + - ", policy='" + policy + '\'' + ", experiments=" + experiments + '}'; } diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java index 414e14bdf..1b2af1079 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java @@ -355,10 +355,9 @@ private List parseRollouts(JSONArray rolloutsJson) { for (Object obj : rolloutsJson) { JSONObject rolloutObject = (JSONObject) obj; String id = rolloutObject.getString("id"); - String policy = rolloutObject.getString("policy"); List experiments = parseExperiments(rolloutObject.getJSONArray("experiments")); - rollouts.add(new Rollout(id, policy, experiments)); + rollouts.add(new Rollout(id, experiments)); } return rollouts; diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java index 18f4f0c5c..be106665d 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java @@ -359,10 +359,9 @@ private List parseRollouts(JSONArray rolloutsJson) { for (Object obj : rolloutsJson) { JSONObject rolloutObject = (JSONObject) obj; String id = (String) rolloutObject.get("id"); - String policy = (String) rolloutObject.get("policy"); List experiments = parseExperiments((JSONArray) rolloutObject.get("experiments")); - rollouts.add(new Rollout(id, policy, experiments)); + rollouts.add(new Rollout(id, experiments)); } return rollouts; diff --git a/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java b/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java index e9ab52a23..c072d79ee 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java +++ b/core-api/src/test/java/com/optimizely/ab/config/ProjectConfigTestUtils.java @@ -630,7 +630,6 @@ private static void verifyRollouts(List actual, List expected) Rollout expectedRollout = expected.get(i); assertEquals(expectedRollout.getId(), actualRollout.getId()); - assertEquals(expectedRollout.getPolicy(), actualRollout.getPolicy()); verifyExperiments(actualRollout.getExperiments(), expectedRollout.getExperiments()); } } diff --git a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java index 36b97ee13..5680e007c 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java +++ b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java @@ -702,7 +702,6 @@ public class ValidProjectConfigV4 { ); private static final Rollout ROLLOUT_1 = new Rollout( ROLLOUT_1_ID, - Layer.LayerPolicy.ROLLOUT.toString(), Collections.singletonList( ROLLOUT_1_EVERYONE_ELSE_RULE ) diff --git a/core-api/src/test/resources/config/valid-project-config-v4.json b/core-api/src/test/resources/config/valid-project-config-v4.json index 5a4499e4e..ea2682a31 100644 --- a/core-api/src/test/resources/config/valid-project-config-v4.json +++ b/core-api/src/test/resources/config/valid-project-config-v4.json @@ -472,7 +472,6 @@ "rollouts": [ { "id": "1058508303", - "policy": "rollout", "experiments": [ { "id": "1785077004", From bb8288355f6c50db193663dd806b1c2dd4ed5421 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Tue, 22 Aug 2017 09:19:19 -0700 Subject: [PATCH 15/16] rollout experiment and variation keys will be the same as id --- .../src/test/resources/config/valid-project-config-v4.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-api/src/test/resources/config/valid-project-config-v4.json b/core-api/src/test/resources/config/valid-project-config-v4.json index ea2682a31..e56b804ed 100644 --- a/core-api/src/test/resources/config/valid-project-config-v4.json +++ b/core-api/src/test/resources/config/valid-project-config-v4.json @@ -475,7 +475,7 @@ "experiments": [ { "id": "1785077004", - "key": "rollout_1_everyone_else_rule", + "key": "1785077004", "status": "Running", "layerId": "1058508303", "audienceIds": [], @@ -483,7 +483,7 @@ "variations": [ { "id": "1566407342", - "key": "rollout_1_everyone_else_rule_enabled_variation", + "key": "1566407342", "variables": [ { "id": "2077511132", From 339411f146d1838a63cb35a95c7940c77d08d22e Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Tue, 22 Aug 2017 09:20:21 -0700 Subject: [PATCH 16/16] change excpected project config data --- .../java/com/optimizely/ab/config/ValidProjectConfigV4.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java index 5680e007c..b073b04d6 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java +++ b/core-api/src/test/java/com/optimizely/ab/config/ValidProjectConfigV4.java @@ -669,13 +669,11 @@ public class ValidProjectConfigV4 { private static final String ROLLOUT_1_ID = "1058508303"; private static final String ROLLOUT_1_EVERYONE_ELSE_EXPERIMENT_ID = "1785077004"; - private static final String ROLLOUT_1_EVERYONE_ELSE_EXPERIMENT_KEY = "rollout_1_everyone_else_rule"; private static final String ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_ID = "1566407342"; - private static final String ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_KEY = "rollout_1_everyone_else_rule_enabled_variation"; private static final String ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_STRING_VALUE = "lumos"; private static final Variation ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION = new Variation( ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_ID, - ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_KEY, + ROLLOUT_1_EVERYONE_ELSE_RULE_ENABLED_VARIATION_ID, Collections.singletonList( new LiveVariableUsageInstance( VARIABLE_STRING_VARIABLE_ID, @@ -685,7 +683,7 @@ public class ValidProjectConfigV4 { ); private static final Experiment ROLLOUT_1_EVERYONE_ELSE_RULE = new Experiment( ROLLOUT_1_EVERYONE_ELSE_EXPERIMENT_ID, - ROLLOUT_1_EVERYONE_ELSE_EXPERIMENT_KEY, + ROLLOUT_1_EVERYONE_ELSE_EXPERIMENT_ID, Experiment.ExperimentStatus.RUNNING.toString(), ROLLOUT_1_ID, Collections.emptyList(),