diff --git a/core-api/src/main/java/com/optimizely/ab/Optimizely.java b/core-api/src/main/java/com/optimizely/ab/Optimizely.java index babd21feb..652c732d5 100644 --- a/core-api/src/main/java/com/optimizely/ab/Optimizely.java +++ b/core-api/src/main/java/com/optimizely/ab/Optimizely.java @@ -35,9 +35,8 @@ import com.optimizely.ab.event.EventHandler; import com.optimizely.ab.event.LogEvent; import com.optimizely.ab.event.internal.BuildVersionInfo; -import com.optimizely.ab.event.internal.EventBuilder; +import com.optimizely.ab.event.internal.EventFactory; import com.optimizely.ab.event.internal.payload.EventBatch.ClientEngine; -import com.optimizely.ab.internal.ControlAttribute; import com.optimizely.ab.notification.NotificationCenter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,7 +81,7 @@ public class Optimizely { private static final Logger logger = LoggerFactory.getLogger(Optimizely.class); @VisibleForTesting final DecisionService decisionService; - @VisibleForTesting final EventBuilder eventBuilder; + @VisibleForTesting final EventFactory eventFactory; @VisibleForTesting final ProjectConfig projectConfig; @VisibleForTesting final EventHandler eventHandler; @VisibleForTesting final ErrorHandler errorHandler; @@ -93,13 +92,13 @@ public class Optimizely { private Optimizely(@Nonnull ProjectConfig projectConfig, @Nonnull DecisionService decisionService, @Nonnull EventHandler eventHandler, - @Nonnull EventBuilder eventBuilder, + @Nonnull EventFactory eventFactory, @Nonnull ErrorHandler errorHandler, @Nullable UserProfileService userProfileService) { this.projectConfig = projectConfig; this.decisionService = decisionService; this.eventHandler = eventHandler; - this.eventBuilder = eventBuilder; + this.eventFactory = eventFactory; this.errorHandler = errorHandler; this.userProfileService = userProfileService; } @@ -193,7 +192,7 @@ private void sendImpression(@Nonnull ProjectConfig projectConfig, @Nonnull Map filteredAttributes, @Nonnull Variation variation) { if (experiment.isRunning()) { - LogEvent impressionEvent = eventBuilder.createImpressionEvent( + LogEvent impressionEvent = eventFactory.createImpressionEvent( projectConfig, experiment, variation, @@ -279,7 +278,7 @@ public void track(@Nonnull String eventName, } // create the conversion event request parameters, then dispatch - LogEvent conversionEvent = eventBuilder.createConversionEvent( + LogEvent conversionEvent = eventFactory.createConversionEvent( projectConfig, experimentVariationMap, userId, @@ -829,7 +828,7 @@ public static class Builder { private DecisionService decisionService; private ErrorHandler errorHandler; private EventHandler eventHandler; - private EventBuilder eventBuilder; + private EventFactory eventFactory; private ClientEngine clientEngine; private String clientVersion; private ProjectConfig projectConfig; @@ -871,8 +870,8 @@ public Builder withClientVersion(String clientVersion) { return this; } - protected Builder withEventBuilder(EventBuilder eventBuilder) { - this.eventBuilder = eventBuilder; + protected Builder withEventBuilder(EventFactory eventFactory) { + this.eventFactory = eventFactory; return this; } @@ -900,8 +899,8 @@ public Optimizely build() throws ConfigParseException { } - if (eventBuilder == null) { - eventBuilder = new EventBuilder(clientEngine, clientVersion); + if (eventFactory == null) { + eventFactory = new EventFactory(clientEngine, clientVersion); } if (errorHandler == null) { @@ -912,7 +911,7 @@ public Optimizely build() throws ConfigParseException { decisionService = new DecisionService(bucketer, errorHandler, projectConfig, userProfileService); } - Optimizely optimizely = new Optimizely(projectConfig, decisionService, eventHandler, eventBuilder, errorHandler, userProfileService); + Optimizely optimizely = new Optimizely(projectConfig, decisionService, eventHandler, eventFactory, errorHandler, userProfileService); optimizely.initialize(); return optimizely; } diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/EventBuilder.java b/core-api/src/main/java/com/optimizely/ab/event/internal/EventBuilder.java deleted file mode 100644 index 96f8161d9..000000000 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/EventBuilder.java +++ /dev/null @@ -1,144 +0,0 @@ -/** - * - * Copyright 2016-2018, 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.event.internal; - -import com.optimizely.ab.annotations.VisibleForTesting; -import com.optimizely.ab.config.EventType; -import com.optimizely.ab.config.Experiment; -import com.optimizely.ab.config.ProjectConfig; -import com.optimizely.ab.config.Variation; -import com.optimizely.ab.event.LogEvent; -import com.optimizely.ab.event.internal.payload.Attribute; -import com.optimizely.ab.event.internal.payload.Decision; -import com.optimizely.ab.event.internal.payload.EventBatch; -import com.optimizely.ab.event.internal.payload.Event; -import com.optimizely.ab.event.internal.payload.Snapshot; -import com.optimizely.ab.event.internal.payload.Visitor; -import com.optimizely.ab.event.internal.serializer.DefaultJsonSerializer; -import com.optimizely.ab.event.internal.serializer.Serializer; -import com.optimizely.ab.internal.EventTagUtils; -import com.optimizely.ab.internal.ControlAttribute; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -public class EventBuilder { - private static final Logger logger = LoggerFactory.getLogger(EventBuilder.class); - static final String EVENT_ENDPOINT = "https://logx.optimizely.com/v1/events"; - static final String ACTIVATE_EVENT_KEY = "campaign_activated"; - - private Serializer serializer; - @VisibleForTesting - public final String clientVersion; - @VisibleForTesting - public final EventBatch.ClientEngine clientEngine; - - public EventBuilder() { - this(EventBatch.ClientEngine.JAVA_SDK, BuildVersionInfo.VERSION); - } - - public EventBuilder(EventBatch.ClientEngine clientEngine, String clientVersion) { - this.clientEngine = clientEngine; - this.clientVersion = clientVersion; - this.serializer = DefaultJsonSerializer.getInstance(); - } - - - public LogEvent createImpressionEvent(@Nonnull ProjectConfig projectConfig, - @Nonnull Experiment activatedExperiment, - @Nonnull Variation variation, - @Nonnull String userId, - @Nonnull Map attributes) { - - Decision decision = new Decision(activatedExperiment.getLayerId(), activatedExperiment.getId(), - variation.getId(), false); - Event impressionEvent = new Event(System.currentTimeMillis(),UUID.randomUUID().toString(), activatedExperiment.getLayerId(), - ACTIVATE_EVENT_KEY, null, null, null, ACTIVATE_EVENT_KEY, null); - Snapshot snapshot = new Snapshot(Arrays.asList(decision), Arrays.asList(impressionEvent)); - - Visitor visitor = new Visitor(userId, null, buildAttributeList(projectConfig, attributes), Arrays.asList(snapshot)); - List visitors = Arrays.asList(visitor); - EventBatch eventBatch = new EventBatch(clientEngine.getClientEngineValue(), clientVersion, projectConfig.getAccountId(), visitors, projectConfig.getAnonymizeIP(), projectConfig.getProjectId(), projectConfig.getRevision()); - String payload = this.serializer.serialize(eventBatch); - return new LogEvent(LogEvent.RequestMethod.POST, EVENT_ENDPOINT, Collections.emptyMap(), payload); - } - - public LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig, - @Nonnull Map experimentVariationMap, - @Nonnull String userId, - @Nonnull String eventId, - @Nonnull String eventName, - @Nonnull Map attributes, - @Nonnull Map eventTags) { - - if (experimentVariationMap.isEmpty()) { - return null; - } - - ArrayList decisions = new ArrayList(); - for (Map.Entry entry : experimentVariationMap.entrySet()) { - Decision decision = new Decision(entry.getKey().getLayerId(), entry.getKey().getId(), entry.getValue().getId(), false); - decisions.add(decision); - } - - EventType eventType = projectConfig.getEventNameMapping().get(eventName); - - Event conversionEvent = new Event(System.currentTimeMillis(),UUID.randomUUID().toString(), eventType.getId(), - eventType.getKey(), null, EventTagUtils.getRevenueValue(eventTags), eventTags, eventType.getKey(), EventTagUtils.getNumericValue(eventTags)); - Snapshot snapshot = new Snapshot(decisions, Arrays.asList(conversionEvent)); - - Visitor visitor = new Visitor(userId, null, buildAttributeList(projectConfig, attributes), Arrays.asList(snapshot)); - List visitors = Arrays.asList(visitor); - EventBatch eventBatch = new EventBatch(clientEngine.getClientEngineValue(), clientVersion, projectConfig.getAccountId(), visitors, projectConfig.getAnonymizeIP(), projectConfig.getProjectId(), projectConfig.getRevision()); - String payload = this.serializer.serialize(eventBatch); - return new LogEvent(LogEvent.RequestMethod.POST, EVENT_ENDPOINT, Collections.emptyMap(), payload); - } - - private List buildAttributeList(ProjectConfig projectConfig, Map attributes) { - List attributesList = new ArrayList(); - - for (Map.Entry entry : attributes.entrySet()) { - String attributeId = projectConfig.getAttributeId(projectConfig, entry.getKey()); - if(attributeId != null) { - Attribute attribute = new Attribute(attributeId, - entry.getKey(), - Attribute.CUSTOM_ATTRIBUTE_TYPE, - entry.getValue()); - attributesList.add(attribute); - } - } - - //checks if botFiltering value is not set in the project config file. - if(projectConfig.getBotFiltering() != null) { - Attribute attribute = new Attribute( - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - Attribute.CUSTOM_ATTRIBUTE_TYPE, - projectConfig.getBotFiltering() - ); - attributesList.add(attribute); - } - - return attributesList; - } -} diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/EventFactory.java b/core-api/src/main/java/com/optimizely/ab/event/internal/EventFactory.java new file mode 100644 index 000000000..ea4bb5b40 --- /dev/null +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/EventFactory.java @@ -0,0 +1,206 @@ +/** + * + * Copyright 2016-2018, 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.event.internal; + +import com.optimizely.ab.annotations.VisibleForTesting; +import com.optimizely.ab.config.EventType; +import com.optimizely.ab.config.Experiment; +import com.optimizely.ab.config.ProjectConfig; +import com.optimizely.ab.config.Variation; +import com.optimizely.ab.event.LogEvent; +import com.optimizely.ab.event.internal.payload.Attribute; +import com.optimizely.ab.event.internal.payload.Decision; +import com.optimizely.ab.event.internal.payload.EventBatch; +import com.optimizely.ab.event.internal.payload.Event; +import com.optimizely.ab.event.internal.payload.Snapshot; +import com.optimizely.ab.event.internal.payload.Visitor; +import com.optimizely.ab.event.internal.serializer.DefaultJsonSerializer; +import com.optimizely.ab.event.internal.serializer.Serializer; +import com.optimizely.ab.internal.EventTagUtils; +import com.optimizely.ab.internal.ControlAttribute; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class EventFactory { + private static final Logger logger = LoggerFactory.getLogger(EventFactory.class); + static final String EVENT_ENDPOINT = "https://logx.optimizely.com/v1/events"; // Should be part of the datafile + static final String ACTIVATE_EVENT_KEY = "campaign_activated"; + + private Serializer serializer; + @VisibleForTesting + public final String clientVersion; + @VisibleForTesting + public final EventBatch.ClientEngine clientEngine; + + public EventFactory() { + this(EventBatch.ClientEngine.JAVA_SDK, BuildVersionInfo.VERSION); + } + + public EventFactory(EventBatch.ClientEngine clientEngine, String clientVersion) { + this.clientEngine = clientEngine; + this.clientVersion = clientVersion; + this.serializer = DefaultJsonSerializer.getInstance(); + } + + public LogEvent createImpressionEvent(@Nonnull ProjectConfig projectConfig, + @Nonnull Experiment activatedExperiment, + @Nonnull Variation variation, + @Nonnull String userId, + @Nonnull Map attributes) { + + Decision decision = new Decision.Builder() + .setCampaignId(activatedExperiment.getLayerId()) + .setExperimentId(activatedExperiment.getId()) + .setVariationId(variation.getId()) + .setIsCampaignHoldback(false) + .build(); + + Event impressionEvent = new Event.Builder() + .setTimestamp(System.currentTimeMillis()) + .setUuid(UUID.randomUUID().toString()) + .setEntityId(activatedExperiment.getLayerId()) + .setKey(ACTIVATE_EVENT_KEY) + .setType(ACTIVATE_EVENT_KEY) + .build(); + + Snapshot snapshot = new Snapshot.Builder() + .setDecisions(Collections.singletonList(decision)) + .setEvents(Collections.singletonList(impressionEvent)) + .build(); + + Visitor visitor = new Visitor.Builder() + .setVisitorId(userId) + .setAttributes(buildAttributeList(projectConfig, attributes)) + .setSnapshots(Collections.singletonList((snapshot))) + .build(); + + EventBatch eventBatch = new EventBatch.Builder() + .setClientName(clientEngine.getClientEngineValue()) + .setClientVersion(clientVersion) + .setAccountId(projectConfig.getAccountId()) + .setVisitors(Collections.singletonList(visitor)) + .setAnonymizeIp(projectConfig.getAnonymizeIP()) + .setProjectId(projectConfig.getProjectId()) + .setRevision(projectConfig.getRevision()) + .build(); + + String payload = this.serializer.serialize(eventBatch); + return new LogEvent(LogEvent.RequestMethod.POST, EVENT_ENDPOINT, Collections.emptyMap(), payload); + } + + public LogEvent createConversionEvent(@Nonnull ProjectConfig projectConfig, + @Nonnull Map experimentVariationMap, + @Nonnull String userId, + @Nonnull String eventId, // Why is this not used? + @Nonnull String eventName, + @Nonnull Map attributes, + @Nonnull Map eventTags) { + + if (experimentVariationMap.isEmpty()) { + return null; + } + + ArrayList decisions = new ArrayList(experimentVariationMap.size()); + for (Map.Entry entry : experimentVariationMap.entrySet()) { + Decision decision = new Decision.Builder() + .setCampaignId(entry.getKey().getLayerId()) + .setExperimentId(entry.getKey().getId()) + .setVariationId(entry.getValue().getId()) + .setIsCampaignHoldback(false) + .build(); + + decisions.add(decision); + } + + EventType eventType = projectConfig.getEventNameMapping().get(eventName); + + Event conversionEvent = new Event.Builder() + .setTimestamp(System.currentTimeMillis()) + .setUuid(UUID.randomUUID().toString()) + .setEntityId(eventType.getId()) + .setKey(eventType.getKey()) + .setRevenue(EventTagUtils.getRevenueValue(eventTags)) + .setTags(eventTags) + .setType(eventType.getKey()) + .setValue(EventTagUtils.getNumericValue(eventTags)) + .build(); + + Snapshot snapshot = new Snapshot.Builder() + .setDecisions(decisions) + .setEvents(Collections.singletonList((conversionEvent))) + .build(); + + Visitor visitor = new Visitor.Builder() + .setVisitorId(userId) + .setAttributes(buildAttributeList(projectConfig, attributes)) + .setSnapshots(Collections.singletonList(snapshot)) + .build(); + + EventBatch eventBatch = new EventBatch.Builder() + .setClientName(clientEngine.getClientEngineValue()) + .setClientVersion(clientVersion) + .setAccountId(projectConfig.getAccountId()) + .setVisitors(Collections.singletonList(visitor)) + .setAnonymizeIp(projectConfig.getAnonymizeIP()) + .setProjectId(projectConfig.getProjectId()) + .setRevision(projectConfig.getRevision()) + .build(); + + String payload = this.serializer.serialize(eventBatch); + return new LogEvent(LogEvent.RequestMethod.POST, EVENT_ENDPOINT, Collections.emptyMap(), payload); + } + + private List buildAttributeList(ProjectConfig projectConfig, Map attributes) { + List attributesList = new ArrayList(); + + for (Map.Entry entry : attributes.entrySet()) { + String attributeId = projectConfig.getAttributeId(projectConfig, entry.getKey()); + if(attributeId == null) { + continue; + } + + Attribute attribute = new Attribute.Builder() + .setEntityId(attributeId) + .setKey(entry.getKey()) + .setType(Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue(entry.getValue()) + .build(); + + attributesList.add(attribute); + } + + //checks if botFiltering value is not set in the project config file. + if(projectConfig.getBotFiltering() != null) { + Attribute attribute = new Attribute.Builder() + .setEntityId(ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString()) + .setKey(ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString()) + .setType(Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue(projectConfig.getBotFiltering()) + .build(); + + attributesList.add(attribute); + } + + return attributesList; + } +} diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Attribute.java b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Attribute.java index 74580cc1c..fdbb276a9 100644 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Attribute.java +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Attribute.java @@ -17,6 +17,7 @@ package com.optimizely.ab.event.internal.payload; import com.fasterxml.jackson.annotation.JsonProperty; +import com.optimizely.ab.annotations.VisibleForTesting; public class Attribute { public static final String CUSTOM_ATTRIBUTE_TYPE = "custom"; @@ -28,11 +29,10 @@ public class Attribute { String type; Object value; - public Attribute() { + @VisibleForTesting + public Attribute() { } - } - - public Attribute(String entityId, String key, String type, Object value) { + private Attribute(String entityId, String key, String type, Object value) { this.entityId = entityId; this.key = key; this.type = type; @@ -92,4 +92,36 @@ public int hashCode() { result = 31 * result + value.hashCode(); return result; } + + public static class Builder { + + private String entityId; + private String key; + private String type; + private Object value; + + public Builder setEntityId(String entityId) { + this.entityId = entityId; + return this; + } + + public Builder setKey(String key) { + this.key = key; + return this; + } + + public Builder setType(String type) { + this.type = type; + return this; + } + + public Builder setValue(Object value) { + this.value = value; + return this; + } + + public Attribute build() { + return new Attribute(entityId, key, type, value); + } + } } diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Decision.java b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Decision.java index b5af81da9..a12c9e36c 100644 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Decision.java +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Decision.java @@ -17,6 +17,7 @@ package com.optimizely.ab.event.internal.payload; import com.fasterxml.jackson.annotation.JsonProperty; +import com.optimizely.ab.annotations.VisibleForTesting; public class Decision { @JsonProperty("campaign_id") @@ -28,6 +29,9 @@ public class Decision { @JsonProperty("is_campaign_holdback") boolean isCampaignHoldback; + @VisibleForTesting + public Decision() { } + public Decision(String campaignId, String experimentId, String variationId, boolean isCampaignHoldback) { this.campaignId = campaignId; this.experimentId = experimentId; @@ -35,10 +39,6 @@ public Decision(String campaignId, String experimentId, String variationId, bool this.isCampaignHoldback = isCampaignHoldback; } - public Decision() { - - } - public String getCampaignId() { return campaignId; } @@ -67,6 +67,7 @@ public boolean equals(Object o) { if (!experimentId.equals(that.experimentId)) return false; return variationId.equals(that.variationId); } + @Override public int hashCode() { int result = campaignId.hashCode(); @@ -75,4 +76,36 @@ public int hashCode() { result = 31 * result + (isCampaignHoldback ? 1 : 0); return result; } + + public static class Builder { + + private String campaignId; + private String experimentId; + private String variationId; + private boolean isCampaignHoldback; + + public Builder setCampaignId(String campaignId) { + this.campaignId = campaignId; + return this; + } + + public Builder setExperimentId(String experimentId) { + this.experimentId = experimentId; + return this; + } + + public Builder setVariationId(String variationId) { + this.variationId = variationId; + return this; + } + + public Builder setIsCampaignHoldback(boolean isCampaignHoldback) { + this.isCampaignHoldback = isCampaignHoldback; + return this; + } + + public Decision build() { + return new Decision(campaignId, experimentId, variationId, isCampaignHoldback); + } + } } diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Event.java b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Event.java index 9ce40541b..4d38f8f93 100644 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Event.java +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Event.java @@ -17,6 +17,7 @@ package com.optimizely.ab.event.internal.payload; import com.fasterxml.jackson.annotation.JsonProperty; +import com.optimizely.ab.annotations.VisibleForTesting; import java.util.Map; @@ -32,9 +33,8 @@ public class Event { String type; Number value; - public Event() { - - } + @VisibleForTesting + public Event() { } public Event(long timestamp, String uuid, String entityId, String key, Number quantity, Number revenue, Map tags, String type, Number value) { @@ -153,4 +153,65 @@ public int hashCode() { return result; } + public static class Builder { + + private long timestamp; + private String uuid; + private String entityId; + private String key; + private Number quantity = null; + private Number revenue = null; + private Map tags = null; + private String type; + private Number value = null; + + public Builder setTimestamp(long timestamp) { + this.timestamp = timestamp; + return this; + } + + public Builder setUuid(String uuid) { + this.uuid = uuid; + return this; + } + + public Builder setEntityId(String entityId) { + this.entityId = entityId; + return this; + } + + public Builder setKey(String key) { + this.key = key; + return this; + } + + public Builder setQuantity(Number quantity) { + this.quantity = quantity; + return this; + } + + public Builder setRevenue(Number revenue) { + this.revenue = revenue; + return this; + } + + public Builder setTags(Map tags) { + this.tags = tags; + return this; + } + + public Builder setType(String type) { + this.type = type; + return this; + } + + public Builder setValue(Number value) { + this.value = value; + return this; + } + + public Event build() { + return new Event(timestamp, uuid, entityId, key, quantity, revenue, tags, type, value); + } + } } diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/EventBatch.java b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/EventBatch.java index 9cee5ead4..f3850e6ef 100644 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/EventBatch.java +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/EventBatch.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonValue; +import com.optimizely.ab.annotations.VisibleForTesting; import com.optimizely.ab.event.internal.BuildVersionInfo; import java.util.List; @@ -46,26 +47,17 @@ public String getClientEngineValue() { @JsonProperty("anonymize_ip") Boolean anonymizeIp; @JsonProperty("client_name") - String clientName = ClientEngine.JAVA_SDK.getClientEngineValue(); + String clientName; @JsonProperty("client_version") - String clientVersion = BuildVersionInfo.VERSION; + String clientVersion; @JsonProperty("project_id") String projectId; String revision; - public EventBatch() { + @VisibleForTesting + public EventBatch() { } - } - - public EventBatch(String accountId, List visitors, Boolean anonymizeIp, String projectId, String revision) { - this.accountId = accountId; - this.visitors = visitors; - this.anonymizeIp = anonymizeIp; - this.projectId = projectId; - this.revision = revision; - } - - public EventBatch(String clientName, String clientVersion, String accountId, List visitors, Boolean anonymizeIp, String projectId, String revision) { + private EventBatch(String clientName, String clientVersion, String accountId, List visitors, Boolean anonymizeIp, String projectId, String revision) { this.accountId = accountId; this.visitors = visitors; this.anonymizeIp = anonymizeIp; @@ -159,4 +151,55 @@ public int hashCode() { result = 31 * result + (revision != null ? revision.hashCode() : 0); return result; } + + public static class Builder { + + private String clientName = ClientEngine.JAVA_SDK.getClientEngineValue(); + private String clientVersion = BuildVersionInfo.VERSION; + private String accountId; + private List visitors; + private Boolean anonymizeIp; + private String projectId; + private String revision; + + public Builder setClientName(String clientName) { + this.clientName = clientName; + return this; + } + + public Builder setClientVersion(String clientVersion) { + this.clientVersion = clientVersion; + return this; + } + + public Builder setAccountId(String accountId) { + this.accountId = accountId; + return this; + } + + public Builder setVisitors(List visitors) { + this.visitors = visitors; + return this; + } + + public Builder setAnonymizeIp(Boolean anonymizeIp) { + this.anonymizeIp = anonymizeIp; + return this; + } + + public Builder setProjectId(String projectId) { + this.projectId = projectId; + return this; + } + + public Builder setRevision(String revision) { + this.revision = revision; + return this; + } + + public EventBatch build() { + return new EventBatch(clientName, clientVersion, accountId, visitors, anonymizeIp, projectId, revision); + } + } + } diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Snapshot.java b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Snapshot.java index ee16f6984..a1b2ad759 100644 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Snapshot.java +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Snapshot.java @@ -17,6 +17,7 @@ package com.optimizely.ab.event.internal.payload; import com.fasterxml.jackson.annotation.JsonProperty; +import com.optimizely.ab.annotations.VisibleForTesting; import java.util.List; @@ -26,9 +27,8 @@ public class Snapshot { @JsonProperty("activation_timestamp") Long activationTimestamp; - public Snapshot() { - - } + @VisibleForTesting + public Snapshot() { } public Snapshot(List decisions, List events) { this.decisions = decisions; @@ -83,4 +83,24 @@ public int hashCode() { } return result; } + + public static class Builder { + + private List decisions; + private List events; + + public Builder setDecisions(List decisions) { + this.decisions = decisions; + return this; + } + + public Builder setEvents(List events) { + this.events = events; + return this; + } + + public Snapshot build() { + return new Snapshot(decisions, events); + } + } } diff --git a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Visitor.java b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Visitor.java index 0eb815dbb..b9e4326e1 100644 --- a/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Visitor.java +++ b/core-api/src/main/java/com/optimizely/ab/event/internal/payload/Visitor.java @@ -17,6 +17,7 @@ package com.optimizely.ab.event.internal.payload; import com.fasterxml.jackson.annotation.JsonProperty; +import com.optimizely.ab.annotations.VisibleForTesting; import java.util.List; @@ -28,11 +29,10 @@ public class Visitor { List attributes; List snapshots; - public Visitor() { + @VisibleForTesting + public Visitor() { } - } - - public Visitor(String visitorId, String sessionId, List attributes, List snapshots) { + private Visitor(String visitorId, String sessionId, List attributes, List snapshots) { this.visitorId = visitorId; this.sessionId = sessionId; this.attributes = attributes; @@ -92,4 +92,36 @@ public int hashCode() { result = 31 * result + snapshots.hashCode(); return result; } + + public static class Builder { + + private String visitorId; + private String sessionId = null; + private List attributes; + private List snapshots; + + public Builder setVisitorId(String visitorId) { + this.visitorId = visitorId; + return this; + } + + public Builder setSessionId(String sessionId) { + this.sessionId = sessionId; + return this; + } + + public Builder setAttributes(List attributes) { + this.attributes = attributes; + return this; + } + + public Builder setSnapshots(List snapshots) { + this.snapshots = snapshots; + return this; + } + + public Visitor build() { + return new Visitor(visitorId, sessionId, attributes, snapshots); + } + } } diff --git a/core-api/src/test/java/com/optimizely/ab/OptimizelyBuilderTest.java b/core-api/src/test/java/com/optimizely/ab/OptimizelyBuilderTest.java index 4a48c7c4b..e142091ec 100644 --- a/core-api/src/test/java/com/optimizely/ab/OptimizelyBuilderTest.java +++ b/core-api/src/test/java/com/optimizely/ab/OptimizelyBuilderTest.java @@ -17,17 +17,15 @@ package com.optimizely.ab; import com.optimizely.ab.bucketing.UserProfileService; -import com.optimizely.ab.config.ProjectConfig; import com.optimizely.ab.config.ProjectConfigTestUtils; import com.optimizely.ab.config.parser.ConfigParseException; import com.optimizely.ab.error.ErrorHandler; import com.optimizely.ab.error.NoOpErrorHandler; import com.optimizely.ab.event.EventHandler; import com.optimizely.ab.event.internal.BuildVersionInfo; -import com.optimizely.ab.event.internal.EventBuilder; +import com.optimizely.ab.event.internal.EventFactory; import com.optimizely.ab.event.internal.payload.EventBatch.ClientEngine; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -35,8 +33,6 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import static com.optimizely.ab.config.ProjectConfigTestUtils.noAudienceProjectConfigJsonV2; -import static com.optimizely.ab.config.ProjectConfigTestUtils.noAudienceProjectConfigV2; import static com.optimizely.ab.config.ProjectConfigTestUtils.validConfigJsonV2; import static com.optimizely.ab.config.ProjectConfigTestUtils.validConfigJsonV3; import static com.optimizely.ab.config.ProjectConfigTestUtils.validProjectConfigV2; @@ -52,17 +48,6 @@ @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public class OptimizelyBuilderTest { - - private static final String userId = "userId"; - private static String noAudienceDatafile; - private static ProjectConfig noAudienceProjectConfig; - - @BeforeClass - public static void setUp() throws Exception { - noAudienceDatafile = noAudienceProjectConfigJsonV2(); - noAudienceProjectConfig = noAudienceProjectConfigV2(); - } - @Rule public ExpectedException thrown = ExpectedException.none(); @@ -129,7 +114,7 @@ public void withDefaultClientEngine() throws Exception { Optimizely optimizelyClient = Optimizely.builder(validConfigJsonV2(), mockEventHandler) .build(); - assertThat(((EventBuilder)optimizelyClient.eventBuilder).clientEngine, is(ClientEngine.JAVA_SDK)); + assertThat(((EventFactory)optimizelyClient.eventFactory).clientEngine, is(ClientEngine.JAVA_SDK)); } @Test @@ -138,7 +123,7 @@ public void withAndroidSDKClientEngine() throws Exception { .withClientEngine(ClientEngine.ANDROID_SDK) .build(); - assertThat(((EventBuilder)optimizelyClient.eventBuilder).clientEngine, is(ClientEngine.ANDROID_SDK)); + assertThat(((EventFactory)optimizelyClient.eventFactory).clientEngine, is(ClientEngine.ANDROID_SDK)); } @Test @@ -147,7 +132,7 @@ public void withAndroidTVSDKClientEngine() throws Exception { .withClientEngine(ClientEngine.ANDROID_TV_SDK) .build(); - assertThat(((EventBuilder)optimizelyClient.eventBuilder).clientEngine, is(ClientEngine.ANDROID_TV_SDK)); + assertThat(((EventFactory)optimizelyClient.eventFactory).clientEngine, is(ClientEngine.ANDROID_TV_SDK)); } @Test @@ -155,7 +140,7 @@ public void withDefaultClientVersion() throws Exception { Optimizely optimizelyClient = Optimizely.builder(validConfigJsonV2(), mockEventHandler) .build(); - assertThat(((EventBuilder)optimizelyClient.eventBuilder).clientVersion, is(BuildVersionInfo.VERSION)); + assertThat(((EventFactory)optimizelyClient.eventFactory).clientVersion, is(BuildVersionInfo.VERSION)); } @Test @@ -164,7 +149,7 @@ public void withCustomClientVersion() throws Exception { .withClientVersion("0.0.0") .build(); - assertThat(((EventBuilder)optimizelyClient.eventBuilder).clientVersion, is("0.0.0")); + assertThat(((EventFactory)optimizelyClient.eventFactory).clientVersion, is("0.0.0")); } @SuppressFBWarnings(value="NP_NONNULL_PARAM_VIOLATION", justification="Testing nullness contract violation") diff --git a/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java b/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java index a77762b2a..c474758c5 100644 --- a/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java +++ b/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java @@ -35,12 +35,11 @@ import com.optimizely.ab.error.RaiseExceptionErrorHandler; import com.optimizely.ab.event.EventHandler; import com.optimizely.ab.event.LogEvent; -import com.optimizely.ab.event.internal.EventBuilder; +import com.optimizely.ab.event.internal.EventFactory; import com.optimizely.ab.internal.LogbackVerifier; import com.optimizely.ab.internal.ControlAttribute; import com.optimizely.ab.notification.ActivateNotificationListener; import com.optimizely.ab.notification.NotificationCenter; -import com.optimizely.ab.notification.NotificationListener; import com.optimizely.ab.notification.TrackNotificationListener; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.junit.Rule; @@ -64,45 +63,10 @@ import java.util.List; import java.util.Map; -import static com.optimizely.ab.config.ProjectConfigTestUtils.noAudienceProjectConfigJsonV2; -import static com.optimizely.ab.config.ProjectConfigTestUtils.noAudienceProjectConfigJsonV3; -import static com.optimizely.ab.config.ProjectConfigTestUtils.noAudienceProjectConfigV2; -import static com.optimizely.ab.config.ProjectConfigTestUtils.noAudienceProjectConfigV3; -import static com.optimizely.ab.config.ProjectConfigTestUtils.validConfigJsonV2; -import static com.optimizely.ab.config.ProjectConfigTestUtils.validConfigJsonV3; -import static com.optimizely.ab.config.ProjectConfigTestUtils.validConfigJsonV4; -import static com.optimizely.ab.config.ProjectConfigTestUtils.validProjectConfigV2; -import static com.optimizely.ab.config.ProjectConfigTestUtils.validProjectConfigV3; -import static com.optimizely.ab.config.ProjectConfigTestUtils.validProjectConfigV4; -import static com.optimizely.ab.config.ValidProjectConfigV4.ATTRIBUTE_HOUSE_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.AUDIENCE_GRYFFINDOR_VALUE; -import static com.optimizely.ab.config.ValidProjectConfigV4.EVENT_BASIC_EVENT_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.EVENT_LAUNCHED_EXPERIMENT_ONLY_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.EXPERIMENT_BASIC_EXPERIMENT_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.EXPERIMENT_LAUNCHED_EXPERIMENT_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.EXPERIMENT_MULTIVARIATE_EXPERIMENT_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.EXPERIMENT_PAUSED_EXPERIMENT_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_FLAG_MULTI_VARIATE_FEATURE; -import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_FLAG_SINGLE_VARIABLE_DOUBLE; -import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_FLAG_SINGLE_VARIABLE_INTEGER; -import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_MULTI_VARIATE_FEATURE_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_SINGLE_VARIABLE_BOOLEAN_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_SINGLE_VARIABLE_DOUBLE_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.FEATURE_SINGLE_VARIABLE_INTEGER_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.MULTIVARIATE_EXPERIMENT_FORCED_VARIATION_USER_ID_GRED; -import static com.optimizely.ab.config.ValidProjectConfigV4.PAUSED_EXPERIMENT_FORCED_VARIATION_USER_ID_CONTROL; -import static com.optimizely.ab.config.ValidProjectConfigV4.ROLLOUT_2_ID; -import static com.optimizely.ab.config.ValidProjectConfigV4.VARIABLE_BOOLEAN_VARIABLE_DEFAULT_VALUE; -import static com.optimizely.ab.config.ValidProjectConfigV4.VARIABLE_BOOLEAN_VARIABLE_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.VARIABLE_DOUBLE_DEFAULT_VALUE; -import static com.optimizely.ab.config.ValidProjectConfigV4.VARIABLE_DOUBLE_VARIABLE_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.VARIABLE_FIRST_LETTER_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.VARIABLE_INTEGER_VARIABLE_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.VARIATION_MULTIVARIATE_EXPERIMENT_GRED; -import static com.optimizely.ab.config.ValidProjectConfigV4.VARIATION_MULTIVARIATE_EXPERIMENT_GRED_KEY; -import static com.optimizely.ab.config.ValidProjectConfigV4.EXPERIMENT_DOUBLE_FEATURE_EXPERIMENT_KEY; +import static com.optimizely.ab.config.ProjectConfigTestUtils.*; +import static com.optimizely.ab.config.ValidProjectConfigV4.*; import static com.optimizely.ab.event.LogEvent.RequestMethod; -import static com.optimizely.ab.event.internal.EventBuilderTest.createExperimentVariationMap; +import static com.optimizely.ab.event.internal.EventFactoryTest.createExperimentVariationMap; import static java.util.Arrays.asList; import static junit.framework.TestCase.assertTrue; import static org.hamcrest.CoreMatchers.is; @@ -115,19 +79,8 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assume.assumeTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyMapOf; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; /** * Tests for the top-level {@link Optimizely} class. @@ -223,11 +176,11 @@ public void activateEndToEnd() throws Exception { } testUserAttributes.put(bucketingKey, bucketingId); Variation bucketedVariation = activatedExperiment.getVariations().get(0); - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -236,7 +189,7 @@ public void activateEndToEnd() throws Exception { testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, testUserId, + when(mockEventFactory.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, testUserId, testUserAttributes)) .thenReturn(logEventToDispatch); @@ -330,11 +283,11 @@ public void activateWithExperimentKeyForced() throws Exception { Experiment activatedExperiment = validProjectConfig.getExperiments().get(0); Variation forcedVariation = activatedExperiment.getVariations().get(1); Variation bucketedVariation = activatedExperiment.getVariations().get(0); - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -356,7 +309,7 @@ public void activateWithExperimentKeyForced() throws Exception { testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(forcedVariation), + when(mockEventFactory.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(forcedVariation), eq(testUserId), eq(testUserAttributes))) .thenReturn(logEventToDispatch); @@ -386,11 +339,11 @@ public void getVariationWithExperimentKeyForced() throws Exception { Experiment activatedExperiment = validProjectConfig.getExperiments().get(0); Variation forcedVariation = activatedExperiment.getVariations().get(1); Variation bucketedVariation = activatedExperiment.getVariations().get(0); - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -412,7 +365,7 @@ public void getVariationWithExperimentKeyForced() throws Exception { testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(forcedVariation), + when(mockEventFactory.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(forcedVariation), eq(testUserId), eq(testUserAttributes))) .thenReturn(logEventToDispatch); @@ -444,11 +397,11 @@ public void isFeatureEnabledWithExperimentKeyForced() throws Exception { Experiment activatedExperiment = validProjectConfig.getExperimentKeyMapping().get(EXPERIMENT_MULTIVARIATE_EXPERIMENT_KEY); Variation forcedVariation = activatedExperiment.getVariations().get(1); - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -464,7 +417,7 @@ public void isFeatureEnabledWithExperimentKeyForced() throws Exception { testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(forcedVariation), + when(mockEventFactory.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(forcedVariation), eq(testUserId), eq(testUserAttributes))) .thenReturn(logEventToDispatch); @@ -491,11 +444,11 @@ public void activateWithExperimentKey() throws Exception { Experiment activatedExperiment = validProjectConfig.getExperiments().get(0); Variation bucketedVariation = activatedExperiment.getVariations().get(0); Variation userIdBucketVariation = activatedExperiment.getVariations().get(1); - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -513,7 +466,7 @@ public void activateWithExperimentKey() throws Exception { Map testParams = new HashMap(); testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), + when(mockEventFactory.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), eq(testUserAttributes))) .thenReturn(logEventToDispatch); @@ -588,11 +541,11 @@ public void activateWithAttributes() throws Exception { Attribute attribute = validProjectConfig.getAttributes().get(0); // setup a mock event builder to return expected impression params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -600,7 +553,7 @@ public void activateWithAttributes() throws Exception { Map testParams = new HashMap(); testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), + when(mockEventFactory.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), anyMapOf(String.class, String.class))) .thenReturn(logEventToDispatch); @@ -624,7 +577,7 @@ public void activateWithAttributes() throws Exception { // setup the attribute map captor (so we can verify its content) ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); - verify(mockEventBuilder).createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), + verify(mockEventFactory).createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), attributeCaptor.capture()); Map actualValue = attributeCaptor.getValue(); @@ -647,11 +600,11 @@ public void activateWithUnknownAttribute() throws Exception { Variation bucketedVariation = activatedExperiment.getVariations().get(0); // setup a mock event builder to return mock params and endpoint - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(new RaiseExceptionErrorHandler()) .build(); @@ -668,7 +621,7 @@ public void activateWithUnknownAttribute() throws Exception { Map testParams = new HashMap(); testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), + when(mockEventFactory.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), anyMapOf(String.class, String.class))) .thenReturn(logEventToDispatch); @@ -691,7 +644,7 @@ public void activateWithUnknownAttribute() throws Exception { ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); // verify that the event builder was called with the expected attributes - verify(mockEventBuilder).createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), + verify(mockEventFactory).createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), attributeCaptor.capture()); Map actualValue = attributeCaptor.getValue(); @@ -713,11 +666,11 @@ public void activateWithNullAttributes() throws Exception { Variation bucketedVariation = activatedExperiment.getVariations().get(0); // setup a mock event builder to return expected impression params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(noAudienceDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(noAudienceProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -725,7 +678,7 @@ public void activateWithNullAttributes() throws Exception { Map testParams = new HashMap(); testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(eq(noAudienceProjectConfig), eq(activatedExperiment), eq(bucketedVariation), + when(mockEventFactory.createImpressionEvent(eq(noAudienceProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), eq(Collections.emptyMap()))) .thenReturn(logEventToDispatch); @@ -744,7 +697,7 @@ public void activateWithNullAttributes() throws Exception { // setup the attribute map captor (so we can verify its content) ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); - verify(mockEventBuilder).createImpressionEvent(eq(noAudienceProjectConfig), eq(activatedExperiment), + verify(mockEventFactory).createImpressionEvent(eq(noAudienceProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), attributeCaptor.capture()); Map actualValue = attributeCaptor.getValue(); @@ -764,11 +717,11 @@ public void activateWithNullAttributeValues() throws Exception { Attribute attribute = validProjectConfig.getAttributes().get(0); // setup a mock event builder to return expected impression params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -776,7 +729,7 @@ public void activateWithNullAttributeValues() throws Exception { Map testParams = new HashMap(); testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), + when(mockEventFactory.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), anyMapOf(String.class, String.class))) .thenReturn(logEventToDispatch); @@ -794,7 +747,7 @@ public void activateWithNullAttributeValues() throws Exception { // setup the attribute map captor (so we can verify its content) ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); - verify(mockEventBuilder).createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), + verify(mockEventFactory).createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), attributeCaptor.capture()); Map actualValue = attributeCaptor.getValue(); @@ -1207,7 +1160,7 @@ public void trackEventEndToEndForced() throws Exception { } List allExperiments = new ArrayList(); allExperiments.add(config.getExperiments().get(0)); - EventBuilder eventBuilder = new EventBuilder(); + EventFactory eventFactory = new EventFactory(); DecisionService spyDecisionService = spy(new DecisionService(mockBucketer, mockErrorHandler, config, @@ -1215,7 +1168,7 @@ public void trackEventEndToEndForced() throws Exception { Optimizely optimizely = Optimizely.builder(datafile, mockEventHandler) .withDecisionService(spyDecisionService) - .withEventBuilder(eventBuilder) + .withEventBuilder(eventFactory) .withConfig(noAudienceProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -1281,7 +1234,7 @@ public void trackEventEndToEnd() throws Exception { } List allExperiments = config.getExperiments(); - EventBuilder eventBuilder = new EventBuilder(); + EventFactory eventFactory = new EventFactory(); DecisionService spyDecisionService = spy(new DecisionService(mockBucketer, mockErrorHandler, config, @@ -1289,7 +1242,7 @@ public void trackEventEndToEnd() throws Exception { Optimizely optimizely = Optimizely.builder(datafile, mockEventHandler) .withDecisionService(spyDecisionService) - .withEventBuilder(eventBuilder) + .withEventBuilder(eventFactory) .withConfig(noAudienceProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -1377,11 +1330,11 @@ public void trackEventWithAttributes() throws Exception { } // setup a mock event builder to return expected conversion params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -1396,7 +1349,7 @@ public void trackEventWithAttributes() throws Exception { genericUserId, attributes); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1418,7 +1371,7 @@ public void trackEventWithAttributes() throws Exception { ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); // verify that the event builder was called with the expected attributes - verify(mockEventBuilder).createConversionEvent( + verify(mockEventFactory).createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1450,11 +1403,11 @@ public void trackEventWithNullAttributes() throws Exception { } // setup a mock event builder to return expected conversion params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -1468,7 +1421,7 @@ public void trackEventWithNullAttributes() throws Exception { genericUserId, Collections.emptyMap()); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1493,7 +1446,7 @@ public void trackEventWithNullAttributes() throws Exception { ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); // verify that the event builder was called with the expected attributes - verify(mockEventBuilder).createConversionEvent( + verify(mockEventFactory).createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1522,11 +1475,11 @@ public void trackEventWithNullAttributeValues() throws Exception { } // setup a mock event builder to return expected conversion params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -1540,7 +1493,7 @@ public void trackEventWithNullAttributeValues() throws Exception { genericUserId, Collections.emptyMap()); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1564,7 +1517,7 @@ public void trackEventWithNullAttributeValues() throws Exception { ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); // verify that the event builder was called with the expected attributes - verify(mockEventBuilder).createConversionEvent( + verify(mockEventFactory).createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1594,11 +1547,11 @@ public void trackEventWithUnknownAttribute() throws Exception { } // setup a mock event builder to return expected conversion params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(new RaiseExceptionErrorHandler()) .build(); @@ -1612,7 +1565,7 @@ public void trackEventWithUnknownAttribute() throws Exception { genericUserId, Collections.emptyMap()); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1635,7 +1588,7 @@ public void trackEventWithUnknownAttribute() throws Exception { ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); // verify that the event builder was called with the expected attributes - verify(mockEventBuilder).createConversionEvent( + verify(mockEventFactory).createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1652,7 +1605,7 @@ public void trackEventWithUnknownAttribute() throws Exception { /** * Verify that {@link Optimizely#track(String, String, Map, Map)} passes event features to - * {@link EventBuilder#createConversionEvent(ProjectConfig, Map, String, String, String, Map, Map)} + * {@link EventFactory#createConversionEvent(ProjectConfig, Map, String, String, String, Map, Map)} */ @Test public void trackEventWithEventTags() throws Exception { @@ -1665,11 +1618,11 @@ public void trackEventWithEventTags() throws Exception { } // setup a mock event builder to return expected conversion params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -1690,7 +1643,7 @@ public void trackEventWithEventTags() throws Exception { Collections.emptyMap()); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1712,7 +1665,7 @@ public void trackEventWithEventTags() throws Exception { ArgumentCaptor eventTagCaptor = ArgumentCaptor.forClass(Map.class); // verify that the event builder was called with the expected attributes - verify(mockEventBuilder).createConversionEvent( + verify(mockEventFactory).createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1732,7 +1685,7 @@ public void trackEventWithEventTags() throws Exception { /** * Verify that {@link Optimizely#track(String, String, Map, Map)} called with null event tags will default to - * an empty map when calling {@link EventBuilder#createConversionEvent(ProjectConfig, Map, String, String, String, Map, Map)} + * an empty map when calling {@link EventFactory#createConversionEvent(ProjectConfig, Map, String, String, String, Map, Map)} */ @Test @SuppressFBWarnings( @@ -1748,11 +1701,11 @@ public void trackEventWithNullEventTags() throws Exception { } // setup a mock event builder to return expected conversion params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -1766,7 +1719,7 @@ public void trackEventWithNullEventTags() throws Exception { genericUserId, Collections.emptyMap()); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1785,7 +1738,7 @@ public void trackEventWithNullEventTags() throws Exception { optimizely.track(eventType.getKey(), genericUserId, Collections.emptyMap(), null); // verify that the event builder was called with the expected attributes - verify(mockEventBuilder).createConversionEvent( + verify(mockEventFactory).createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1813,11 +1766,11 @@ public void trackEventWithNullOrEmptyUserID() throws Exception { eventType = validProjectConfig.getEventTypes().get(0); } // setup a mock event builder to return expected conversion params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -1831,7 +1784,7 @@ public void trackEventWithNullOrEmptyUserID() throws Exception { genericUserId, Collections.emptyMap()); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -1864,11 +1817,11 @@ public void trackEventWithNullOrEmptyEventKey() throws Exception { } String nullEventKey = null; // setup a mock event builder to return expected conversion params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -1882,7 +1835,7 @@ public void trackEventWithNullOrEmptyEventKey() throws Exception { genericUserId, Collections.emptyMap()); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -2010,7 +1963,7 @@ public void trackDoesNotSendEventWhenExperimentsAreLaunchedOnly() throws Excepti */ @Test public void trackDispatchesWhenEventHasLaunchedAndRunningExperiments() throws Exception { - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); EventType eventType; if (datafileVersion >= 4) { eventType = validProjectConfig.getEventNameMapping().get(EVENT_BASIC_EVENT_KEY); @@ -2027,7 +1980,7 @@ public void trackDispatchesWhenEventHasLaunchedAndRunningExperiments() throws Ex Optimizely client = Optimizely.builder(validDatafile, mockEventHandler) .withConfig(noAudienceProjectConfig) .withBucketing(mockBucketAlgorithm) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .build(); Map testParams = new HashMap(); @@ -2043,7 +1996,7 @@ public void trackDispatchesWhenEventHasLaunchedAndRunningExperiments() throws Ex ArgumentCaptor experimentVariationMapCaptor = ArgumentCaptor.forClass(Map.class); LogEvent conversionEvent = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(noAudienceProjectConfig), experimentVariationMapCaptor.capture(), eq(genericUserId), @@ -2395,11 +2348,11 @@ public void getVariationExperimentStatusPrecedesForcedVariation() throws Excepti public void activateWithListener() throws Exception { final Experiment activatedExperiment = validProjectConfig.getExperiments().get(0); final Variation bucketedVariation = activatedExperiment.getVariations().get(0); - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -2434,7 +2387,7 @@ public void onActivate(@Nonnull Experiment experiment, @Nonnull String userId, @ Map testParams = new HashMap(); testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), + when(mockEventFactory.createImpressionEvent(eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), eq(testUserAttributes))) .thenReturn(logEventToDispatch); @@ -2463,11 +2416,11 @@ public void activateWithListenerNullAttributes() throws Exception { final Variation bucketedVariation = activatedExperiment.getVariations().get(0); // setup a mock event builder to return expected impression params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(noAudienceDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(noAudienceProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -2475,7 +2428,7 @@ public void activateWithListenerNullAttributes() throws Exception { Map testParams = new HashMap(); testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(eq(noAudienceProjectConfig), eq(activatedExperiment), eq(bucketedVariation), + when(mockEventFactory.createImpressionEvent(eq(noAudienceProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), eq(Collections.emptyMap()))) .thenReturn(logEventToDispatch); @@ -2511,7 +2464,7 @@ public void onActivate(@Nonnull Experiment experiment, @Nonnull String userId, @ // setup the attribute map captor (so we can verify its content) ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); - verify(mockEventBuilder).createImpressionEvent(eq(noAudienceProjectConfig), eq(activatedExperiment), + verify(mockEventFactory).createImpressionEvent(eq(noAudienceProjectConfig), eq(activatedExperiment), eq(bucketedVariation), eq(testUserId), attributeCaptor.capture()); Map actualValue = attributeCaptor.getValue(); @@ -2541,11 +2494,11 @@ public void addNotificationListenerFromNotificationCenter() throws Exception { eventType = validProjectConfig.getEventTypes().get(0); } Variation bucketedVariation = activatedExperiment.getVariations().get(0); - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withDecisionService(mockDecisionService) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -2555,7 +2508,7 @@ public void addNotificationListenerFromNotificationCenter() throws Exception { Map testParams = new HashMap(); testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(validProjectConfig, activatedExperiment, + when(mockEventFactory.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, genericUserId, attributes)) .thenReturn(logEventToDispatch); @@ -2584,7 +2537,7 @@ public void addNotificationListenerFromNotificationCenter() throws Exception { eventType.getKey(), genericUserId, attributes); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -2611,11 +2564,11 @@ public void addNotificationListenerFromNotificationCenter() throws Exception { public void removeNotificationListenerNotificationCenter() throws Exception { Experiment activatedExperiment = validProjectConfig.getExperiments().get(0); Variation bucketedVariation = activatedExperiment.getVariations().get(0); - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -2626,14 +2579,14 @@ public void removeNotificationListenerNotificationCenter() throws Exception { Map testParams = new HashMap(); testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(validProjectConfig, activatedExperiment, + when(mockEventFactory.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, genericUserId, attributes)) .thenReturn(logEventToDispatch); when(mockBucketer.bucket(activatedExperiment, genericUserId)) .thenReturn(bucketedVariation); - when(mockEventBuilder.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, genericUserId, + when(mockEventFactory.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, genericUserId, attributes)) .thenReturn(logEventToDispatch); @@ -2666,7 +2619,7 @@ public void removeNotificationListenerNotificationCenter() throws Exception { eventType.getKey(), genericUserId, attributes); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -2699,11 +2652,11 @@ public void clearNotificationListenersNotificationCenter() throws Exception { attributes.put("browser_type", "chrome"); } Variation bucketedVariation = activatedExperiment.getVariations().get(0); - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -2711,7 +2664,7 @@ public void clearNotificationListenersNotificationCenter() throws Exception { Map testParams = new HashMap(); testParams.put("test", "params"); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createImpressionEvent(validProjectConfig, activatedExperiment, + when(mockEventFactory.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, genericUserId, attributes)) .thenReturn(logEventToDispatch); @@ -2721,7 +2674,7 @@ public void clearNotificationListenersNotificationCenter() throws Exception { // set up argument captor for the attributes map to compare map equality ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); - when(mockEventBuilder.createImpressionEvent( + when(mockEventFactory.createImpressionEvent( eq(validProjectConfig), eq(activatedExperiment), eq(bucketedVariation), @@ -2761,7 +2714,7 @@ public void clearNotificationListenersNotificationCenter() throws Exception { eventType.getKey(), OptimizelyTest.genericUserId, attributes); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(OptimizelyTest.genericUserId), @@ -2794,11 +2747,11 @@ public void trackEventWithListenerAttributes() throws Exception { } // setup a mock event builder to return expected conversion params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -2813,7 +2766,7 @@ public void trackEventWithListenerAttributes() throws Exception { genericUserId, attributes); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -2849,7 +2802,7 @@ public void onTrack(@Nonnull String eventKey, @Nonnull String userId, @Nonnull M ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); // verify that the event builder was called with the expected attributes - verify(mockEventBuilder).createConversionEvent( + verify(mockEventFactory).createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -2881,11 +2834,11 @@ public void trackEventWithListenerNullAttributes() throws Exception { } // setup a mock event builder to return expected conversion params - EventBuilder mockEventBuilder = mock(EventBuilder.class); + EventFactory mockEventFactory = mock(EventFactory.class); Optimizely optimizely = Optimizely.builder(validDatafile, mockEventHandler) .withBucketing(mockBucketer) - .withEventBuilder(mockEventBuilder) + .withEventBuilder(mockEventFactory) .withConfig(validProjectConfig) .withErrorHandler(mockErrorHandler) .build(); @@ -2899,7 +2852,7 @@ public void trackEventWithListenerNullAttributes() throws Exception { genericUserId, Collections.emptyMap()); LogEvent logEventToDispatch = new LogEvent(RequestMethod.GET, "test_url", testParams, ""); - when(mockEventBuilder.createConversionEvent( + when(mockEventFactory.createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), @@ -2938,7 +2891,7 @@ public void onTrack(@Nonnull String eventKey, @Nonnull String userId, @Nonnull M ArgumentCaptor attributeCaptor = ArgumentCaptor.forClass(Map.class); // verify that the event builder was called with the expected attributes - verify(mockEventBuilder).createConversionEvent( + verify(mockEventFactory).createConversionEvent( eq(validProjectConfig), eq(experimentVariationMap), eq(genericUserId), diff --git a/core-api/src/test/java/com/optimizely/ab/event/internal/EventBuilderTest.java b/core-api/src/test/java/com/optimizely/ab/event/internal/EventFactoryTest.java similarity index 81% rename from core-api/src/test/java/com/optimizely/ab/event/internal/EventBuilderTest.java rename to core-api/src/test/java/com/optimizely/ab/event/internal/EventFactoryTest.java index 879386a44..be170c839 100644 --- a/core-api/src/test/java/com/optimizely/ab/event/internal/EventBuilderTest.java +++ b/core-api/src/test/java/com/optimizely/ab/event/internal/EventFactoryTest.java @@ -67,7 +67,7 @@ import static org.mockito.Mockito.when; @RunWith(Parameterized.class) -public class EventBuilderTest { +public class EventFactoryTest { @Parameterized.Parameters public static Collection data() throws IOException { @@ -86,13 +86,13 @@ public static Collection data() throws IOException { private Gson gson = new GsonBuilder() .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create(); - private EventBuilder builder = new EventBuilder(); + private EventFactory factory = new EventFactory(); private static String userId = "userId"; private int datafileVersion; private ProjectConfig validProjectConfig; - public EventBuilderTest(int datafileVersion, + public EventFactoryTest(int datafileVersion, ProjectConfig validProjectConfig) { this.datafileVersion = datafileVersion; this.validProjectConfig = validProjectConfig; @@ -111,21 +111,30 @@ public void createImpressionEventPassingUserAgentAttribute() throws Exception { Map attributeMap = new HashMap(); attributeMap.put(attribute.getKey(), "value"); attributeMap.put(ControlAttribute.USER_AGENT_ATTRIBUTE.toString(), "Chrome"); - Decision expectedDecision = new Decision(activatedExperiment.getLayerId(), activatedExperiment.getId(), bucketedVariation.getId(), false); - com.optimizely.ab.event.internal.payload.Attribute feature = new com.optimizely.ab.event.internal.payload.Attribute(attribute.getId(), - attribute.getKey(), com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - "value"); - com.optimizely.ab.event.internal.payload.Attribute userAgentFeature = new com.optimizely.ab.event.internal.payload.Attribute( - ControlAttribute.USER_AGENT_ATTRIBUTE.toString(), - ControlAttribute.USER_AGENT_ATTRIBUTE.toString(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - "Chrome"); - - com.optimizely.ab.event.internal.payload.Attribute botFilteringFeature = new com.optimizely.ab.event.internal.payload.Attribute( - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - validProjectConfig.getBotFiltering()); + + Decision expectedDecision = new Decision.Builder() + .setCampaignId(activatedExperiment.getLayerId()) + .setExperimentId(activatedExperiment.getId()) + .setVariationId(bucketedVariation.getId()) + .setIsCampaignHoldback(false) + .build(); + + com.optimizely.ab.event.internal.payload.Attribute feature = new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(attribute.getId()) + .setKey(attribute.getKey()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue("value") + .build(); + + com.optimizely.ab.event.internal.payload.Attribute userAgentFeature = new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(ControlAttribute.USER_AGENT_ATTRIBUTE.toString()) + .setKey(ControlAttribute.USER_AGENT_ATTRIBUTE.toString()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue("Chrome") + .build(); + + com.optimizely.ab.event.internal.payload.Attribute botFilteringFeature = getBotFilteringAttribute(); + List expectedUserFeatures; if(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) @@ -133,11 +142,11 @@ public void createImpressionEventPassingUserAgentAttribute() throws Exception { else expectedUserFeatures = Arrays.asList(userAgentFeature, feature); - LogEvent impressionEvent = builder.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, + LogEvent impressionEvent = factory.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, userId, attributeMap); // verify that request endpoint is correct - assertThat(impressionEvent.getEndpointUrl(), is(EventBuilder.EVENT_ENDPOINT)); + assertThat(impressionEvent.getEndpointUrl(), is(EventFactory.EVENT_ENDPOINT)); EventBatch eventBatch = gson.fromJson(impressionEvent.getBody(), EventBatch.class); @@ -168,15 +177,23 @@ public void createImpressionEvent() throws Exception { Attribute attribute = validProjectConfig.getAttributes().get(0); String userId = "userId"; Map attributeMap = Collections.singletonMap(attribute.getKey(), "value"); - Decision expectedDecision = new Decision(activatedExperiment.getLayerId(), activatedExperiment.getId(), bucketedVariation.getId(), false); - com.optimizely.ab.event.internal.payload.Attribute feature = new com.optimizely.ab.event.internal.payload.Attribute(attribute.getId(), - attribute.getKey(), com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - "value"); - com.optimizely.ab.event.internal.payload.Attribute botFilteringFeature = new com.optimizely.ab.event.internal.payload.Attribute( - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - validProjectConfig.getBotFiltering()); + + Decision expectedDecision = new Decision.Builder() + .setCampaignId(activatedExperiment.getLayerId()) + .setExperimentId(activatedExperiment.getId()) + .setVariationId(bucketedVariation.getId()) + .setIsCampaignHoldback(false) + .build(); + + com.optimizely.ab.event.internal.payload.Attribute feature = new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(attribute.getId()) + .setKey(attribute.getKey()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue("value") + .build(); + + com.optimizely.ab.event.internal.payload.Attribute botFilteringFeature = getBotFilteringAttribute(); + List expectedUserFeatures; if(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) @@ -184,11 +201,11 @@ public void createImpressionEvent() throws Exception { else expectedUserFeatures = Arrays.asList(feature); - LogEvent impressionEvent = builder.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, + LogEvent impressionEvent = factory.createImpressionEvent(validProjectConfig, activatedExperiment, bucketedVariation, userId, attributeMap); // verify that request endpoint is correct - assertThat(impressionEvent.getEndpointUrl(), is(EventBuilder.EVENT_ENDPOINT)); + assertThat(impressionEvent.getEndpointUrl(), is(EventFactory.EVENT_ENDPOINT)); EventBatch eventBatch = gson.fromJson(impressionEvent.getBody(), EventBatch.class); @@ -220,7 +237,7 @@ public void createImpressionEventIgnoresUnknownAttributes() throws Exception { Variation bucketedVariation = activatedExperiment.getVariations().get(0); LogEvent impressionEvent = - builder.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, "userId", + factory.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, "userId", Collections.singletonMap("unknownAttribute", "blahValue")); EventBatch impression = gson.fromJson(impressionEvent.getBody(), EventBatch.class); @@ -233,12 +250,12 @@ public void createImpressionEventIgnoresUnknownAttributes() throws Exception { } /** - * Verify that supplying {@link EventBuilder} with a custom client engine and client version results in impression + * Verify that supplying {@link EventFactory} with a custom client engine and client version results in impression * events being sent with the overriden values. */ @Test public void createImpressionEventAndroidClientEngineClientVersion() throws Exception { - EventBuilder builder = new EventBuilder(EventBatch.ClientEngine.ANDROID_SDK, "0.0.0"); + EventFactory factory = new EventFactory(EventBatch.ClientEngine.ANDROID_SDK, "0.0.0"); ProjectConfig projectConfig = validProjectConfigV2(); Experiment activatedExperiment = projectConfig.getExperiments().get(0); Variation bucketedVariation = activatedExperiment.getVariations().get(0); @@ -246,7 +263,7 @@ public void createImpressionEventAndroidClientEngineClientVersion() throws Excep String userId = "userId"; Map attributeMap = Collections.singletonMap(attribute.getKey(), "value"); - LogEvent impressionEvent = builder.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, + LogEvent impressionEvent = factory.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, userId, attributeMap); EventBatch impression = gson.fromJson(impressionEvent.getBody(), EventBatch.class); @@ -255,13 +272,13 @@ public void createImpressionEventAndroidClientEngineClientVersion() throws Excep } /** - * Verify that supplying {@link EventBuilder} with a custom Android TV client engine and client version + * Verify that supplying {@link EventFactory} with a custom Android TV client engine and client version * results in impression events being sent with the overriden values. */ @Test public void createImpressionEventAndroidTVClientEngineClientVersion() throws Exception { String clientVersion = "0.0.0"; - EventBuilder builder = new EventBuilder(EventBatch.ClientEngine.ANDROID_TV_SDK, clientVersion); + EventFactory factory = new EventFactory(EventBatch.ClientEngine.ANDROID_TV_SDK, clientVersion); ProjectConfig projectConfig = validProjectConfigV2(); Experiment activatedExperiment = projectConfig.getExperiments().get(0); Variation bucketedVariation = activatedExperiment.getVariations().get(0); @@ -269,7 +286,7 @@ public void createImpressionEventAndroidTVClientEngineClientVersion() throws Exc String userId = "userId"; Map attributeMap = Collections.singletonMap(attribute.getKey(), "value"); - LogEvent impressionEvent = builder.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, + LogEvent impressionEvent = factory.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, userId, attributeMap); EventBatch impression = gson.fromJson(impressionEvent.getBody(), EventBatch.class); @@ -315,7 +332,7 @@ public void createConversionEvent() throws Exception { eventType.getKey(), userId, attributeMap); - LogEvent conversionEvent = builder.createConversionEvent( + LogEvent conversionEvent = factory.createConversionEvent( validProjectConfig, experimentVariationMap, userId, @@ -328,14 +345,19 @@ public void createConversionEvent() throws Exception { for (Experiment experiment : experimentsForEventKey) { if (experiment.isRunning()) { - Decision layerState = new Decision(experiment.getLayerId(), experiment.getId(), - experiment.getVariations().get(0).getId(), false); + Decision layerState = new Decision.Builder() + .setCampaignId(experiment.getLayerId()) + .setExperimentId(experiment.getId()) + .setVariationId(experiment.getVariations().get(0).getId()) + .setIsCampaignHoldback(false) + .build(); + expectedDecisions.add(layerState); } } // verify that the request endpoint is correct - assertThat(conversionEvent.getEndpointUrl(), is(EventBuilder.EVENT_ENDPOINT)); + assertThat(conversionEvent.getEndpointUrl(), is(EventFactory.EVENT_ENDPOINT)); EventBatch conversion = gson.fromJson(conversionEvent.getBody(), EventBatch.class); @@ -346,20 +368,18 @@ public void createConversionEvent() throws Exception { assertThat(conversion.getProjectId(), is(validProjectConfig.getProjectId())); assertThat(conversion.getAccountId(), is(validProjectConfig.getAccountId())); - com.optimizely.ab.event.internal.payload.Attribute feature = new com.optimizely.ab.event.internal.payload.Attribute(attribute.getId(), attribute.getKey(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - AUDIENCE_GRYFFINDOR_VALUE); - com.optimizely.ab.event.internal.payload.Attribute feature2 = new com.optimizely.ab.event.internal.payload.Attribute( - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - validProjectConfig.getBotFiltering()); - List expectedUserFeatures; + com.optimizely.ab.event.internal.payload.Attribute feature = new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(attribute.getId()).setKey(attribute.getKey()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue(AUDIENCE_GRYFFINDOR_VALUE) + .build(); - if(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) - expectedUserFeatures = Arrays.asList(feature, feature2); - else - expectedUserFeatures = Arrays.asList(feature); + List expectedUserFeatures = new ArrayList(); + expectedUserFeatures.add(feature); + + if(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { + expectedUserFeatures.add(getBotFilteringAttribute()); + } assertEquals(conversion.getVisitors().get(0).getAttributes(), expectedUserFeatures); assertThat(conversion.getVisitors().get(0).getSnapshots().get(0).getDecisions(), containsInAnyOrder(expectedDecisions.toArray())); @@ -415,7 +435,7 @@ public void createConversionEventPassingUserAgentAttribute() throws Exception { eventType.getKey(), userId, attributeMap); - LogEvent conversionEvent = builder.createConversionEvent( + LogEvent conversionEvent = factory.createConversionEvent( validProjectConfig, experimentVariationMap, userId, @@ -428,14 +448,19 @@ public void createConversionEventPassingUserAgentAttribute() throws Exception { for (Experiment experiment : experimentsForEventKey) { if (experiment.isRunning()) { - Decision layerState = new Decision(experiment.getLayerId(), experiment.getId(), - experiment.getVariations().get(0).getId(), false); + Decision layerState = new Decision.Builder() + .setCampaignId(experiment.getLayerId()) + .setExperimentId(experiment.getId()) + .setVariationId(experiment.getVariations().get(0).getId()) + .setIsCampaignHoldback(false) + .build(); + expectedDecisions.add(layerState); } } // verify that the request endpoint is correct - assertThat(conversionEvent.getEndpointUrl(), is(EventBuilder.EVENT_ENDPOINT)); + assertThat(conversionEvent.getEndpointUrl(), is(EventFactory.EVENT_ENDPOINT)); EventBatch conversion = gson.fromJson(conversionEvent.getBody(), EventBatch.class); @@ -444,26 +469,26 @@ public void createConversionEventPassingUserAgentAttribute() throws Exception { assertThat(conversion.getProjectId(), is(validProjectConfig.getProjectId())); assertThat(conversion.getAccountId(), is(validProjectConfig.getAccountId())); - com.optimizely.ab.event.internal.payload.Attribute feature = new com.optimizely.ab.event.internal.payload.Attribute( - attribute.getId(), attribute.getKey(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - AUDIENCE_GRYFFINDOR_VALUE); - com.optimizely.ab.event.internal.payload.Attribute userAgentFeature = new com.optimizely.ab.event.internal.payload.Attribute( - ControlAttribute.USER_AGENT_ATTRIBUTE.toString(), - ControlAttribute.USER_AGENT_ATTRIBUTE.toString(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - "Chrome"); - com.optimizely.ab.event.internal.payload.Attribute botFilteringFeature = new com.optimizely.ab.event.internal.payload.Attribute( - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - validProjectConfig.getBotFiltering()); - List expectedUserFeatures; - - if(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) - expectedUserFeatures = Arrays.asList(userAgentFeature, feature, botFilteringFeature); - else - expectedUserFeatures = Arrays.asList(userAgentFeature, feature); + com.optimizely.ab.event.internal.payload.Attribute feature = new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(attribute.getId()).setKey(attribute.getKey()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue(AUDIENCE_GRYFFINDOR_VALUE) + .build(); + + com.optimizely.ab.event.internal.payload.Attribute userAgentFeature = new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(ControlAttribute.USER_AGENT_ATTRIBUTE.toString()) + .setKey(ControlAttribute.USER_AGENT_ATTRIBUTE.toString()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue("Chrome") + .build(); + + List expectedUserFeatures = new ArrayList(); + expectedUserFeatures.add(userAgentFeature); + expectedUserFeatures.add(feature); + + if(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { + expectedUserFeatures.add(getBotFilteringAttribute()); + } assertEquals(conversion.getVisitors().get(0).getAttributes(), expectedUserFeatures); assertThat(conversion.getVisitors().get(0).getSnapshots().get(0).getDecisions(), containsInAnyOrder(expectedDecisions.toArray())); @@ -515,7 +540,8 @@ public void createConversionParamsWithEventMetrics() throws Exception { eventType.getKey(), userId, attributeMap); - LogEvent conversionEvent = builder.createConversionEvent(validProjectConfig, experimentVariationMap, userId, + + LogEvent conversionEvent = factory.createConversionEvent(validProjectConfig, experimentVariationMap, userId, eventType.getId(), eventType.getKey(), attributeMap, eventTagMap); @@ -557,7 +583,7 @@ public void createConversionEventForcedVariationBucketingPrecedesAudienceEval() eventType.getKey(), whitelistedUserId, Collections.emptyMap()); - LogEvent conversionEvent = builder.createConversionEvent( + LogEvent conversionEvent = factory.createConversionEvent( validProjectConfig, experimentVariationMap, whitelistedUserId, @@ -608,7 +634,7 @@ public void createConversionEventExperimentStatusPrecedesForcedVariation() { eventType.getKey(), whitelistedUserId, Collections.emptyMap()); - LogEvent conversionEvent = builder.createConversionEvent( + LogEvent conversionEvent = factory.createConversionEvent( validProjectConfig, experimentVariationMap, whitelistedUserId, @@ -625,12 +651,12 @@ public void createConversionEventExperimentStatusPrecedesForcedVariation() { } /** - * Verify that supplying {@link EventBuilder} with a custom client engine and client version results in conversion + * Verify that supplying {@link EventFactory} with a custom client engine and client version results in conversion * events being sent with the overriden values. */ @Test public void createConversionEventAndroidClientEngineClientVersion() throws Exception { - EventBuilder builder = new EventBuilder(EventBatch.ClientEngine.ANDROID_SDK, "0.0.0"); + EventFactory factory = new EventFactory(EventBatch.ClientEngine.ANDROID_SDK, "0.0.0"); Attribute attribute = validProjectConfig.getAttributes().get(0); EventType eventType = validProjectConfig.getEventTypes().get(0); @@ -653,7 +679,8 @@ public void createConversionEventAndroidClientEngineClientVersion() throws Excep eventType.getKey(), userId, attributeMap); - LogEvent conversionEvent = builder.createConversionEvent( + + LogEvent conversionEvent = factory.createConversionEvent( validProjectConfig, experimentVariationMap, userId, @@ -669,13 +696,13 @@ public void createConversionEventAndroidClientEngineClientVersion() throws Excep } /** - * Verify that supplying {@link EventBuilder} with a Android TV client engine and client version results in + * Verify that supplying {@link EventFactory} with a Android TV client engine and client version results in * conversion events being sent with the overriden values. */ @Test public void createConversionEventAndroidTVClientEngineClientVersion() throws Exception { String clientVersion = "0.0.0"; - EventBuilder builder = new EventBuilder(EventBatch.ClientEngine.ANDROID_TV_SDK, clientVersion); + EventFactory factory = new EventFactory(EventBatch.ClientEngine.ANDROID_TV_SDK, clientVersion); ProjectConfig projectConfig = validProjectConfigV2(); Attribute attribute = projectConfig.getAttributes().get(0); EventType eventType = projectConfig.getEventTypes().get(0); @@ -694,7 +721,7 @@ public void createConversionEventAndroidTVClientEngineClientVersion() throws Exc experimentVariationMap.put(experiment, experiment.getVariations().get(0)); } - LogEvent conversionEvent = builder.createConversionEvent( + LogEvent conversionEvent = factory.createConversionEvent( projectConfig, experimentVariationMap, userId, @@ -710,15 +737,15 @@ public void createConversionEventAndroidTVClientEngineClientVersion() throws Exc /** * Verify that supplying an empty Experiment Variation map to - * {@link EventBuilder#createConversionEvent(ProjectConfig, Map, String, String, String, Map, Map)} + * {@link EventFactory#createConversionEvent(ProjectConfig, Map, String, String, String, Map, Map)} * returns a null {@link LogEvent}. */ @Test public void createConversionEventReturnsNullWhenExperimentVariationMapIsEmpty() { EventType eventType = validProjectConfig.getEventTypes().get(0); - EventBuilder builder = new EventBuilder(); + EventFactory factory = new EventFactory(); - LogEvent conversionEvent = builder.createConversionEvent( + LogEvent conversionEvent = factory.createConversionEvent( validProjectConfig, Collections.emptyMap(), userId, @@ -747,34 +774,39 @@ public void createImpressionEventWithBucketingId() throws Exception { attributeMap.put(ControlAttribute.BUCKETING_ATTRIBUTE.toString(), "variation"); - Decision expectedDecision = new Decision(activatedExperiment.getLayerId(), activatedExperiment.getId(), bucketedVariation.getId(), false); - - com.optimizely.ab.event.internal.payload.Attribute feature = new com.optimizely.ab.event.internal.payload.Attribute(attribute.getId(), attribute.getKey(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - "value"); - com.optimizely.ab.event.internal.payload.Attribute feature1 = new com.optimizely.ab.event.internal.payload.Attribute( - ControlAttribute.BUCKETING_ATTRIBUTE.toString(), - ControlAttribute.BUCKETING_ATTRIBUTE.toString(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - "variation"); - com.optimizely.ab.event.internal.payload.Attribute feature2 = new com.optimizely.ab.event.internal.payload.Attribute( - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - validProjectConfig.getBotFiltering()); - - List expectedUserFeatures; - - if(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) - expectedUserFeatures = Arrays.asList(feature, feature1, feature2); - else - expectedUserFeatures = Arrays.asList(feature, feature1); + Decision expectedDecision = new Decision.Builder() + .setCampaignId(activatedExperiment.getLayerId()) + .setExperimentId(activatedExperiment.getId()) + .setVariationId(bucketedVariation.getId()) + .setIsCampaignHoldback(false) + .build(); + + com.optimizely.ab.event.internal.payload.Attribute feature = new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(attribute.getId()).setKey(attribute.getKey()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue("value") + .build(); + + com.optimizely.ab.event.internal.payload.Attribute feature1 = new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(ControlAttribute.BUCKETING_ATTRIBUTE.toString()) + .setKey(ControlAttribute.BUCKETING_ATTRIBUTE.toString()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue("variation") + .build(); + + List expectedUserFeatures = new ArrayList(); + expectedUserFeatures.add(feature); + expectedUserFeatures.add(feature1); + + if(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { + expectedUserFeatures.add(getBotFilteringAttribute()); + } - LogEvent impressionEvent = builder.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, + LogEvent impressionEvent = factory.createImpressionEvent(projectConfig, activatedExperiment, bucketedVariation, userId, attributeMap); // verify that request endpoint is correct - assertThat(impressionEvent.getEndpointUrl(), is(EventBuilder.EVENT_ENDPOINT)); + assertThat(impressionEvent.getEndpointUrl(), is(EventFactory.EVENT_ENDPOINT)); EventBatch impression = gson.fromJson(impressionEvent.getBody(), EventBatch.class); @@ -830,13 +862,15 @@ public void createConversionEventWithBucketingId() throws Exception { Map eventTagMap = new HashMap(); eventTagMap.put("boolean_param", false); eventTagMap.put("string_param", "123"); + Map experimentVariationMap = createExperimentVariationMap( validProjectConfig, decisionService, eventType.getKey(), userId, attributeMap); - LogEvent conversionEvent = builder.createConversionEvent( + + LogEvent conversionEvent = factory.createConversionEvent( validProjectConfig, experimentVariationMap, userId, @@ -849,14 +883,19 @@ public void createConversionEventWithBucketingId() throws Exception { for (Experiment experiment : experimentsForEventKey) { if (experiment.isRunning()) { - Decision decision = new Decision(experiment.getLayerId(), experiment.getId(), - experiment.getVariations().get(0).getId(), false); + Decision decision = new Decision.Builder() + .setCampaignId(experiment.getLayerId()) + .setExperimentId(experiment.getId()) + .setVariationId(experiment.getVariations().get(0).getId()) + .setIsCampaignHoldback(false) + .build(); + expectedDecisions.add(decision); } } // verify that the request endpoint is correct - assertThat(conversionEvent.getEndpointUrl(), is(EventBuilder.EVENT_ENDPOINT)); + assertThat(conversionEvent.getEndpointUrl(), is(EventFactory.EVENT_ENDPOINT)); EventBatch conversion = gson.fromJson(conversionEvent.getBody(), EventBatch.class); @@ -866,25 +905,26 @@ public void createConversionEventWithBucketingId() throws Exception { assertThat(conversion.getProjectId(), is(validProjectConfig.getProjectId())); assertThat(conversion.getAccountId(), is(validProjectConfig.getAccountId())); - com.optimizely.ab.event.internal.payload.Attribute attribute1 = new com.optimizely.ab.event.internal.payload.Attribute(attribute.getId(), attribute.getKey(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - AUDIENCE_GRYFFINDOR_VALUE); - com.optimizely.ab.event.internal.payload.Attribute attribute2 = new com.optimizely.ab.event.internal.payload.Attribute( - ControlAttribute.BUCKETING_ATTRIBUTE.toString(), - ControlAttribute.BUCKETING_ATTRIBUTE.toString(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - bucketingId); - com.optimizely.ab.event.internal.payload.Attribute attribute3 = new com.optimizely.ab.event.internal.payload.Attribute( - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString(), - com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE, - validProjectConfig.getBotFiltering()); - List expectedUserFeatures; - - if(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) - expectedUserFeatures = Arrays.asList(attribute1, attribute2, attribute3); - else - expectedUserFeatures = Arrays.asList(attribute1, attribute2); + com.optimizely.ab.event.internal.payload.Attribute attribute1 = new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(attribute.getId()).setKey(attribute.getKey()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue(AUDIENCE_GRYFFINDOR_VALUE) + .build(); + + com.optimizely.ab.event.internal.payload.Attribute attribute2 = new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(ControlAttribute.BUCKETING_ATTRIBUTE.toString()) + .setKey(ControlAttribute.BUCKETING_ATTRIBUTE.toString()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue(bucketingId) + .build(); + + List expectedUserFeatures = new ArrayList(); + expectedUserFeatures.add(attribute1); + expectedUserFeatures.add(attribute2); + + if(datafileVersion >= Integer.parseInt(ProjectConfig.Version.V4.toString())) { + expectedUserFeatures.add(getBotFilteringAttribute()); + } assertEquals(conversion.getVisitors().get(0).getAttributes(), expectedUserFeatures); assertThat(conversion.getVisitors().get(0).getSnapshots().get(0).getDecisions(), containsInAnyOrder(expectedDecisions.toArray())); @@ -921,5 +961,14 @@ public static Map createExperimentVariationMap(ProjectCon return experimentVariationMap; } + + private com.optimizely.ab.event.internal.payload.Attribute getBotFilteringAttribute() { + return new com.optimizely.ab.event.internal.payload.Attribute.Builder() + .setEntityId(ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString()) + .setKey(ControlAttribute.BOT_FILTERING_ATTRIBUTE.toString()) + .setType(com.optimizely.ab.event.internal.payload.Attribute.CUSTOM_ATTRIBUTE_TYPE) + .setValue(validProjectConfig.getBotFiltering()) + .build(); + } } diff --git a/core-api/src/test/java/com/optimizely/ab/event/internal/serializer/SerializerTestUtils.java b/core-api/src/test/java/com/optimizely/ab/event/internal/serializer/SerializerTestUtils.java index 0e46737d8..8edf39baa 100644 --- a/core-api/src/test/java/com/optimizely/ab/event/internal/serializer/SerializerTestUtils.java +++ b/core-api/src/test/java/com/optimizely/ab/event/internal/serializer/SerializerTestUtils.java @@ -26,7 +26,6 @@ import com.optimizely.ab.event.internal.payload.Visitor; import java.io.IOException; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -34,7 +33,6 @@ public class SerializerTestUtils { private static final String visitorId = "testvisitor"; private static final long timestamp = 12345L; - private static final boolean isGlobalHoldback = false; private static final String projectId = "1"; private static final String layerId = "2"; private static final String accountId = "3"; @@ -43,38 +41,57 @@ public class SerializerTestUtils { private static final String experimentId = "5"; private static final String sessionId = "sessionid"; private static final String revision = "1"; - private static final Decision decision = new Decision(layerId, experimentId, variationId, isLayerHoldback); + private static final Decision decision = new Decision.Builder() + .setCampaignId(layerId) + .setExperimentId(experimentId) + .setVariationId(variationId) + .setIsCampaignHoldback(isLayerHoldback) + .build(); private static final String featureId = "6"; private static final String featureName = "testfeature"; private static final String featureType = "custom"; private static final String featureValue = "testfeaturevalue"; - private static final boolean shouldIndex = true; - private static final List userFeatures = Collections.singletonList( - new Attribute(featureId, featureName, featureType, featureValue)); - - private static final boolean actionTriggered = true; + private static final List userFeatures = Collections.singletonList(new Attribute.Builder() + .setEntityId(featureId) + .setKey(featureName) + .setType(featureType) + .setValue(featureValue) + .build()); private static final String eventEntityId = "7"; private static final String eventName = "testevent"; - private static final String eventMetricName = "revenue"; - private static final long eventMetricValue = 5000L; - private static final List events = Collections.singletonList(new Event(timestamp, - "uuid", eventEntityId, eventName, null, 5000L, null, eventName, null)); + private static final List events = Collections.singletonList(new Event.Builder() + .setTimestamp(timestamp) + .setUuid("uuid") + .setEntityId(eventEntityId) + .setKey(eventName) + .setRevenue(5000L) + .setType(eventName) + .build() + ); static EventBatch generateImpression() { - Snapshot snapshot = new Snapshot(Arrays.asList(decision), events); - - Visitor vistor = new Visitor(visitorId, null, userFeatures, Arrays.asList(snapshot)); - EventBatch impression = new EventBatch(accountId, Arrays.asList(vistor), false, projectId,revision ); - impression.setProjectId(projectId); - impression.setAccountId(accountId); - impression.setClientVersion("0.1.1"); - impression.setAnonymizeIp(true); - impression.setRevision(revision); - - return impression; + Snapshot snapshot = new Snapshot.Builder() + .setDecisions(Collections.singletonList(decision)) + .setEvents(events) + .build(); + + Visitor visitor = new Visitor.Builder() + .setVisitorId(visitorId) + .setAttributes(userFeatures) + .setSnapshots(Collections.singletonList(snapshot)) + .build(); + + return new EventBatch.Builder() + .setClientVersion("0.1.1") + .setAccountId(accountId) + .setVisitors(Collections.singletonList(visitor)) + .setAnonymizeIp(true) + .setProjectId(projectId) + .setRevision(revision) + .build(); } static EventBatch generateImpressionWithSessionId() {