diff --git a/iterable-extension/build.gradle b/iterable-extension/build.gradle index bdf8d06..fc4489c 100644 --- a/iterable-extension/build.gradle +++ b/iterable-extension/build.gradle @@ -1,4 +1,7 @@ -apply plugin: 'java' +plugins { + id 'java' + id 'com.github.sherter.google-java-format' version '0.8' +} repositories { mavenLocal() @@ -25,4 +28,10 @@ task buildZip(type: Zip) { } } +tasks.verifyGoogleJavaFormat.ignoreFailures = true + +googleJavaFormat { + options style: 'AOSP' +} + build.dependsOn buildZip diff --git a/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableExtension.java b/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableExtension.java index a33803e..238a421 100644 --- a/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableExtension.java +++ b/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableExtension.java @@ -1,6 +1,5 @@ package com.mparticle.ext.iterable; - import com.fasterxml.jackson.databind.ObjectMapper; import com.mparticle.iterable.*; import com.mparticle.sdk.MessageProcessor; @@ -10,12 +9,11 @@ import com.mparticle.sdk.model.audienceprocessing.UserProfile; import com.mparticle.sdk.model.eventprocessing.*; import com.mparticle.sdk.model.registration.*; -import retrofit2.Call; -import retrofit2.Response; - import java.io.IOException; import java.util.*; import java.util.stream.Collectors; +import retrofit2.Call; +import retrofit2.Response; public class IterableExtension extends MessageProcessor { @@ -35,17 +33,24 @@ public class IterableExtension extends MessageProcessor { IterableService iterableService = IterableService.newInstance(); @Override - public ModuleRegistrationResponse processRegistrationRequest(ModuleRegistrationRequest request) { + public ModuleRegistrationResponse processRegistrationRequest( + ModuleRegistrationRequest request) { // Processing ModuleRegistrationRequests is handled by the Ingress Lambda. return new ModuleRegistrationResponse("Iterable", "1.6.0"); } - + /** + * When a MessageProcessor is given a batch of data/events, it will first call this method. This + * is a good time to do some setup. + */ @Override - public EventProcessingResponse processEventProcessingRequest(EventProcessingRequest request) throws IOException { + public EventProcessingResponse processEventProcessingRequest(EventProcessingRequest request) + throws IOException { Collections.sort( request.getEvents(), - (a, b) -> a.getTimestamp() > b.getTimestamp() ? 1 : a.getTimestamp() == b.getTimestamp() ? 0 : -1 - ); + (a, b) -> + a.getTimestamp() > b.getTimestamp() + ? 1 + : a.getTimestamp() == b.getTimestamp() ? 0 : -1); insertPlaceholderEmail(request); updateUser(request); processPushOpens(request); @@ -59,39 +64,50 @@ private void processPushOpens(EventProcessingRequest processingRequest) throws I } if (processingRequest.getEvents() != null) { - List pushOpenEvents = processingRequest.getEvents().stream() - .filter(e -> e.getType() == Event.Type.PUSH_MESSAGE_OPEN) - .map(e -> (PushMessageOpenEvent) e) - .collect(Collectors.toList()); + List pushOpenEvents = + processingRequest + .getEvents() + .stream() + .filter(e -> e.getType() == Event.Type.PUSH_MESSAGE_OPEN) + .map(e -> (PushMessageOpenEvent) e) + .collect(Collectors.toList()); for (PushMessageOpenEvent event : pushOpenEvents) { TrackPushOpenRequest request = new TrackPushOpenRequest(); if (event.getPayload() != null && processingRequest.getUserIdentities() != null) { addUserIdentitiesToRequest(request, processingRequest); if (request.email == null && request.userId == null) { - IterableExtensionLogger.logError("Unable to process PushMessageOpenEvent - user has no email or customer id."); + IterableExtensionLogger.logError( + "Unable to process PushMessageOpenEvent - user has no email or customer id."); return; } ObjectMapper mapper = new ObjectMapper(); Map payload = mapper.readValue(event.getPayload(), Map.class); if (payload.containsKey("itbl")) { - //Android and iOS have differently encoded payload formats. See the tests for examples. + // Android and iOS have differently encoded payload formats. See the tests + // for examples. Map iterableMap; - if (processingRequest.getRuntimeEnvironment() instanceof AndroidRuntimeEnvironment) { + if (processingRequest.getRuntimeEnvironment() + instanceof AndroidRuntimeEnvironment) { iterableMap = mapper.readValue((String) payload.get("itbl"), Map.class); } else { iterableMap = (Map) payload.get("itbl"); } - request.campaignId = convertItblPayloadFieldToInt(iterableMap.get("campaignId")); - request.templateId = convertItblPayloadFieldToInt(iterableMap.get("templateId")); + request.campaignId = + convertItblPayloadFieldToInt(iterableMap.get("campaignId")); + request.templateId = + convertItblPayloadFieldToInt(iterableMap.get("templateId")); request.messageId = (String) iterableMap.get("messageId"); if (request.campaignId == 0 || request.templateId == 0) { // Proof sends don't have a campaignId return; } request.createdAt = (int) (event.getTimestamp() / 1000.0); - Call preparedCall = iterableService.trackPushOpen(getApiKey(processingRequest), request); - Response response = makeIterableRequest(preparedCall, event.getId()); + Call preparedCall = + iterableService.trackPushOpen( + getApiKey(processingRequest), request); + Response response = + makeIterableRequest(preparedCall, event.getId()); handleIterableResponse(response, event.getId()); } } @@ -117,13 +133,17 @@ private static String getApiKey(AudienceMembershipChangeRequest event) { /** * Verify that there's an email present, create a placeholder if not. * - * @param request + * @param request the mParticle request * @throws IOException */ private void insertPlaceholderEmail(EventProcessingRequest request) throws IOException { - long count = request.getUserIdentities() == null ? 0 : request.getUserIdentities().stream() - .filter(t -> t.getType().equals(UserIdentity.Type.EMAIL)) - .count(); + long count = + request.getUserIdentities() == null + ? 0 + : request.getUserIdentities() + .stream() + .filter(t -> t.getType().equals(UserIdentity.Type.EMAIL)) + .count(); if (count > 0) { return; } @@ -131,9 +151,21 @@ private void insertPlaceholderEmail(EventProcessingRequest request) throws IOExc if (request.getUserIdentities() == null) { request.setUserIdentities(new ArrayList<>()); } - request.getUserIdentities().add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, placeholderEmail)); + request.getUserIdentities() + .add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, placeholderEmail)); } + /** + * Map mParticle PushSubscriptionEvent to Iterable RegisterDeviceTokenRequest. + * + *

mParticle push_registration: + * https://docs.mparticle.com/developers/server/json-reference/#push_registration Iterable + * registerDeviceToken: https://api.iterable.com/api/docs#users_registerDeviceToken + * + * @param event the mParticle push subscription event + */ @Override public void processPushSubscriptionEvent(PushSubscriptionEvent event) throws IOException { // Skip processing if the SDK is present - it registers tokens automatically @@ -146,82 +178,134 @@ public void processPushSubscriptionEvent(PushSubscriptionEvent event) throws IOE return; } request.device = new Device(); - if (event.getRequest().getRuntimeEnvironment().getType().equals(RuntimeEnvironment.Type.IOS)) { - Boolean sandboxed = ((IosRuntimeEnvironment) event.getRequest().getRuntimeEnvironment()).getIsSandboxed(); + if (event.getRequest() + .getRuntimeEnvironment() + .getType() + .equals(RuntimeEnvironment.Type.IOS)) { + Boolean sandboxed = + ((IosRuntimeEnvironment) event.getRequest().getRuntimeEnvironment()) + .getIsSandboxed(); if (sandboxed != null && sandboxed) { request.device.platform = Device.PLATFORM_APNS_SANDBOX; - request.device.applicationName = event.getRequest().getAccount().getAccountSettings().get(SETTING_APNS_SANDBOX_KEY); + request.device.applicationName = + event.getRequest() + .getAccount() + .getAccountSettings() + .get(SETTING_APNS_SANDBOX_KEY); } else { request.device.platform = Device.PLATFORM_APNS; - request.device.applicationName = event.getRequest().getAccount().getAccountSettings().get(SETTING_APNS_KEY); + request.device.applicationName = + event.getRequest().getAccount().getAccountSettings().get(SETTING_APNS_KEY); } - } else if (event.getRequest().getRuntimeEnvironment().getType().equals(RuntimeEnvironment.Type.ANDROID)) { + } else if (event.getRequest() + .getRuntimeEnvironment() + .getType() + .equals(RuntimeEnvironment.Type.ANDROID)) { request.device.platform = Device.PLATFORM_GCM; - request.device.applicationName = event.getRequest().getAccount().getAccountSettings().get(SETTING_GCM_NAME_KEY); + request.device.applicationName = + event.getRequest().getAccount().getAccountSettings().get(SETTING_GCM_NAME_KEY); } else { - IterableExtensionLogger.logError("Cannot process push subscription event for unknown RuntimeEnvironment type."); + IterableExtensionLogger.logError( + "Cannot process push subscription event for unknown RuntimeEnvironment type."); return; } request.device.token = event.getToken(); try { - UserIdentity email = event.getRequest().getUserIdentities().stream() - .filter(t -> t.getType().equals(UserIdentity.Type.EMAIL)) - .findFirst() - .get(); + UserIdentity email = + event.getRequest() + .getUserIdentities() + .stream() + .filter(t -> t.getType().equals(UserIdentity.Type.EMAIL)) + .findFirst() + .get(); request.email = email.getValue(); } catch (NoSuchElementException e) { - IterableExtensionLogger.logError("Unable to construct Iterable RegisterDeviceTokenRequest - no user email."); + IterableExtensionLogger.logError( + "Unable to construct Iterable RegisterDeviceTokenRequest - no user email."); return; } - Call preparedCall = iterableService.registerToken(getApiKey(event), request); + Call preparedCall = + iterableService.registerToken(getApiKey(event), request); Response response = makeIterableRequest(preparedCall, event.getId()); handleIterableResponse(response, event.getId()); } + /** + * Collect user attributes from mParticle request and make Iterable UpdateEmailRequest and/or + * UserUpdateRequest. + * + *

mParticle user_attributes: + * https://docs.mparticle.com/developers/server/json-reference/#user_attributes Iterable + * updateUser: https://api.iterable.com/api/docs#users_updateUser Iterable updateEmail: + * https://api.iterable.com/api/docs#users_updateEmail + * + * @param request the mParticle request + */ void updateUser(EventProcessingRequest request) throws IOException { if (request.getEvents() != null) { - List emailChangeEvents = request.getEvents().stream() - .filter(e -> e.getType() == Event.Type.USER_IDENTITY_CHANGE) - .map(e -> (UserIdentityChangeEvent) e) - .filter(e -> e.getAdded() != null && e.getRemoved() != null) - .filter(e -> e.getAdded().size() > 0 && e.getRemoved().size() > 0) - .filter(e -> e.getAdded().get(0).getType().equals(UserIdentity.Type.EMAIL)) - .filter(e -> !isEmpty(e.getAdded().get(0).getValue()) && !isEmpty(e.getRemoved().get(0).getValue())) - .collect(Collectors.toList()); - - List emailAddedEvents = request.getEvents().stream() - .filter(e -> e.getType() == Event.Type.USER_IDENTITY_CHANGE) - .map(e -> (UserIdentityChangeEvent) e) - .filter(e -> e.getAdded() != null && e.getAdded().size() > 0) - .filter(e -> e.getRemoved() == null || e.getRemoved().size() == 0) - .filter(e -> e.getAdded().get(0).getType().equals(UserIdentity.Type.EMAIL)) - .filter(e -> !isEmpty(e.getAdded().get(0).getValue())) - .collect(Collectors.toList()); + List emailChangeEvents = + request.getEvents() + .stream() + .filter(e -> e.getType() == Event.Type.USER_IDENTITY_CHANGE) + .map(e -> (UserIdentityChangeEvent) e) + .filter(e -> e.getAdded() != null && e.getRemoved() != null) + .filter(e -> e.getAdded().size() > 0 && e.getRemoved().size() > 0) + .filter( + e -> + e.getAdded() + .get(0) + .getType() + .equals(UserIdentity.Type.EMAIL)) + .filter( + e -> + !isEmpty(e.getAdded().get(0).getValue()) + && !isEmpty(e.getRemoved().get(0).getValue())) + .collect(Collectors.toList()); + + List emailAddedEvents = + request.getEvents() + .stream() + .filter(e -> e.getType() == Event.Type.USER_IDENTITY_CHANGE) + .map(e -> (UserIdentityChangeEvent) e) + .filter(e -> e.getAdded() != null && e.getAdded().size() > 0) + .filter(e -> e.getRemoved() == null || e.getRemoved().size() == 0) + .filter( + e -> + e.getAdded() + .get(0) + .getType() + .equals(UserIdentity.Type.EMAIL)) + .filter(e -> !isEmpty(e.getAdded().get(0).getValue())) + .collect(Collectors.toList()); String placeholderEmail = getPlaceholderEmail(request); - //convert from placeholder to email now that we have one + // convert from placeholder to email now that we have one for (UserIdentityChangeEvent changeEvent : emailAddedEvents) { UpdateEmailRequest updateEmailRequest = new UpdateEmailRequest(); updateEmailRequest.currentEmail = placeholderEmail; - //this is safe due to the filters above + // this is safe due to the filters above updateEmailRequest.newEmail = changeEvent.getAdded().get(0).getValue(); - Call preparedCall = iterableService.updateEmail(getApiKey(request), updateEmailRequest); - Response response = makeIterableRequest(preparedCall, changeEvent.getId()); + Call preparedCall = + iterableService.updateEmail(getApiKey(request), updateEmailRequest); + Response response = + makeIterableRequest(preparedCall, changeEvent.getId()); handleIterableResponse(response, changeEvent.getId()); } - //convert from old to new email + // convert from old to new email for (UserIdentityChangeEvent changeEvent : emailChangeEvents) { UpdateEmailRequest updateEmailRequest = new UpdateEmailRequest(); - //these are safe due to the filters above + // these are safe due to the filters above updateEmailRequest.currentEmail = changeEvent.getRemoved().get(0).getValue(); updateEmailRequest.newEmail = changeEvent.getAdded().get(0).getValue(); - Call preparedCall = iterableService.updateEmail(getApiKey(request), updateEmailRequest); - Response response = makeIterableRequest(preparedCall, changeEvent.getId()); + Call preparedCall = + iterableService.updateEmail(getApiKey(request), updateEmailRequest); + Response response = + makeIterableRequest(preparedCall, changeEvent.getId()); handleIterableResponse(response, changeEvent.getId()); } } @@ -230,20 +314,25 @@ void updateUser(EventProcessingRequest request) throws IOException { if (request.getUserIdentities() != null) { addUserIdentitiesToRequest(userUpdateRequest, request); if (!isEmpty(userUpdateRequest.email) || !isEmpty(userUpdateRequest.userId)) { - userUpdateRequest.dataFields = convertAttributes(request.getUserAttributes(), shouldCoerceStrings(request)); - Call preparedCall = iterableService.userUpdate(getApiKey(request), userUpdateRequest); - Response response = makeIterableRequest(preparedCall, request.getId()); + userUpdateRequest.dataFields = + convertAttributes( + request.getUserAttributes(), shouldCoerceStrings(request)); + Call preparedCall = + iterableService.userUpdate(getApiKey(request), userUpdateRequest); + Response response = + makeIterableRequest(preparedCall, request.getId()); handleIterableResponse(response, request.getId()); } } } - private Map convertAttributes(Map attributes, boolean coerceStringsToScalars) { + private Map convertAttributes( + Map attributes, boolean coerceStringsToScalars) { if (attributes == null) { return null; } Map attributesWithReserved = convertReservedAttributes(attributes); - + if (coerceStringsToScalars) { return attemptTypeConversion(attributesWithReserved); } else { @@ -267,16 +356,18 @@ private static Map convertReservedAttributes(Map } private static boolean shouldCoerceStrings(EventProcessingRequest request) { - String settingValue = request.getAccount().getAccountSettings().get(SETTING_COERCE_STRINGS_TO_SCALARS); - - if (settingValue == null) { + String settingValue = + request.getAccount().getAccountSettings().get(SETTING_COERCE_STRINGS_TO_SCALARS); + + if (settingValue == null) { return false; } return Boolean.parseBoolean(settingValue); } private static boolean shouldUseMPID(Account account) { - String settingValue = account.getStringSetting(SETTING_USER_ID_FIELD,false, USER_ID_FIELD_CUSTOMER_ID); + String settingValue = + account.getStringSetting(SETTING_USER_ID_FIELD, false, USER_ID_FIELD_CUSTOMER_ID); return settingValue.equals(USER_ID_FIELD_MPID); } @@ -285,10 +376,11 @@ private static boolean isEmpty(CharSequence chars) { } /** - * Map an mParticle `purchase` product_action to Iterable's `trackPurchase` request. + * Map mParticle ProductActionEvent to Iterable TrackPurchaseRequest. * - * mParticle product_action: https://docs.mparticle.com/developers/server/json-reference#product_action - * Iterable trackPurchase: https://api.iterable.com/api/docs#commerce_trackPurchase + *

mParticle product_action: + * https://docs.mparticle.com/developers/server/json-reference#product_action Iterable + * trackPurchase: https://api.iterable.com/api/docs#commerce_trackPurchase * * @param event the mParticle event * @throws IOException @@ -304,17 +396,22 @@ public void processProductActionEvent(ProductActionEvent event) throws IOExcepti ApiUser apiUser = new ApiUser(); addUserIdentitiesToRequest(apiUser, event.getRequest()); boolean shouldCoerceStrings = shouldCoerceStrings(event.getRequest()); - apiUser.dataFields = convertAttributes(event.getRequest().getUserAttributes(), shouldCoerceStrings); + apiUser.dataFields = + convertAttributes(event.getRequest().getUserAttributes(), shouldCoerceStrings); purchaseRequest.user = apiUser; purchaseRequest.total = event.getTotalAmount(); if (event.getProducts() != null) { - purchaseRequest.items = event.getProducts().stream() - .map(p -> convertToCommerceItem(p, shouldCoerceStrings)) - .collect(Collectors.toList()); + purchaseRequest.items = + event.getProducts() + .stream() + .map(p -> convertToCommerceItem(p, shouldCoerceStrings)) + .collect(Collectors.toList()); } - Call preparedCall = iterableService.trackPurchase(getApiKey(event), purchaseRequest); - Response response = makeIterableRequest(preparedCall, event.getId()); + Call preparedCall = + iterableService.trackPurchase(getApiKey(event), purchaseRequest); + Response response = + makeIterableRequest(preparedCall, event.getId()); handleIterableResponse(response, event.getId()); } } @@ -322,8 +419,8 @@ public void processProductActionEvent(ProductActionEvent event) throws IOExcepti CommerceItem convertToCommerceItem(Product product, boolean shouldCoerceStrings) { CommerceItem item = new CommerceItem(); item.dataFields = convertAttributes(product.getAttributes(), shouldCoerceStrings); - //iterable requires ID, and they also take SKU. mParticle doesn't differentiate - //between sku and id. so, use our sku/id for both in Iterable: + // iterable requires ID, and they also take SKU. mParticle doesn't differentiate + // between sku and id. so, use our sku/id for both in Iterable: item.id = item.sku = product.getId(); item.name = product.getName(); item.price = product.getPrice(); @@ -339,62 +436,98 @@ CommerceItem convertToCommerceItem(Product product, boolean shouldCoerceStrings) @Override public void processUserAttributeChangeEvent(UserAttributeChangeEvent event) { - //there's no reason to do this - it's already done at the start of batch processing - //updateUser(event.getContext()); + // there's no reason to do this - it's already done at the start of batch processing + // updateUser(event.getContext()); } /** + * Make the best attempt at creating a placeholder email, prioritize: 1. MPID if enabled 2. + * Platform respective device IDs 3. customer Id 4. device application stamps * - * Make the best attempt at creating a placeholder email, prioritize: - * 1. MPID if enabled - * 2. Platform respective device IDs - * 3. customer Id - * 4. device application stamps * @param request - * @return - * - * Also see: https://support.iterable.com/hc/en-us/articles/208499956-Creating-user-profiles-without-an-email-address + * @return Also see: + * https://support.iterable.com/hc/en-us/articles/208499956-Creating-user-profiles-without-an-email-address */ static String getPlaceholderEmail(EventProcessingRequest request) throws IOException { String id = null; if (shouldUseMPID(request.getAccount())) { id = request.getMpId(); } else { - if (request.getRuntimeEnvironment() instanceof IosRuntimeEnvironment || request.getRuntimeEnvironment() instanceof TVOSRuntimeEnvironment ) { + if (request.getRuntimeEnvironment() instanceof IosRuntimeEnvironment + || request.getRuntimeEnvironment() instanceof TVOSRuntimeEnvironment) { List deviceIdentities = null; if (request.getRuntimeEnvironment() instanceof IosRuntimeEnvironment) { - deviceIdentities = ((IosRuntimeEnvironment) request.getRuntimeEnvironment()).getIdentities(); + deviceIdentities = + ((IosRuntimeEnvironment) request.getRuntimeEnvironment()) + .getIdentities(); } else { - deviceIdentities = ((TVOSRuntimeEnvironment) request.getRuntimeEnvironment()).getIdentities(); + deviceIdentities = + ((TVOSRuntimeEnvironment) request.getRuntimeEnvironment()) + .getIdentities(); } if (deviceIdentities != null) { - DeviceIdentity deviceIdentity = deviceIdentities.stream().filter(t -> t.getType().equals(DeviceIdentity.Type.IOS_VENDOR_ID)) - .findFirst() - .orElse(null); + DeviceIdentity deviceIdentity = + deviceIdentities + .stream() + .filter( + t -> + t.getType() + .equals( + DeviceIdentity.Type + .IOS_VENDOR_ID)) + .findFirst() + .orElse(null); if (deviceIdentity != null) { id = deviceIdentity.getValue(); } if (isEmpty(id)) { - deviceIdentity = deviceIdentities.stream().filter(t -> t.getType().equals(DeviceIdentity.Type.IOS_ADVERTISING_ID)) - .findFirst() - .orElse(null); + deviceIdentity = + deviceIdentities + .stream() + .filter( + t -> + t.getType() + .equals( + DeviceIdentity.Type + .IOS_ADVERTISING_ID)) + .findFirst() + .orElse(null); if (deviceIdentity != null) { id = deviceIdentity.getValue(); } } } } else if (request.getRuntimeEnvironment() instanceof AndroidRuntimeEnvironment) { - if (((AndroidRuntimeEnvironment)request.getRuntimeEnvironment()).getIdentities() != null) { - DeviceIdentity deviceIdentity = ((AndroidRuntimeEnvironment)request.getRuntimeEnvironment()).getIdentities().stream().filter(t -> t.getType().equals(DeviceIdentity.Type.GOOGLE_ADVERTISING_ID)) - .findFirst() - .orElse(null); + if (((AndroidRuntimeEnvironment) request.getRuntimeEnvironment()).getIdentities() + != null) { + DeviceIdentity deviceIdentity = + ((AndroidRuntimeEnvironment) request.getRuntimeEnvironment()) + .getIdentities() + .stream() + .filter( + t -> + t.getType() + .equals( + DeviceIdentity.Type + .GOOGLE_ADVERTISING_ID)) + .findFirst() + .orElse(null); if (deviceIdentity != null) { id = deviceIdentity.getValue(); } if (isEmpty(id)) { - deviceIdentity = ((AndroidRuntimeEnvironment) request.getRuntimeEnvironment()).getIdentities().stream().filter(t -> t.getType().equals(DeviceIdentity.Type.ANDROID_ID)) - .findFirst() - .orElse(null); + deviceIdentity = + ((AndroidRuntimeEnvironment) request.getRuntimeEnvironment()) + .getIdentities() + .stream() + .filter( + t -> + t.getType() + .equals( + DeviceIdentity.Type + .ANDROID_ID)) + .findFirst() + .orElse(null); if (deviceIdentity != null) { id = deviceIdentity.getValue(); } @@ -404,10 +537,12 @@ static String getPlaceholderEmail(EventProcessingRequest request) throws IOExcep if (isEmpty(id)) { if (request.getUserIdentities() != null) { - UserIdentity customerId = request.getUserIdentities().stream() - .filter(t -> t.getType().equals(UserIdentity.Type.CUSTOMER)) - .findFirst() - .orElse(null); + UserIdentity customerId = + request.getUserIdentities() + .stream() + .filter(t -> t.getType().equals(UserIdentity.Type.CUSTOMER)) + .findFirst() + .orElse(null); if (customerId != null) { id = customerId.getValue(); } @@ -421,12 +556,13 @@ static String getPlaceholderEmail(EventProcessingRequest request) throws IOExcep if (isEmpty(id)) { // This error should stop processing for the entire batch. - throw new IOException("Unable to send user to Iterable - no email and unable to construct placeholder."); + throw new IOException( + "Unable to send user to Iterable - no email and unable to construct placeholder."); } return id + PLACEHOLDER_EMAIL_DOMAIN; } - private static List convertToIntList(String csv){ + private static List convertToIntList(String csv) { if (csv == null) { return null; } else if (csv.isEmpty()) { @@ -449,25 +585,21 @@ private static List convertToIntList(String csv){ public static final String TEMPLATE_ID_KEY = "templateId"; /** + * This is expected to be called with an event that conforms to the following: Name: + * "updateSubscriptions" * - * This is expected to be called with an event that conforms to the following: - * Name: "updateSubscriptions" - * - * And has at least some of the following: - * - * Attribute: emailListIds - * Attribute: unsubscribedChannelIds - * Attribute: unsubscribedMessageTypeIds - * Attribute: campaignId - * Attribute: templateId + *

And has at least some of the following: * + *

Attribute: emailListIds Attribute: unsubscribedChannelIds Attribute: + * unsubscribedMessageTypeIds Attribute: campaignId Attribute: templateId */ private boolean processSubscribeEvent(CustomEvent event) throws IOException { UpdateSubscriptionsRequest updateRequest = generateSubscriptionRequest(event); if (updateRequest == null) { return false; } - Call preparedCall = iterableService.updateSubscriptions(getApiKey(event), updateRequest); + Call preparedCall = + iterableService.updateSubscriptions(getApiKey(event), updateRequest); Response response = makeIterableRequest(preparedCall, event.getId()); handleIterableResponse(response, event.getId()); return true; @@ -481,14 +613,16 @@ static UpdateSubscriptionsRequest generateSubscriptionRequest(CustomEvent event) Map eventAttributes = event.getAttributes(); updateRequest.emailListIds = convertToIntList(eventAttributes.get(EMAIL_LIST_ID_LIST_KEY)); - updateRequest.unsubscribedChannelIds = convertToIntList(eventAttributes.get(UNSUBSCRIBE_CHANNEL_ID_LIST_KEY)); - updateRequest.unsubscribedMessageTypeIds = convertToIntList(eventAttributes.get(UNSUBSCRIBE_MESSAGE_TYPE_ID_LIST_KEY)); + updateRequest.unsubscribedChannelIds = + convertToIntList(eventAttributes.get(UNSUBSCRIBE_CHANNEL_ID_LIST_KEY)); + updateRequest.unsubscribedMessageTypeIds = + convertToIntList(eventAttributes.get(UNSUBSCRIBE_MESSAGE_TYPE_ID_LIST_KEY)); String campaignId = eventAttributes.get(CAMPAIGN_ID_KEY); if (!isEmpty(campaignId)) { try { updateRequest.campaignId = Integer.parseInt(campaignId.trim()); - }catch (NumberFormatException ignored) { + } catch (NumberFormatException ignored) { } } @@ -497,7 +631,7 @@ static UpdateSubscriptionsRequest generateSubscriptionRequest(CustomEvent event) if (!isEmpty(templateId)) { try { updateRequest.templateId = Integer.parseInt(templateId.trim()); - }catch (NumberFormatException ignored) { + } catch (NumberFormatException ignored) { } } @@ -514,12 +648,14 @@ static UpdateSubscriptionsRequest generateSubscriptionRequest(CustomEvent event) } /** - * Map an mParticle `custom_event` to Iterable's `track` request. + * Map mParticle CustomEvent to Iterable TrackRequest. * - * mParticle custom_event: https://docs.mparticle.com/developers/server/json-reference/#custom_event - * Iterable track: https://api.iterable.com/api/docs#events_track + *

mParticle custom_event: + * https://docs.mparticle.com/developers/server/json-reference/#custom_event Iterable track: + * https://api.iterable.com/api/docs#events_track * * @param event the mParticle event + * @throws IOException */ @Override public void processCustomEvent(CustomEvent event) throws IOException { @@ -541,10 +677,12 @@ public void processCustomEvent(CustomEvent event) throws IOException { } /** - * Make a best-effort attempt to coerce the values of each map item to bool, double, int, and string types + * Make a best-effort attempt to coerce the values of each map item to bool, double, int, and + * string types * - * mParticle's API only accepts string, whereas Iterable's API accept different types. By coercing these types, - * users of the Iterable API are able to create campaigns, aggregate events, etc. + *

mParticle's API only accepts string, whereas Iterable's API accept different types. By + * coercing these types, users of the Iterable API are able to create campaigns, aggregate + * events, etc. * * @param attributes * @return @@ -554,37 +692,40 @@ private Map attemptTypeConversion(Map attributes return null; } Map converted = new HashMap<>(attributes.size()); - attributes.forEach((key,value)-> { - if (isEmpty(value)) { - converted.put(key, value); - } else { - if (value.toLowerCase(Locale.US).equals("true") || value.toLowerCase(Locale.US).equals("false")) { - converted.put(key, Boolean.parseBoolean(value)); - } else { - try { - double doubleValue = Double.parseDouble(value); - if ((doubleValue % 1) == 0) { - converted.put(key, Integer.parseInt(value)); + attributes.forEach( + (key, value) -> { + if (isEmpty(value)) { + converted.put(key, value); + } else { + if (value.toLowerCase(Locale.US).equals("true") + || value.toLowerCase(Locale.US).equals("false")) { + converted.put(key, Boolean.parseBoolean(value)); } else { - converted.put(key, doubleValue); + try { + double doubleValue = Double.parseDouble(value); + if ((doubleValue % 1) == 0) { + converted.put(key, Integer.parseInt(value)); + } else { + converted.put(key, doubleValue); + } + } catch (NumberFormatException nfe) { + converted.put(key, value); + } } - }catch (NumberFormatException nfe) { - converted.put(key, value); } - } - } - - }); + }); return converted; } /** - * Map mParticle `PushMessageReceiptEvent` to Iterable `trackPushOpen` request. + * Map mParticle PushMessageReceiptEvent to Iterable TrackPushOpenRequest. * - * mParticle push_message event https://docs.mparticle.com/developers/server/json-reference#push_message - * Iterable trackPushOpen request: https://api.iterable.com/api/docs#events_trackPushOpen + *

mParticle push_message event + * https://docs.mparticle.com/developers/server/json-reference#push_message Iterable + * trackPushOpen request: https://api.iterable.com/api/docs#events_trackPushOpen * * @param event the mParticle event + * @throws IOException */ @Override public void processPushMessageReceiptEvent(PushMessageReceiptEvent event) throws IOException { @@ -597,15 +738,18 @@ public void processPushMessageReceiptEvent(PushMessageReceiptEvent event) throws if (event.getPayload() != null && event.getRequest().getUserIdentities() != null) { addUserIdentitiesToRequest(request, event.getRequest()); if (request.email == null && request.userId == null) { - IterableExtensionLogger.logError("Unable to process PushMessageReceiptEvent - user has no email or customer id."); + IterableExtensionLogger.logError( + "Unable to process PushMessageReceiptEvent - user has no email or customer id."); return; } ObjectMapper mapper = new ObjectMapper(); Map payload = mapper.readValue(event.getPayload(), Map.class); if (payload.containsKey("itbl")) { - //Android and iOS have differently encoded payload formats. See the tests for examples. + // Android and iOS have differently encoded payload formats. See the tests for + // examples. Map iterableMap; - if (event.getRequest().getRuntimeEnvironment() instanceof AndroidRuntimeEnvironment) { + if (event.getRequest().getRuntimeEnvironment() + instanceof AndroidRuntimeEnvironment) { iterableMap = mapper.readValue((String) payload.get("itbl"), Map.class); } else { iterableMap = (Map) payload.get("itbl"); @@ -618,8 +762,10 @@ public void processPushMessageReceiptEvent(PushMessageReceiptEvent event) throws return; } request.createdAt = (int) (event.getTimestamp() / 1000.0); - Call preparedCall = iterableService.trackPushOpen(getApiKey(event), request); - Response response = makeIterableRequest(preparedCall, event.getId()); + Call preparedCall = + iterableService.trackPushOpen(getApiKey(event), request); + Response response = + makeIterableRequest(preparedCall, event.getId()); handleIterableResponse(response, event.getId()); } } @@ -634,20 +780,23 @@ public static Integer convertItblPayloadFieldToInt(Object itblField) { } /** - * Map an mParticle `AudienceMembershipChangeRequest` to Iterable list `subscribe` and `unsubscribe` requests. + * Map mParticle AudienceMembershipChangeRequest to Iterable SubscribeRequests and + * UnsubscribeRequests. * - * Each subscribe and unsubscribe request may contain multiple users if there are multiple + *

Each subscribe and unsubscribe request may contain multiple users if there are multiple * users being added or removed from the same list. No dataFields are sent with the users. * - * mParticle Audience Processing: https://docs.mparticle.com/developers/partners/firehose/#audience-processing - * Iterable subscribe: https://api.iterable.com/api/docs#lists_subscribe - * Iterable unsubscribe: https://api.iterable.com/api/docs#lists_unsubscribe + *

mParticle Audience Processing: + * https://docs.mparticle.com/developers/partners/firehose/#audience-processing Iterable + * subscribe: https://api.iterable.com/api/docs#lists_subscribe Iterable unsubscribe: + * https://api.iterable.com/api/docs#lists_unsubscribe * * @param request the mParticle request * @return a response that indicates the request was processed successfully */ @Override - public AudienceMembershipChangeResponse processAudienceMembershipChangeRequest(AudienceMembershipChangeRequest request) throws IOException { + public AudienceMembershipChangeResponse processAudienceMembershipChangeRequest( + AudienceMembershipChangeRequest request) throws IOException { HashMap> additions = new HashMap<>(); HashMap> removals = new HashMap<>(); for (UserProfile profile : request.getUserProfiles()) { @@ -655,14 +804,25 @@ public AudienceMembershipChangeResponse processAudienceMembershipChangeRequest(A addUserIdentitiesToRequest(userRequest, profile, request.getAccount()); if (userRequest.email != null) { if (profile.getAudiences() != null) { - List addedAudiences = profile.getAudiences().stream() - .filter(audience -> audience.getAudienceAction() == Audience.AudienceAction.ADD) - .collect(Collectors.toList()); - List removedAudiences = profile.getAudiences().stream() - .filter(audience -> audience.getAudienceAction() == Audience.AudienceAction.DELETE) - .collect(Collectors.toList()); + List addedAudiences = + profile.getAudiences() + .stream() + .filter( + audience -> + audience.getAudienceAction() + == Audience.AudienceAction.ADD) + .collect(Collectors.toList()); + List removedAudiences = + profile.getAudiences() + .stream() + .filter( + audience -> + audience.getAudienceAction() + == Audience.AudienceAction.DELETE) + .collect(Collectors.toList()); for (Audience audience : addedAudiences) { - Map audienceSettings = audience.getAudienceSubscriptionSettings(); + Map audienceSettings = + audience.getAudienceSubscriptionSettings(); int listId = Integer.parseInt(audienceSettings.get(SETTING_LIST_ID)); ApiUser user = new ApiUser(); user.email = userRequest.email; @@ -673,7 +833,8 @@ public AudienceMembershipChangeResponse processAudienceMembershipChangeRequest(A additions.get(listId).add(user); } for (Audience audience : removedAudiences) { - Map audienceSettings = audience.getAudienceSubscriptionSettings(); + Map audienceSettings = + audience.getAudienceSubscriptionSettings(); int listId = Integer.parseInt(audienceSettings.get(SETTING_LIST_ID)); ApiUser user = new ApiUser(); user.email = userRequest.email; @@ -691,7 +852,8 @@ public AudienceMembershipChangeResponse processAudienceMembershipChangeRequest(A SubscribeRequest subscribeRequest = new SubscribeRequest(); subscribeRequest.listId = entry.getKey(); subscribeRequest.subscribers = entry.getValue(); - Call preparedCall = iterableService.listSubscribe(getApiKey(request), subscribeRequest); + Call preparedCall = + iterableService.listSubscribe(getApiKey(request), subscribeRequest); Response response = makeIterableRequest(preparedCall, request.getId()); handleIterableListResponse(response, request.getId()); } @@ -700,27 +862,37 @@ public AudienceMembershipChangeResponse processAudienceMembershipChangeRequest(A UnsubscribeRequest unsubscribeRequest = new UnsubscribeRequest(); unsubscribeRequest.listId = entry.getKey(); unsubscribeRequest.subscribers = entry.getValue(); - Call preparedCall = iterableService.listUnsubscribe(getApiKey(request), unsubscribeRequest); + Call preparedCall = + iterableService.listUnsubscribe(getApiKey(request), unsubscribeRequest); Response response = makeIterableRequest(preparedCall, request.getId()); handleIterableListResponse(response, request.getId()); - } + } return new AudienceMembershipChangeResponse(); } - private void addUserIdentitiesToRequest(UserRequest request, EventProcessingRequest processingRequest) { - addUserIdentitiesToRequest(request, processingRequest.getUserIdentities(), processingRequest.getAccount(), processingRequest.getMpId()); + private void addUserIdentitiesToRequest( + UserRequest request, EventProcessingRequest processingRequest) { + addUserIdentitiesToRequest( + request, + processingRequest.getUserIdentities(), + processingRequest.getAccount(), + processingRequest.getMpId()); } - private void addUserIdentitiesToRequest(UserRequest request, UserProfile userProfile, Account account) { - addUserIdentitiesToRequest(request, userProfile.getUserIdentities(), account, userProfile.getMpId()); + private void addUserIdentitiesToRequest( + UserRequest request, UserProfile userProfile, Account account) { + addUserIdentitiesToRequest( + request, userProfile.getUserIdentities(), account, userProfile.getMpId()); } - private void addUserIdentitiesToRequest(UserRequest request, List identities, Account account, String mpid) { + private void addUserIdentitiesToRequest( + UserRequest request, List identities, Account account, String mpid) { if (identities != null) { for (UserIdentity identity : identities) { if (identity.getType().equals(UserIdentity.Type.EMAIL)) { request.email = identity.getValue(); - } else if (identity.getType().equals(UserIdentity.Type.CUSTOMER) && !shouldUseMPID(account)) { + } else if (identity.getType().equals(UserIdentity.Type.CUSTOMER) + && !shouldUseMPID(account)) { request.userId = identity.getValue(); } } @@ -735,11 +907,12 @@ private void addUserIdentitiesToRequest(UserRequest request, List private boolean hasBundledSDK(EventProcessingRequest processingRequest) { Map integrationAttributes = processingRequest.getIntegrationAttributes(); - return integrationAttributes != null && - integrationAttributes.getOrDefault("Iterable.sdkVersion", null) != null; + return integrationAttributes != null + && integrationAttributes.getOrDefault("Iterable.sdkVersion", null) != null; } - static void handleIterableResponse(Response response, UUID eventId) throws RetriableError { + static void handleIterableResponse(Response response, UUID eventId) + throws RetriableError { boolean isResponseBodySuccess = response.body() != null && response.body().isSuccess(); if (!response.isSuccessful() || !isResponseBodySuccess) { IterableExtensionLogger.logApiError(response, eventId); @@ -749,7 +922,8 @@ static void handleIterableResponse(Response response, UUID } } - static void handleIterableListResponse(Response response, UUID audienceRequestId) throws RetriableError { + static void handleIterableListResponse(Response response, UUID audienceRequestId) + throws RetriableError { if (!response.isSuccessful()) { IterableExtensionLogger.logApiError(response, audienceRequestId); if (RETRIABLE_HTTP_STATUS_SET.contains(response.code())) { @@ -759,7 +933,8 @@ static void handleIterableListResponse(Response response, UUID aud boolean hasFailures = response.body().failCount > 0; if (hasFailures) { IterableExtensionLogger.logError( - "List subscribe or unsubscribe request failed count: " + response.body().failCount); + "List subscribe or unsubscribe request failed count: " + + response.body().failCount); } } @@ -771,4 +946,4 @@ static Response makeIterableRequest(Call call, UUID requestId) throws throw new RetriableError(); } } -} \ No newline at end of file +} diff --git a/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableExtensionLogger.java b/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableExtensionLogger.java index 2d510db..f85f2f4 100644 --- a/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableExtensionLogger.java +++ b/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableExtensionLogger.java @@ -4,58 +4,57 @@ import com.google.gson.GsonBuilder; import com.mparticle.iterable.IterableApiResponse; import com.mparticle.iterable.IterableErrorHandler; -import retrofit2.Response; - import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import retrofit2.Response; /** - * A utility class for logging state while processing mParticle batches. All - * static methods write a JSON object to Standard Output where it can be queried - * in Cloudwatch. + * A utility class for logging state while processing mParticle batches. All static methods write a + * JSON object to Standard Output where it can be queried in Cloudwatch. */ public class IterableExtensionLogger { - private static final Gson gson = new GsonBuilder().create(); + private static final Gson gson = new GsonBuilder().create(); - static void logApiError(Response response, UUID id) { - String iterableApiCode = null; - try { - IterableApiResponse errorBody = IterableErrorHandler.parseError(response); - iterableApiCode = errorBody.code; - } catch (IOException e) { - iterableApiCode = "Unable to parse Iterable API code"; + static void logApiError(Response response, UUID id) { + String iterableApiCode = null; + try { + IterableApiResponse errorBody = IterableErrorHandler.parseError(response); + iterableApiCode = errorBody.code; + } catch (IOException e) { + iterableApiCode = "Unable to parse Iterable API code"; + } + String requestId = id != null ? id.toString() : "Unavailable"; + String url = response.raw().request().url().encodedPath(); + String httpStatus = String.valueOf(response.code()); + Map logMessage = new HashMap<>(); + logMessage.put("message", "Error sending request to Iterable"); + logMessage.put("url", url); + logMessage.put("httpStatus", httpStatus); + logMessage.put("iterableApiCode", iterableApiCode); + logMessage.put("mParticleEventId", requestId); + String messageJson = gson.toJson(logMessage); + System.out.println(messageJson); } - String requestId = id != null ? id.toString() : "Unavailable"; - String url = response.raw().request().url().encodedPath(); - String httpStatus = String.valueOf(response.code()); - Map logMessage = new HashMap<>(); - logMessage.put("message", "Error sending request to Iterable"); - logMessage.put("url", url); - logMessage.put("httpStatus", httpStatus); - logMessage.put("iterableApiCode", iterableApiCode); - logMessage.put("mParticleEventId", requestId); - String messageJson = gson.toJson(logMessage); - System.out.println(messageJson); - } - static void logApiTimeout(String url, UUID mparticleEventId) { - String eventIdString = mparticleEventId != null ? mparticleEventId.toString() : "Unavailable"; - Map logMessage = new HashMap<>(); - logMessage.put("errorType", "Retriable"); - logMessage.put("message", "A timeout occurred while making request to Iterable"); - logMessage.put("url", url); - logMessage.put("mparticleEventId", eventIdString); - String messageJson = gson.toJson(logMessage); - System.out.println(messageJson); - } + static void logApiTimeout(String url, UUID mparticleEventId) { + String eventIdString = + mparticleEventId != null ? mparticleEventId.toString() : "Unavailable"; + Map logMessage = new HashMap<>(); + logMessage.put("errorType", "Retriable"); + logMessage.put("message", "A timeout occurred while making request to Iterable"); + logMessage.put("url", url); + logMessage.put("mparticleEventId", eventIdString); + String messageJson = gson.toJson(logMessage); + System.out.println(messageJson); + } - public static void logError(String message) { - Map logMessage = new HashMap<>(); - logMessage.put("message", message); - String messageJson = gson.toJson(logMessage); - System.out.println(messageJson); - } + public static void logError(String message) { + Map logMessage = new HashMap<>(); + logMessage.put("message", message); + String messageJson = gson.toJson(logMessage); + System.out.println(messageJson); + } } diff --git a/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableLambdaEndpoint.java b/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableLambdaEndpoint.java index 95c7a5c..6deb4d0 100644 --- a/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableLambdaEndpoint.java +++ b/iterable-extension/src/main/java/com/mparticle/ext/iterable/IterableLambdaEndpoint.java @@ -5,39 +5,38 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.mparticle.sdk.model.Message; import com.mparticle.sdk.model.MessageSerializer; -import org.apache.commons.io.IOUtils; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import org.apache.commons.io.IOUtils; public class IterableLambdaEndpoint implements RequestStreamHandler { - static MessageSerializer serializer = new MessageSerializer(); - static IterableExtension processor = new IterableExtension(); - static final ObjectMapper mapper = new ObjectMapper(); + static MessageSerializer serializer = new MessageSerializer(); + static IterableExtension processor = new IterableExtension(); + static final ObjectMapper mapper = new ObjectMapper(); - @Override - public void handleRequest(InputStream input, OutputStream output, Context context) - throws RetriableError { - try { - String inputString = IOUtils.toString(input, "UTF-8"); - Message request = parseQueueTrigger(inputString); - Message response = processor.processMessage(request); - serializer.serialize(output, response); - } catch (RetriableError e) { - IterableExtensionLogger.logError("Processing terminated by a RetriableError"); - throw e; - } catch (Exception e) { - IterableExtensionLogger.logError("Processing terminated by An unexpected error"); - e.printStackTrace(System.out); + @Override + public void handleRequest(InputStream input, OutputStream output, Context context) + throws RetriableError { + try { + String inputString = IOUtils.toString(input, "UTF-8"); + Message request = parseQueueTrigger(inputString); + Message response = processor.processMessage(request); + serializer.serialize(output, response); + } catch (RetriableError e) { + IterableExtensionLogger.logError("Processing terminated by a RetriableError"); + throw e; + } catch (Exception e) { + IterableExtensionLogger.logError("Processing terminated by An unexpected error"); + e.printStackTrace(System.out); + } } - } - public static Message parseQueueTrigger(String triggerString) throws IOException { - QueueTrigger trigger = mapper.readValue(triggerString, QueueTrigger.class); - String messageBody = trigger.records.get(0).body; - Message request = serializer.deserialize(messageBody, Message.class); - return request; - } + public static Message parseQueueTrigger(String triggerString) throws IOException { + QueueTrigger trigger = mapper.readValue(triggerString, QueueTrigger.class); + String messageBody = trigger.records.get(0).body; + Message request = serializer.deserialize(messageBody, Message.class); + return request; + } } diff --git a/iterable-extension/src/main/java/com/mparticle/ext/iterable/QueueMessageBody.java b/iterable-extension/src/main/java/com/mparticle/ext/iterable/QueueMessageBody.java index 7bee484..4e8f9d2 100644 --- a/iterable-extension/src/main/java/com/mparticle/ext/iterable/QueueMessageBody.java +++ b/iterable-extension/src/main/java/com/mparticle/ext/iterable/QueueMessageBody.java @@ -5,6 +5,6 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class QueueMessageBody { - @JsonProperty(value = "body", required = true) - public String body; + @JsonProperty(value = "body", required = true) + public String body; } diff --git a/iterable-extension/src/main/java/com/mparticle/ext/iterable/QueueTrigger.java b/iterable-extension/src/main/java/com/mparticle/ext/iterable/QueueTrigger.java index 26c06a0..0a0b8e5 100644 --- a/iterable-extension/src/main/java/com/mparticle/ext/iterable/QueueTrigger.java +++ b/iterable-extension/src/main/java/com/mparticle/ext/iterable/QueueTrigger.java @@ -2,11 +2,10 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; @JsonIgnoreProperties(ignoreUnknown = true) public class QueueTrigger { - @JsonProperty(value = "Records", required = true) - public List records; + @JsonProperty(value = "Records", required = true) + public List records; } diff --git a/iterable-extension/src/main/java/com/mparticle/ext/iterable/RetriableError.java b/iterable-extension/src/main/java/com/mparticle/ext/iterable/RetriableError.java index 04a1d28..62f14fc 100644 --- a/iterable-extension/src/main/java/com/mparticle/ext/iterable/RetriableError.java +++ b/iterable-extension/src/main/java/com/mparticle/ext/iterable/RetriableError.java @@ -2,16 +2,14 @@ import java.io.IOException; -/** - * Exception thrown when batch processing fails and should be retried. - */ +/** Exception thrown when batch processing fails and should be retried. */ public class RetriableError extends IOException { - public RetriableError() { - super(); - } + public RetriableError() { + super(); + } - public RetriableError(String message) { - super(message); - } + public RetriableError(String message) { + super(message); + } } diff --git a/iterable-extension/src/test/java/com/mparticle/ext/iterable/IterableExtensionTest.java b/iterable-extension/src/test/java/com/mparticle/ext/iterable/IterableExtensionTest.java index 0de8fcd..74690c6 100644 --- a/iterable-extension/src/test/java/com/mparticle/ext/iterable/IterableExtensionTest.java +++ b/iterable-extension/src/test/java/com/mparticle/ext/iterable/IterableExtensionTest.java @@ -1,32 +1,30 @@ package com.mparticle.ext.iterable; +import static com.mparticle.ext.iterable.IterableExtension.*; +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; + import com.mparticle.iterable.*; import com.mparticle.sdk.model.audienceprocessing.Audience; import com.mparticle.sdk.model.audienceprocessing.AudienceMembershipChangeRequest; import com.mparticle.sdk.model.audienceprocessing.UserProfile; import com.mparticle.sdk.model.eventprocessing.*; import com.mparticle.sdk.model.registration.Account; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.math.BigDecimal; +import java.util.*; import okhttp3.*; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.mockito.Mockito; import retrofit2.Call; import retrofit2.Response; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.math.BigDecimal; -import java.util.*; - -import static com.mparticle.ext.iterable.IterableExtension.*; -import static org.junit.Assert.*; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; - public class IterableExtensionTest { private static final String TEST_API_KEY = "foo api key"; private IterableExtension testIterableExtension; @@ -75,16 +73,21 @@ public void setup() { testUserProfile = new UserProfile(); testUserProfileWithEmail = new UserProfile(); userIdentitiesWithEmail = new LinkedList<>(); - userIdentitiesWithEmail.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, - "email_only@iterable.com")); + userIdentitiesWithEmail.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "email_only@iterable.com")); testUserProfileWithEmail.setUserIdentities(userIdentitiesWithEmail); testUserProfileWithEmailAndCustomerId = new UserProfile(); userIdentitiesWithEmailAndCustomerId = new LinkedList<>(); - userIdentitiesWithEmailAndCustomerId.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, - "email_and_id@iterable.com")); - userIdentitiesWithEmailAndCustomerId.add(new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, - "c1")); - testUserProfileWithEmailAndCustomerId.setUserIdentities(userIdentitiesWithEmailAndCustomerId); + userIdentitiesWithEmailAndCustomerId.add( + new UserIdentity( + UserIdentity.Type.EMAIL, + Identity.Encoding.RAW, + "email_and_id@iterable.com")); + userIdentitiesWithEmailAndCustomerId.add( + new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "c1")); + testUserProfileWithEmailAndCustomerId.setUserIdentities( + userIdentitiesWithEmailAndCustomerId); testAccount = new Account(); Map accountSettings = new HashMap<>(); @@ -94,8 +97,12 @@ public void setup() { testIterableApiSuccess = new IterableApiResponse(); testIterableApiSuccess.code = IterableApiResponse.SUCCESS_MESSAGE; testSuccessResponse = Response.success(testIterableApiSuccess); - testErrorResponse = Response.error(400, ResponseBody.create( - MediaType.parse("application/json; charset=utf-8"), "{code:\"InvalidEmailAddressError\"}")); + testErrorResponse = + Response.error( + 400, + ResponseBody.create( + MediaType.parse("application/json; charset=utf-8"), + "{code:\"InvalidEmailAddressError\"}")); } @Test @@ -112,7 +119,7 @@ public void testProcessEventProcessingRequest() { Event customEvent4 = new UserAttributeChangeEvent(); customEvent4.setTimestamp(4); request.setDeviceApplicationStamp("foo"); - //out of order + // out of order events.add(customEvent1); events.add(customEvent2); events.add(customEvent3); @@ -126,10 +133,14 @@ public void testProcessEventProcessingRequest() { } assertNotNull("IterableService should have been created", extension.iterableService); - assertEquals("Events should have been in order",1, request.getEvents().get(0).getTimestamp()); - assertEquals("Events should have been in order",2, request.getEvents().get(1).getTimestamp()); - assertEquals("Events should have been in order",3, request.getEvents().get(2).getTimestamp()); - assertEquals("Events should have been in order",4, request.getEvents().get(3).getTimestamp()); + assertEquals( + "Events should have been in order", 1, request.getEvents().get(0).getTimestamp()); + assertEquals( + "Events should have been in order", 2, request.getEvents().get(1).getTimestamp()); + assertEquals( + "Events should have been in order", 3, request.getEvents().get(2).getTimestamp()); + assertEquals( + "Events should have been in order", 4, request.getEvents().get(3).getTimestamp()); } @Test @@ -144,21 +155,27 @@ public void testUpdateUser() throws Exception { Response response = Response.success(apiResponse); Mockito.when(callMock.execute()).thenReturn(response); EventProcessingRequest request = createEventProcessingRequest(); - //no user identities, no API call + // no user identities, no API call extension.updateUser(request); UserUpdateRequest userUpdateRequest = new UserUpdateRequest(); - Mockito.verify(extension.iterableService, never()).userUpdate(TEST_API_KEY, userUpdateRequest); + Mockito.verify(extension.iterableService, never()) + .userUpdate(TEST_API_KEY, userUpdateRequest); - //user identities but no email/userid, no API call + // user identities but no email/userid, no API call List identities = new LinkedList<>(); - identities.add(new UserIdentity(UserIdentity.Type.FACEBOOK, Identity.Encoding.RAW, "123456")); + identities.add( + new UserIdentity(UserIdentity.Type.FACEBOOK, Identity.Encoding.RAW, "123456")); request.setUserIdentities(identities); extension.updateUser(request); - Mockito.verify(extension.iterableService, never()).userUpdate(TEST_API_KEY, userUpdateRequest); - - //ok, now we should get a single API call - identities.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); - identities.add(new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); + Mockito.verify(extension.iterableService, never()) + .userUpdate(TEST_API_KEY, userUpdateRequest); + + // ok, now we should get a single API call + identities.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); + identities.add( + new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); Map userAttributes = new HashMap(); userAttributes.put("some attribute key", "some attribute value"); request.setUserAttributes(userAttributes); @@ -166,13 +183,15 @@ public void testUpdateUser() throws Exception { extension.updateUser(request); - ArgumentCaptor argument = ArgumentCaptor.forClass(UserUpdateRequest.class); + ArgumentCaptor argument = + ArgumentCaptor.forClass(UserUpdateRequest.class); ArgumentCaptor apiArg = ArgumentCaptor.forClass(String.class); Mockito.verify(extension.iterableService).userUpdate(apiArg.capture(), argument.capture()); assertEquals(TEST_API_KEY, apiArg.getValue()); assertEquals("mptest@mparticle.com", argument.getValue().email); assertEquals("123456", argument.getValue().userId); - assertEquals(argument.getValue().dataFields.get("some attribute key"), "some attribute value"); + assertEquals( + argument.getValue().dataFields.get("some attribute key"), "some attribute value"); } @Test @@ -194,11 +213,16 @@ public void testReservedAttributeConversion() throws IOException { Mockito.verify(testIterableExtension.iterableService, times(1)) .userUpdate(any(), args.capture()); - assertEquals("Reserved phone number attribute should be converted with non-digit characters removed", - "+15558765309", args.getValue().dataFields.get("phoneNumber")); - assertEquals("Non-reserved attributes should be unchanged", - "some attribute value", args.getValue().dataFields.get("some attribute key")); - assertNull("mParticle reserved attribute shouldn't be present", + assertEquals( + "Reserved phone number attribute should be converted with non-digit characters removed", + "+15558765309", + args.getValue().dataFields.get("phoneNumber")); + assertEquals( + "Non-reserved attributes should be unchanged", + "some attribute value", + args.getValue().dataFields.get("some attribute key")); + assertNull( + "mParticle reserved attribute shouldn't be present", args.getValue().dataFields.get(MPARTICLE_RESERVED_PHONE_ATTR)); } @@ -217,11 +241,13 @@ public void testUserAttributeTypeConversion() throws Exception { Mockito.when(callMock.execute()).thenReturn(response); EventProcessingRequest request = createEventProcessingRequest(); - + List identities = new LinkedList<>(); - identities.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); + identities.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); request.setUserIdentities(identities); - + Map userAttributes = new HashMap<>(); userAttributes.put("test_bool", "True"); userAttributes.put("test_int", "123"); @@ -237,9 +263,11 @@ public void testUserAttributeTypeConversion() throws Exception { request.getAccount().getAccountSettings().remove(SETTING_COERCE_STRINGS_TO_SCALARS); extension.updateUser(request); - ArgumentCaptor argument = ArgumentCaptor.forClass(UserUpdateRequest.class); + ArgumentCaptor argument = + ArgumentCaptor.forClass(UserUpdateRequest.class); ArgumentCaptor apiArg = ArgumentCaptor.forClass(String.class); - Mockito.verify(extension.iterableService, times(3)).userUpdate(apiArg.capture(), argument.capture()); + Mockito.verify(extension.iterableService, times(3)) + .userUpdate(apiArg.capture(), argument.capture()); List actualRequests = argument.getAllValues(); @@ -261,7 +289,8 @@ public void testUserAttributeTypeConversion() throws Exception { @Test public void testProcessUserAttributeChangeEvent() throws Exception { - //just verify that we're not processing anything - it's all done in processEventProcessingRequest + // just verify that we're not processing anything - it's all done in + // processEventProcessingRequest IterableExtension extension = new IterableExtension(); extension.iterableService = Mockito.mock(IterableService.class); extension.processUserAttributeChangeEvent(new UserAttributeChangeEvent()); @@ -282,8 +311,11 @@ public void testProcessCustomEvent() throws Exception { event.setName("My Event Name"); EventProcessingRequest request = createEventProcessingRequest(); List userIdentities = new LinkedList<>(); - userIdentities.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); - userIdentities.add(new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); + userIdentities.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); + userIdentities.add( + new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); request.setUserIdentities(userIdentities); event.setRequest(request); Map attributes = new HashMap<>(); @@ -297,7 +329,8 @@ public void testProcessCustomEvent() throws Exception { assertEquals("My Event Name", argument.getValue().getEventName()); assertEquals("mptest@mparticle.com", argument.getValue().email); assertEquals("123456", argument.getValue().userId); - assertEquals("some attribute value", argument.getValue().dataFields.get("some attribute key")); + assertEquals( + "some attribute value", argument.getValue().dataFields.get("some attribute key")); assertEquals((int) (timeStamp / 1000.0), argument.getValue().createdAt + 0); assertEquals(event.getId().toString(), argument.getValue().id); } @@ -324,19 +357,24 @@ public void testProcessAndroidPushMessageReceiptEvent() throws Exception { Mockito.verifyZeroInteractions(extension.iterableService); List userIdentities = new LinkedList<>(); - userIdentities.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); - userIdentities.add(new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); + userIdentities.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); + userIdentities.add( + new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); eventProcessingRequest.setUserIdentities(userIdentities); eventProcessingRequest.setRuntimeEnvironment(new AndroidRuntimeEnvironment()); event.setRequest(eventProcessingRequest); - event.setPayload("{\"google.sent_time\":1507657706679,\"body\":\"example\",\"from\":\"674988899928\",\"itbl\":\"{\\\"campaignId\\\":12345,\\\"isGhostPush\\\":false,\\\"messageId\\\":\\\"1dce4e505b11111ca1111d6fdd774fbd\\\",\\\"templateId\\\":54321}\",\"google.message_id\":\"0:1507657706689231%62399b94f9fd7ecd\"}"); + event.setPayload( + "{\"google.sent_time\":1507657706679,\"body\":\"example\",\"from\":\"674988899928\",\"itbl\":\"{\\\"campaignId\\\":12345,\\\"isGhostPush\\\":false,\\\"messageId\\\":\\\"1dce4e505b11111ca1111d6fdd774fbd\\\",\\\"templateId\\\":54321}\",\"google.message_id\":\"0:1507657706689231%62399b94f9fd7ecd\"}"); long timeStamp = System.currentTimeMillis(); event.setTimestamp(timeStamp); extension.processPushMessageReceiptEvent(event); - ArgumentCaptor argument = ArgumentCaptor.forClass(TrackPushOpenRequest.class); + ArgumentCaptor argument = + ArgumentCaptor.forClass(TrackPushOpenRequest.class); Mockito.verify(extension.iterableService).trackPushOpen(Mockito.any(), argument.capture()); assertEquals("mptest@mparticle.com", argument.getValue().email); assertEquals("123456", argument.getValue().userId); @@ -345,9 +383,7 @@ public void testProcessAndroidPushMessageReceiptEvent() throws Exception { assertEquals("1dce4e505b11111ca1111d6fdd774fbd", argument.getValue().messageId); } - /** - * Verify that Android push message receipt event is not handled when campaignId is missing - */ + /** Verify that Android push message receipt event is not handled when campaignId is missing */ @Test public void testProcessAndroidPushMessageReceiptWithoutCampaignId() throws IOException { testIterableExtension.iterableService = iterableServiceMock; @@ -356,9 +392,10 @@ public void testProcessAndroidPushMessageReceiptWithoutCampaignId() throws IOExc eventProcessingRequest.setRuntimeEnvironment(new AndroidRuntimeEnvironment()); PushMessageReceiptEvent event = new PushMessageReceiptEvent(); event.setRequest(eventProcessingRequest); - event.setPayload("{\"google.sent_time\":1507657706679,\"body\":\"example\",\"from\":\"674988899928\",\"itbl\":\"{\\\"isGhostPush\\\":false,\\\"messageId\\\":\\\"1dce4e505b11111ca1111d6fdd774fbd\\\",\\\"templateId\\\":54321}\",\"google.message_id\":\"0:1507657706689231%62399b94f9fd7ecd\"}"); + event.setPayload( + "{\"google.sent_time\":1507657706679,\"body\":\"example\",\"from\":\"674988899928\",\"itbl\":\"{\\\"isGhostPush\\\":false,\\\"messageId\\\":\\\"1dce4e505b11111ca1111d6fdd774fbd\\\",\\\"templateId\\\":54321}\",\"google.message_id\":\"0:1507657706689231%62399b94f9fd7ecd\"}"); event.setTimestamp(System.currentTimeMillis()); - + testIterableExtension.processPushMessageReceiptEvent(event); Mockito.verify(iterableServiceMock, never()).trackPushOpen(Mockito.any(), Mockito.any()); } @@ -385,22 +422,26 @@ public void testProcessiOSPushMessageReceiptEvent() throws Exception { extension.processPushMessageReceiptEvent(event); Mockito.verifyZeroInteractions(extension.iterableService); - List userIdentities = new LinkedList<>(); - userIdentities.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); - userIdentities.add(new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); + userIdentities.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); + userIdentities.add( + new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); eventProcessingRequest.setUserIdentities(userIdentities); eventProcessingRequest.setRuntimeEnvironment(new IosRuntimeEnvironment()); event.setRequest(eventProcessingRequest); - event.setPayload("{\"aps\":{\"content-available\":1 }, \"data\":{\"route\":\"example\", \"tag\":\"example\", \"body\":\"example\"}, \"route\":\"example\", \"type\":\"marketing\", \"itbl\":{\"campaignId\":12345, \"messageId\":\"1dce4e505b11111ca1111d6fdd774fbd\", \"templateId\":54321, \"isGhostPush\":false } }"); + event.setPayload( + "{\"aps\":{\"content-available\":1 }, \"data\":{\"route\":\"example\", \"tag\":\"example\", \"body\":\"example\"}, \"route\":\"example\", \"type\":\"marketing\", \"itbl\":{\"campaignId\":12345, \"messageId\":\"1dce4e505b11111ca1111d6fdd774fbd\", \"templateId\":54321, \"isGhostPush\":false } }"); long timeStamp = System.currentTimeMillis(); event.setTimestamp(timeStamp); extension.processPushMessageReceiptEvent(event); - ArgumentCaptor argument = ArgumentCaptor.forClass(TrackPushOpenRequest.class); + ArgumentCaptor argument = + ArgumentCaptor.forClass(TrackPushOpenRequest.class); Mockito.verify(extension.iterableService).trackPushOpen(Mockito.any(), argument.capture()); assertEquals("mptest@mparticle.com", argument.getValue().email); assertEquals("123456", argument.getValue().userId); @@ -409,9 +450,7 @@ public void testProcessiOSPushMessageReceiptEvent() throws Exception { assertEquals("1dce4e505b11111ca1111d6fdd774fbd", argument.getValue().messageId); } - /** - * Verify that iOS push message receipt event is not handled when campaignId is missing - */ + /** Verify that iOS push message receipt event is not handled when campaignId is missing */ @Test public void testProcessiOSPushMessageReceiptWithoutCampaignId() throws IOException { testIterableExtension.iterableService = iterableServiceMock; @@ -420,16 +459,15 @@ public void testProcessiOSPushMessageReceiptWithoutCampaignId() throws IOExcepti eventProcessingRequest.setRuntimeEnvironment(new IosRuntimeEnvironment()); PushMessageReceiptEvent event = new PushMessageReceiptEvent(); event.setRequest(eventProcessingRequest); - event.setPayload("{\"aps\":{\"content-available\":1 }, \"data\":{\"route\":\"example\", \"tag\":\"example\", \"body\":\"example\"}, \"route\":\"example\", \"type\":\"marketing\", \"itbl\":{\"messageId\":\"1dce4e505b11111ca1111d6fdd774fbd\", \"templateId\":54321, \"isGhostPush\":false } }"); + event.setPayload( + "{\"aps\":{\"content-available\":1 }, \"data\":{\"route\":\"example\", \"tag\":\"example\", \"body\":\"example\"}, \"route\":\"example\", \"type\":\"marketing\", \"itbl\":{\"messageId\":\"1dce4e505b11111ca1111d6fdd774fbd\", \"templateId\":54321, \"isGhostPush\":false } }"); event.setTimestamp(System.currentTimeMillis()); testIterableExtension.processPushMessageReceiptEvent(event); Mockito.verify(iterableServiceMock, never()).trackPushOpen(Mockito.any(), Mockito.any()); } - /** - * Verify that push message receipt event is not handled when Iterable SDK is installed - */ + /** Verify that push message receipt event is not handled when Iterable SDK is installed */ @Test public void testProcessPushMessageReceiptEventWithSDK() throws Exception { IterableExtension extension = new IterableExtension(); @@ -440,29 +478,34 @@ public void testProcessPushMessageReceiptEventWithSDK() throws Exception { integrationAttributes.put("Iterable.sdkVersion", "3.2.1"); eventProcessingRequest.setIntegrationAttributes(integrationAttributes); List userIdentities = new LinkedList<>(); - userIdentities.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); - userIdentities.add(new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); + userIdentities.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); + userIdentities.add( + new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); eventProcessingRequest.setUserIdentities(userIdentities); eventProcessingRequest.setRuntimeEnvironment(new AndroidRuntimeEnvironment()); PushMessageReceiptEvent event = new PushMessageReceiptEvent(); event.setRequest(eventProcessingRequest); - event.setPayload("{\"google.sent_time\":1507657706679,\"body\":\"example\",\"from\":\"674988899928\",\"itbl\":\"{\\\"campaignId\\\":12345,\\\"isGhostPush\\\":false,\\\"messageId\\\":\\\"1dce4e505b11111ca1111d6fdd774fbd\\\",\\\"templateId\\\":54321}\",\"google.message_id\":\"0:1507657706689231%62399b94f9fd7ecd\"}"); + event.setPayload( + "{\"google.sent_time\":1507657706679,\"body\":\"example\",\"from\":\"674988899928\",\"itbl\":\"{\\\"campaignId\\\":12345,\\\"isGhostPush\\\":false,\\\"messageId\\\":\\\"1dce4e505b11111ca1111d6fdd774fbd\\\",\\\"templateId\\\":54321}\",\"google.message_id\":\"0:1507657706689231%62399b94f9fd7ecd\"}"); long timeStamp = System.currentTimeMillis(); event.setTimestamp(timeStamp); extension.processPushMessageReceiptEvent(event); - Mockito.verify(extension.iterableService, never()).trackPushOpen(Mockito.any(), Mockito.any()); + Mockito.verify(extension.iterableService, never()) + .trackPushOpen(Mockito.any(), Mockito.any()); } /** * This test creates 3 audiences and 2 users. - *

- * User 1: Two audiences added, 1 removed - * User 2: 1 audience removed, 2 added - *

- * It then verifies that subscribe/unsubcribe are called the correct amount and with the right list ids + * + *

User 1: Two audiences added, 1 removed User 2: 1 audience removed, 2 added + * + *

It then verifies that subscribe/unsubcribe are called the correct amount and with the + * right list ids */ @Test public void testProcessAudienceMembershipChangeRequest() throws Exception { @@ -470,10 +513,8 @@ public void testProcessAudienceMembershipChangeRequest() throws Exception { IterableService service = Mockito.mock(IterableService.class); extension.iterableService = service; Call callMock = Mockito.mock(Call.class); - Mockito.when(service.listSubscribe(Mockito.any(), Mockito.any())) - .thenReturn(callMock); - Mockito.when(service.listUnsubscribe(Mockito.any(), Mockito.any())) - .thenReturn(callMock); + Mockito.when(service.listSubscribe(Mockito.any(), Mockito.any())).thenReturn(callMock); + Mockito.when(service.listUnsubscribe(Mockito.any(), Mockito.any())).thenReturn(callMock); ListResponse apiResponse = new ListResponse(); Response response = Response.success(apiResponse); Mockito.when(callMock.execute()).thenReturn(response); @@ -528,16 +569,22 @@ public void testProcessAudienceMembershipChangeRequest() throws Exception { UserProfile profile1 = new UserProfile(); profile1.setAudiences(list1); List userIdentities1 = new LinkedList<>(); - userIdentities1.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); - userIdentities1.add(new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); + userIdentities1.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); + userIdentities1.add( + new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); profile1.setUserIdentities(userIdentities1); profiles.add(profile1); UserProfile profile2 = new UserProfile(); profile2.setAudiences(list2); List userIdentities2 = new LinkedList<>(); - userIdentities2.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest-2@mparticle.com")); - userIdentities2.add(new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "1234567")); + userIdentities2.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest-2@mparticle.com")); + userIdentities2.add( + new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "1234567")); profile2.setUserIdentities(userIdentities2); profiles.add(profile2); @@ -553,7 +600,8 @@ public void testProcessAudienceMembershipChangeRequest() throws Exception { ArgumentCaptor argument = ArgumentCaptor.forClass(SubscribeRequest.class); ArgumentCaptor apiArgument = ArgumentCaptor.forClass(String.class); - Mockito.verify(service, Mockito.times(3)).listSubscribe(apiArgument.capture(), argument.capture()); + Mockito.verify(service, Mockito.times(3)) + .listSubscribe(apiArgument.capture(), argument.capture()); String apiKey = apiArgument.getValue(); assertEquals("some api key", apiKey); List subscribeRequests = argument.getAllValues(); @@ -569,29 +617,35 @@ public void testProcessAudienceMembershipChangeRequest() throws Exception { i++; break; case 3: - assertEquals(subscribeRequest.subscribers.get(0).email, "mptest-2@mparticle.com"); + assertEquals( + subscribeRequest.subscribers.get(0).email, "mptest-2@mparticle.com"); i++; break; } } assertEquals(3, i); - ArgumentCaptor unsubArg = ArgumentCaptor.forClass(UnsubscribeRequest.class); - Mockito.verify(service, Mockito.times(3)).listUnsubscribe(Mockito.any(), unsubArg.capture()); + ArgumentCaptor unsubArg = + ArgumentCaptor.forClass(UnsubscribeRequest.class); + Mockito.verify(service, Mockito.times(3)) + .listUnsubscribe(Mockito.any(), unsubArg.capture()); List unsubscribeRequests = unsubArg.getAllValues(); i = 0; for (UnsubscribeRequest unsubscribeRequest : unsubscribeRequests) { switch (unsubscribeRequest.listId) { case 1: - assertEquals(unsubscribeRequest.subscribers.get(0).email, "mptest-2@mparticle.com"); + assertEquals( + unsubscribeRequest.subscribers.get(0).email, "mptest-2@mparticle.com"); i++; break; case 2: - assertEquals(unsubscribeRequest.subscribers.get(0).email, "mptest-2@mparticle.com"); + assertEquals( + unsubscribeRequest.subscribers.get(0).email, "mptest-2@mparticle.com"); i++; break; case 3: - assertEquals(unsubscribeRequest.subscribers.get(0).email, "mptest@mparticle.com"); + assertEquals( + unsubscribeRequest.subscribers.get(0).email, "mptest@mparticle.com"); i++; break; } @@ -629,13 +683,14 @@ public void testProcessAudienceMembershipChangeWithMPID() throws IOException { testIterableExtension.processAudienceMembershipChangeRequest(request); - ArgumentCaptor subscribeArgs = ArgumentCaptor.forClass(SubscribeRequest.class); + ArgumentCaptor subscribeArgs = + ArgumentCaptor.forClass(SubscribeRequest.class); List subscribeRequests = subscribeArgs.getAllValues(); - Mockito.verify(iterableServiceMock, Mockito.times(2)).listSubscribe(Mockito.any(), subscribeArgs.capture()); + Mockito.verify(iterableServiceMock, Mockito.times(2)) + .listSubscribe(Mockito.any(), subscribeArgs.capture()); Collections.sort( subscribeRequests, - (a, b) -> a.listId > b.listId ? 1 : a.listId == b.listId ? 0 : -1 - ); + (a, b) -> a.listId > b.listId ? 1 : a.listId == b.listId ? 0 : -1); assertEquals(1, subscribeRequests.get(0).listId.intValue()); assertEquals(2, subscribeRequests.get(1).listId.intValue()); int expectedUserSubscribeCount = 0; @@ -660,9 +715,11 @@ public void testProcessAudienceMembershipChangeWithMPID() throws IOException { } assertEquals(3, expectedUserSubscribeCount); - ArgumentCaptor unsubArg = ArgumentCaptor.forClass(UnsubscribeRequest.class); + ArgumentCaptor unsubArg = + ArgumentCaptor.forClass(UnsubscribeRequest.class); List unsubscribeRequests = unsubArg.getAllValues(); - Mockito.verify(iterableServiceMock, Mockito.times(1)).listUnsubscribe(Mockito.any(), unsubArg.capture()); + Mockito.verify(iterableServiceMock, Mockito.times(1)) + .listUnsubscribe(Mockito.any(), unsubArg.capture()); assertEquals(3, unsubscribeRequests.get(0).listId.intValue()); int expectedUserUnsubscribeCount = 0; for (ApiUser user : unsubscribeRequests.get(0).subscribers) { @@ -709,8 +766,6 @@ public void testConvertToCommerceItem() throws Exception { item = new IterableExtension().convertToCommerceItem(product, false); assertEquals("123", item.dataFields.get("an int key")); - - } @Test @@ -731,8 +786,11 @@ public void testProcessProductActionEvent() throws Exception { EventProcessingRequest request = createEventProcessingRequest(); List userIdentities = new LinkedList<>(); - userIdentities.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); - userIdentities.add(new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); + userIdentities.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); + userIdentities.add( + new UserIdentity(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, "123456")); request.setUserIdentities(userIdentities); event.setRequest(request); event.setTotalAmount(new BigDecimal(101d)); @@ -755,8 +813,10 @@ public void testProcessProductActionEvent() throws Exception { event.setAction(ProductActionEvent.Action.PURCHASE); extension.processProductActionEvent(event); - ArgumentCaptor purchaseArgs = ArgumentCaptor.forClass(TrackPurchaseRequest.class); - Mockito.verify(extension.iterableService, Mockito.times(1)).trackPurchase(Mockito.any(), purchaseArgs.capture()); + ArgumentCaptor purchaseArgs = + ArgumentCaptor.forClass(TrackPurchaseRequest.class); + Mockito.verify(extension.iterableService, Mockito.times(1)) + .trackPurchase(Mockito.any(), purchaseArgs.capture()); TrackPurchaseRequest trackPurchaseRequest = purchaseArgs.getValue(); assertEquals(trackPurchaseRequest.user.email, "mptest@mparticle.com"); assertEquals(trackPurchaseRequest.user.userId, "123456"); @@ -773,7 +833,7 @@ public void testGetPlaceholderEmailNoEnvironmentOrStamp() throws Exception { Exception e = null; try { String email = IterableExtension.getPlaceholderEmail(request); - }catch (IOException ioe) { + } catch (IOException ioe) { e = ioe; } assertNotNull(e); @@ -813,14 +873,18 @@ public void testGetPlaceholderEmailEnvironmentButNoIds() throws Exception { public void testGetPlaceholderEmailEnvironmentIDFA() throws Exception { EventProcessingRequest request = createEventProcessingRequest(); request.setRuntimeEnvironment(new IosRuntimeEnvironment()); - DeviceIdentity idfa = new DeviceIdentity(DeviceIdentity.Type.IOS_ADVERTISING_ID, Identity.Encoding.RAW, "foo-idfa"); - ((IosRuntimeEnvironment)request.getRuntimeEnvironment()).setIdentities(Arrays.asList(idfa)); + DeviceIdentity idfa = + new DeviceIdentity( + DeviceIdentity.Type.IOS_ADVERTISING_ID, Identity.Encoding.RAW, "foo-idfa"); + ((IosRuntimeEnvironment) request.getRuntimeEnvironment()) + .setIdentities(Arrays.asList(idfa)); request.setDeviceApplicationStamp("1234"); String email = IterableExtension.getPlaceholderEmail(request); assertEquals("foo-idfa@placeholder.email", email); request.setRuntimeEnvironment(new TVOSRuntimeEnvironment()); - ((TVOSRuntimeEnvironment)request.getRuntimeEnvironment()).setIdentities(Arrays.asList(idfa)); + ((TVOSRuntimeEnvironment) request.getRuntimeEnvironment()) + .setIdentities(Arrays.asList(idfa)); request.setDeviceApplicationStamp("1234"); email = IterableExtension.getPlaceholderEmail(request); assertEquals("foo-idfa@placeholder.email", email); @@ -830,15 +894,21 @@ public void testGetPlaceholderEmailEnvironmentIDFA() throws Exception { public void testGetPlaceholderEmailEnvironmentIDFV() throws Exception { EventProcessingRequest request = createEventProcessingRequest(); request.setRuntimeEnvironment(new IosRuntimeEnvironment()); - DeviceIdentity idfv = new DeviceIdentity(DeviceIdentity.Type.IOS_VENDOR_ID, Identity.Encoding.RAW, "foo-idfv"); - DeviceIdentity idfa = new DeviceIdentity(DeviceIdentity.Type.IOS_ADVERTISING_ID, Identity.Encoding.RAW, "foo-idfa"); - ((IosRuntimeEnvironment)request.getRuntimeEnvironment()).setIdentities(Arrays.asList(idfa, idfv)); + DeviceIdentity idfv = + new DeviceIdentity( + DeviceIdentity.Type.IOS_VENDOR_ID, Identity.Encoding.RAW, "foo-idfv"); + DeviceIdentity idfa = + new DeviceIdentity( + DeviceIdentity.Type.IOS_ADVERTISING_ID, Identity.Encoding.RAW, "foo-idfa"); + ((IosRuntimeEnvironment) request.getRuntimeEnvironment()) + .setIdentities(Arrays.asList(idfa, idfv)); request.setDeviceApplicationStamp("1234"); String email = IterableExtension.getPlaceholderEmail(request); assertEquals("foo-idfv@placeholder.email", email); request.setRuntimeEnvironment(new TVOSRuntimeEnvironment()); - ((TVOSRuntimeEnvironment)request.getRuntimeEnvironment()).setIdentities(Arrays.asList(idfa, idfv)); + ((TVOSRuntimeEnvironment) request.getRuntimeEnvironment()) + .setIdentities(Arrays.asList(idfa, idfv)); request.setDeviceApplicationStamp("1234"); email = IterableExtension.getPlaceholderEmail(request); assertEquals("foo-idfv@placeholder.email", email); @@ -848,9 +918,16 @@ public void testGetPlaceholderEmailEnvironmentIDFV() throws Exception { public void testGetPlaceholderEmailEnvironmentGAID() throws Exception { EventProcessingRequest request = createEventProcessingRequest(); request.setRuntimeEnvironment(new AndroidRuntimeEnvironment()); - DeviceIdentity idfv = new DeviceIdentity(DeviceIdentity.Type.ANDROID_ID, Identity.Encoding.RAW, "foo-aid"); - DeviceIdentity idfa = new DeviceIdentity(DeviceIdentity.Type.GOOGLE_ADVERTISING_ID, Identity.Encoding.RAW, "foo-gaid"); - ((AndroidRuntimeEnvironment)request.getRuntimeEnvironment()).setIdentities(Arrays.asList(idfa, idfv)); + DeviceIdentity idfv = + new DeviceIdentity( + DeviceIdentity.Type.ANDROID_ID, Identity.Encoding.RAW, "foo-aid"); + DeviceIdentity idfa = + new DeviceIdentity( + DeviceIdentity.Type.GOOGLE_ADVERTISING_ID, + Identity.Encoding.RAW, + "foo-gaid"); + ((AndroidRuntimeEnvironment) request.getRuntimeEnvironment()) + .setIdentities(Arrays.asList(idfa, idfv)); request.setDeviceApplicationStamp("1234"); String email = IterableExtension.getPlaceholderEmail(request); assertEquals("foo-gaid@placeholder.email", email); @@ -860,8 +937,11 @@ public void testGetPlaceholderEmailEnvironmentGAID() throws Exception { public void testGetPlaceholderEmailEnvironmentAndroidID() throws Exception { EventProcessingRequest request = createEventProcessingRequest(); request.setRuntimeEnvironment(new AndroidRuntimeEnvironment()); - DeviceIdentity idfv = new DeviceIdentity(DeviceIdentity.Type.ANDROID_ID, Identity.Encoding.RAW, "foo-aid"); - ((AndroidRuntimeEnvironment)request.getRuntimeEnvironment()).setIdentities(Arrays.asList(idfv)); + DeviceIdentity idfv = + new DeviceIdentity( + DeviceIdentity.Type.ANDROID_ID, Identity.Encoding.RAW, "foo-aid"); + ((AndroidRuntimeEnvironment) request.getRuntimeEnvironment()) + .setIdentities(Arrays.asList(idfv)); request.setDeviceApplicationStamp("1234"); String email = IterableExtension.getPlaceholderEmail(request); assertEquals("foo-aid@placeholder.email", email); @@ -889,7 +969,9 @@ public void testUpdateSubscriptionsEvent() throws Exception { Map settings = request.getAccount().getAccountSettings(); settings.put(SETTING_API_KEY, "foo api key 2"); List userIdentities = new LinkedList<>(); - userIdentities.add(new UserIdentity(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); + userIdentities.add( + new UserIdentity( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, "mptest@mparticle.com")); request.setUserIdentities(userIdentities); event.setRequest(request); Map attributes = new HashMap<>(); @@ -900,24 +982,26 @@ public void testUpdateSubscriptionsEvent() throws Exception { attributes.put(IterableExtension.CAMPAIGN_ID_KEY, "2323"); attributes.put(IterableExtension.TEMPLATE_ID_KEY, " 5555 "); event.setAttributes(attributes); - List expectedEmailListIdList = Arrays.asList(1,2,3,4,5,6,7,8); - List expectedChannelIdList = Arrays.asList(1,3,5,7); - List expectedMessageTypeIdList = Arrays.asList(1,3,5,7,10); + List expectedEmailListIdList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); + List expectedChannelIdList = Arrays.asList(1, 3, 5, 7); + List expectedMessageTypeIdList = Arrays.asList(1, 3, 5, 7, 10); int expectedCampaignId = 2323; int expectedTemplateId = 5555; extension.processCustomEvent(event); - ArgumentCaptor argument = ArgumentCaptor.forClass(UpdateSubscriptionsRequest.class); + ArgumentCaptor argument = + ArgumentCaptor.forClass(UpdateSubscriptionsRequest.class); ArgumentCaptor stringArgumentCaptor = ArgumentCaptor.forClass(String.class); - Mockito.verify(extension.iterableService).updateSubscriptions(stringArgumentCaptor.capture(), argument.capture()); + Mockito.verify(extension.iterableService) + .updateSubscriptions(stringArgumentCaptor.capture(), argument.capture()); assertEquals("foo api key 2", stringArgumentCaptor.getValue()); assertEquals("mptest@mparticle.com", argument.getValue().email); assertEquals(expectedEmailListIdList, argument.getValue().emailListIds); assertEquals(expectedChannelIdList, argument.getValue().unsubscribedChannelIds); assertEquals(expectedMessageTypeIdList, argument.getValue().unsubscribedMessageTypeIds); - assertEquals(expectedCampaignId, (int)argument.getValue().campaignId); - assertEquals(expectedTemplateId, (int)argument.getValue().templateId); + assertEquals(expectedCampaignId, (int) argument.getValue().campaignId); + assertEquals(expectedTemplateId, (int) argument.getValue().templateId); } @Test @@ -925,63 +1009,82 @@ public void testHandleIterableResponseSuccess() throws RetriableError { ByteArrayOutputStream outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); - IterableExtension.handleIterableResponse(testSuccessResponse, - UUID.fromString("d0567916-c2c7-11ea-b3de-0242ac130004")); + IterableExtension.handleIterableResponse( + testSuccessResponse, UUID.fromString("d0567916-c2c7-11ea-b3de-0242ac130004")); assertEquals("A success response shouldn't log", "", outContent.toString()); System.setOut(System.out); } @Test public void testHandleIterableResponseLogsError() throws RetriableError { - String expectedLogMessage = "{\"iterableApiCode\":\"InvalidEmailAddressError\",\"mParticleEventId\":\"d0567916-c2c7-11ea-b3de-0242ac130004\",\"httpStatus\":\"400\",\"message\":\"Error sending request to Iterable\",\"url\":\"/\"}\n"; + String expectedLogMessage = + "{\"iterableApiCode\":\"InvalidEmailAddressError\",\"mParticleEventId\":\"d0567916-c2c7-11ea-b3de-0242ac130004\",\"httpStatus\":\"400\",\"message\":\"Error sending request to Iterable\",\"url\":\"/\"}\n"; ByteArrayOutputStream outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); - IterableExtension.handleIterableResponse(testErrorResponse, - UUID.fromString("d0567916-c2c7-11ea-b3de-0242ac130004")); + IterableExtension.handleIterableResponse( + testErrorResponse, UUID.fromString("d0567916-c2c7-11ea-b3de-0242ac130004")); assertEquals("An error response should log", expectedLogMessage, outContent.toString()); System.setOut(System.out); } @Test(expected = RetriableError.class) public void testHandleIterableResponseWith429() throws RetriableError { - Response itbl492 = Response.error(429, ResponseBody.create( - MediaType.parse("application/json; charset=utf-8"), "{}")); + Response itbl492 = + Response.error( + 429, + ResponseBody.create( + MediaType.parse("application/json; charset=utf-8"), "{}")); IterableExtension.handleIterableResponse(itbl492, UUID.randomUUID()); } @Test(expected = RetriableError.class) public void testHandleIterableResponseWith502() throws RetriableError { - Response itbl502 = Response.error(502, ResponseBody.create( - MediaType.parse("application/json; charset=utf-8"), "{}")); + Response itbl502 = + Response.error( + 502, + ResponseBody.create( + MediaType.parse("application/json; charset=utf-8"), "{}")); IterableExtension.handleIterableResponse(itbl502, UUID.randomUUID()); } @Test(expected = RetriableError.class) public void testHandleIterableResponseWith504() throws RetriableError { - Response itbl504 = Response.error(504, ResponseBody.create( - MediaType.parse("application/json; charset=utf-8"), "{}")); + Response itbl504 = + Response.error( + 504, + ResponseBody.create( + MediaType.parse("application/json; charset=utf-8"), "{}")); IterableExtension.handleIterableResponse(itbl504, UUID.randomUUID()); } @Test(expected = RetriableError.class) public void testHandleIterableListResponseWith429() throws RetriableError { - Response itbl492 = Response.error(429, ResponseBody.create( - MediaType.parse("application/json; charset=utf-8"), "{}")); + Response itbl492 = + Response.error( + 429, + ResponseBody.create( + MediaType.parse("application/json; charset=utf-8"), "{}")); IterableExtension.handleIterableListResponse(itbl492, UUID.randomUUID()); } @Test(expected = RetriableError.class) public void testHandleIterableListResponseWith502() throws RetriableError { - Response itbl502 = Response.error(502, ResponseBody.create( - MediaType.parse("application/json; charset=utf-8"), "{}")); + Response itbl502 = + Response.error( + 502, + ResponseBody.create( + MediaType.parse("application/json; charset=utf-8"), "{}")); IterableExtension.handleIterableListResponse(itbl502, UUID.randomUUID()); } @Test(expected = RetriableError.class) public void testHandleIterableListResponseWith504() throws RetriableError { - Response itbl504 = Response.error(504, ResponseBody.create( - MediaType.parse("application/json; charset=utf-8"), "{}")); + Response itbl504 = + Response.error( + 504, + ResponseBody.create( + MediaType.parse("application/json; charset=utf-8"), "{}")); IterableExtension.handleIterableListResponse(itbl504, UUID.randomUUID()); } @@ -1007,15 +1110,20 @@ public void testMakeIterableRequestWithListSuccess() throws IOException { @Test(expected = RetriableError.class) public void testMakeIterableRequestWithTimeout() throws IOException { Call call = Mockito.mock(Call.class); - HttpUrl url = new HttpUrl.Builder() - .scheme("https") - .host("api.iterable.com") - .addEncodedPathSegment("/api/events/track") - .build(); - Request request = new Request.Builder() - .method("POST", RequestBody.create(MediaType.parse("application/json; charset=utf-8"), "{}")) - .url(url) - .build(); + HttpUrl url = + new HttpUrl.Builder() + .scheme("https") + .host("api.iterable.com") + .addEncodedPathSegment("/api/events/track") + .build(); + Request request = + new Request.Builder() + .method( + "POST", + RequestBody.create( + MediaType.parse("application/json; charset=utf-8"), "{}")) + .url(url) + .build(); Mockito.when(call.request()).thenReturn(request); Mockito.when(call.execute()).thenThrow(java.net.SocketTimeoutException.class); @@ -1044,4 +1152,3 @@ private Call createCallMockWithSuccessResponse() throws IOException { return callMock; } } - diff --git a/iterable-extension/src/test/java/com/mparticle/ext/iterable/IterableLambdaEndpointTest.java b/iterable-extension/src/test/java/com/mparticle/ext/iterable/IterableLambdaEndpointTest.java index 2f763eb..f64ea85 100644 --- a/iterable-extension/src/test/java/com/mparticle/ext/iterable/IterableLambdaEndpointTest.java +++ b/iterable-extension/src/test/java/com/mparticle/ext/iterable/IterableLambdaEndpointTest.java @@ -1,30 +1,29 @@ package com.mparticle.ext.iterable; -import com.mparticle.sdk.model.Message; -import org.apache.commons.io.IOUtils; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import com.mparticle.sdk.model.Message; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; - -import static org.junit.Assert.assertEquals; +import org.apache.commons.io.IOUtils; +import org.junit.Test; public class IterableLambdaEndpointTest { - static IterableLambdaEndpoint lambda = new IterableLambdaEndpoint(); - private static final String PATH_TO_FIXTURES = "src/test/resources/"; + static IterableLambdaEndpoint lambda = new IterableLambdaEndpoint(); + private static final String PATH_TO_FIXTURES = "src/test/resources/"; - @Test - public void testParseQueueTrigger() throws IOException { - String inputString = IOUtils.toString(readTestFixture("queueTrigger.json"), "UTF-8"); - Message request = lambda.parseQueueTrigger(inputString); - assertEquals(Message.Type.EVENT_PROCESSING_REQUEST, request.getType()); - } + @Test + public void testParseQueueTrigger() throws IOException { + String inputString = IOUtils.toString(readTestFixture("queueTrigger.json"), "UTF-8"); + Message request = lambda.parseQueueTrigger(inputString); + assertEquals(Message.Type.EVENT_PROCESSING_REQUEST, request.getType()); + } - private static InputStream readTestFixture(String fileName) throws IOException { - File initialFile = new File(PATH_TO_FIXTURES + fileName); - InputStream fixtureInputStream = new FileInputStream(initialFile); - return fixtureInputStream; - } + private static InputStream readTestFixture(String fileName) throws IOException { + File initialFile = new File(PATH_TO_FIXTURES + fileName); + InputStream fixtureInputStream = new FileInputStream(initialFile); + return fixtureInputStream; + } } diff --git a/iterable-ingress-extension/build.gradle b/iterable-ingress-extension/build.gradle index d7a0e6f..1e02d4f 100644 --- a/iterable-ingress-extension/build.gradle +++ b/iterable-ingress-extension/build.gradle @@ -1,4 +1,7 @@ -apply plugin: 'java' +plugins { + id 'java' + id 'com.github.sherter.google-java-format' version '0.8' +} repositories { mavenLocal() @@ -25,4 +28,10 @@ task buildZip(type: Zip) { } } +tasks.verifyGoogleJavaFormat.ignoreFailures = true + +googleJavaFormat { + options style: 'AOSP' +} + build.dependsOn buildZip diff --git a/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IngressExtension.java b/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IngressExtension.java index ac2c982..9beee75 100644 --- a/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IngressExtension.java +++ b/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IngressExtension.java @@ -7,165 +7,176 @@ import com.mparticle.sdk.model.audienceprocessing.AudienceSubscriptionResponse; import com.mparticle.sdk.model.eventprocessing.*; import com.mparticle.sdk.model.registration.*; - import java.io.IOException; import java.util.*; public class IngressExtension extends MessageProcessor { - public static final String NAME = "Iterable"; - public static final String SETTING_API_KEY = "apiKey"; - public static final String SETTING_GCM_NAME_KEY = "gcmIntegrationName"; - public static final String SETTING_APNS_KEY = "apnsProdIntegrationName"; - public static final String SETTING_APNS_SANDBOX_KEY = "apnsSandboxIntegrationName"; - public static final String SETTING_LIST_ID = "listId"; - public static final String SETTING_COERCE_STRINGS_TO_SCALARS = "coerceStringsToScalars"; - public static final String SETTING_USER_ID_FIELD = "userIdField"; - public static final String USER_ID_FIELD_CUSTOMER_ID = "customerId"; - - @Override - public ModuleRegistrationResponse processRegistrationRequest(ModuleRegistrationRequest request) { - ModuleRegistrationResponse response = new ModuleRegistrationResponse(NAME, "1.6.0"); - - Permissions permissions = new Permissions(); - permissions.setUserIdentities( - Arrays.asList( - new UserIdentityPermission(UserIdentity.Type.EMAIL, Identity.Encoding.RAW, false), - new UserIdentityPermission(UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, false) - ) - ); - permissions.setDeviceIdentities( - Arrays.asList( - new DeviceIdentityPermission(DeviceIdentity.Type.GOOGLE_CLOUD_MESSAGING_TOKEN, Identity.Encoding.RAW), - new DeviceIdentityPermission(DeviceIdentity.Type.APPLE_PUSH_NOTIFICATION_TOKEN, Identity.Encoding.RAW), - new DeviceIdentityPermission(DeviceIdentity.Type.IOS_VENDOR_ID, Identity.Encoding.RAW), - new DeviceIdentityPermission(DeviceIdentity.Type.ANDROID_ID, Identity.Encoding.RAW), - new DeviceIdentityPermission(DeviceIdentity.Type.GOOGLE_ADVERTISING_ID, Identity.Encoding.RAW) - ) - ); - permissions.setAllowAccessDeviceApplicationStamp(true); - permissions.setAllowUserAttributes(true); - permissions.setAllowDeviceInformation(true); - permissions.setAllowAccessMpid(true); - response.setPermissions(permissions); - response.setDescription("Iterable makes consumer growth marketing and user engagement simple. With Iterable, marketers send the right message, to the right device, at the right time."); - EventProcessingRegistration eventProcessingRegistration = new EventProcessingRegistration() - .setSupportedRuntimeEnvironments( - Arrays.asList( - RuntimeEnvironment.Type.ANDROID, - RuntimeEnvironment.Type.IOS, - RuntimeEnvironment.Type.MOBILEWEB, - RuntimeEnvironment.Type.UNKNOWN) - ); - eventProcessingRegistration.setPushMessagingProviderId("itbl"); - - List eventSettings = new ArrayList<>(); - List audienceSettings = new ArrayList<>(); - Setting apiKey = new TextSetting(SETTING_API_KEY, "API Key") - .setIsRequired(true) - .setIsConfidential(true) - .setDescription("API key used to connect to the Iterable API - see the Integrations section of your Iterable account."); - Setting userIdField = new TextSetting(SETTING_USER_ID_FIELD, "User ID") - .setIsRequired(true) - .setDefaultValue(USER_ID_FIELD_CUSTOMER_ID) - .setDescription("Select which user identity to forward to Iterable as your customer's user ID."); - - audienceSettings.add(apiKey); - audienceSettings.add(userIdField); - - eventSettings.add(apiKey); - eventSettings.add( - new TextSetting(SETTING_GCM_NAME_KEY, "GCM Push Integration Name") - .setIsRequired(false) - .setDescription("GCM integration name set up in the Mobile Push section of your Iterable account.") - - ); - eventSettings.add( - new TextSetting(SETTING_APNS_SANDBOX_KEY, "APNS Sandbox Integration Name") - .setIsRequired(false) - .setDescription("APNS Sandbox integration name set up in the Mobile Push section of your Iterable account.") - ); - eventSettings.add( - new TextSetting(SETTING_APNS_KEY, "APNS Production Integration Name") - .setIsRequired(false) - .setDescription("APNS Production integration name set up in the Mobile Push section of your Iterable account.") - ); - eventSettings.add( - new BooleanSetting(SETTING_COERCE_STRINGS_TO_SCALARS, "Coerce Strings to Scalars") - .setIsChecked(true) - .setDescription("If enabled, mParticle will attempt to coerce string attributes into scalar types (integer, boolean, and float).") - ); - eventProcessingRegistration.setAccountSettings(eventSettings); - - List connectionSettings = new ArrayList<>(); - connectionSettings.add(userIdField); - eventProcessingRegistration.setConnectionSettings(connectionSettings); - - // Specify supported event types - List supportedEventTypes = Arrays.asList( - Event.Type.CUSTOM_EVENT, - Event.Type.PUSH_SUBSCRIPTION, - Event.Type.PUSH_MESSAGE_RECEIPT, - Event.Type.PUSH_MESSAGE_OPEN, - Event.Type.USER_IDENTITY_CHANGE, - Event.Type.PRODUCT_ACTION); - - eventProcessingRegistration.setSupportedEventTypes(supportedEventTypes); - response.setEventProcessingRegistration(eventProcessingRegistration); - AudienceProcessingRegistration audienceRegistration = new AudienceProcessingRegistration(); - audienceRegistration.setAccountSettings(audienceSettings); - List subscriptionSettings = new LinkedList<>(); - IntegerSetting listIdSetting = new IntegerSetting(SETTING_LIST_ID, "List ID"); - listIdSetting.setIsRequired(true); - listIdSetting.setDescription("The ID of the Iterable list to populate with the users from this segment."); - subscriptionSettings.add(listIdSetting); - audienceRegistration.setAudienceConnectionSettings(subscriptionSettings); - response.setAudienceProcessingRegistration(audienceRegistration); - - return response; - } - - /** - * When a MessageProcessor is given a batch of data/events, it will first call this method. This - * is a good time to do some setup. - */ - @Override - public EventProcessingResponse processEventProcessingRequest(EventProcessingRequest request) - throws IOException { - // do some setup, then call super. if you don't call super, you'll effectively short circuit - // the whole thing, which isn't really fun for anyone. - return super.processEventProcessingRequest(request); - } - - @Override - public void processPushMessageReceiptEvent(PushMessageReceiptEvent event) throws IOException { - super.processPushMessageReceiptEvent(event); - } - - @Override - public void processPushSubscriptionEvent(PushSubscriptionEvent event) throws IOException { - super.processPushSubscriptionEvent(event); - } - - @Override - public void processUserIdentityChangeEvent(UserIdentityChangeEvent event) throws IOException { - super.processUserIdentityChangeEvent(event); - } - - @Override - public void processCustomEvent(CustomEvent event) throws IOException { - super.processCustomEvent(event); - } - - @Override - public AudienceMembershipChangeResponse processAudienceMembershipChangeRequest( - AudienceMembershipChangeRequest request) throws IOException { - return super.processAudienceMembershipChangeRequest(request); - } - - @Override - public AudienceSubscriptionResponse processAudienceSubscriptionRequest( - AudienceSubscriptionRequest request) throws IOException { - return super.processAudienceSubscriptionRequest(request); - } + public static final String NAME = "Iterable"; + public static final String SETTING_API_KEY = "apiKey"; + public static final String SETTING_GCM_NAME_KEY = "gcmIntegrationName"; + public static final String SETTING_APNS_KEY = "apnsProdIntegrationName"; + public static final String SETTING_APNS_SANDBOX_KEY = "apnsSandboxIntegrationName"; + public static final String SETTING_LIST_ID = "listId"; + public static final String SETTING_COERCE_STRINGS_TO_SCALARS = "coerceStringsToScalars"; + public static final String SETTING_USER_ID_FIELD = "userIdField"; + public static final String USER_ID_FIELD_CUSTOMER_ID = "customerId"; + + @Override + public ModuleRegistrationResponse processRegistrationRequest( + ModuleRegistrationRequest request) { + ModuleRegistrationResponse response = new ModuleRegistrationResponse(NAME, "1.6.0"); + + Permissions permissions = new Permissions(); + permissions.setUserIdentities( + Arrays.asList( + new UserIdentityPermission( + UserIdentity.Type.EMAIL, Identity.Encoding.RAW, false), + new UserIdentityPermission( + UserIdentity.Type.CUSTOMER, Identity.Encoding.RAW, false))); + permissions.setDeviceIdentities( + Arrays.asList( + new DeviceIdentityPermission( + DeviceIdentity.Type.GOOGLE_CLOUD_MESSAGING_TOKEN, + Identity.Encoding.RAW), + new DeviceIdentityPermission( + DeviceIdentity.Type.APPLE_PUSH_NOTIFICATION_TOKEN, + Identity.Encoding.RAW), + new DeviceIdentityPermission( + DeviceIdentity.Type.IOS_VENDOR_ID, Identity.Encoding.RAW), + new DeviceIdentityPermission( + DeviceIdentity.Type.ANDROID_ID, Identity.Encoding.RAW), + new DeviceIdentityPermission( + DeviceIdentity.Type.GOOGLE_ADVERTISING_ID, Identity.Encoding.RAW))); + permissions.setAllowAccessDeviceApplicationStamp(true); + permissions.setAllowUserAttributes(true); + permissions.setAllowDeviceInformation(true); + permissions.setAllowAccessMpid(true); + response.setPermissions(permissions); + response.setDescription( + "Iterable makes consumer growth marketing and user engagement simple. With Iterable, marketers send the right message, to the right device, at the right time."); + EventProcessingRegistration eventProcessingRegistration = + new EventProcessingRegistration() + .setSupportedRuntimeEnvironments( + Arrays.asList( + RuntimeEnvironment.Type.ANDROID, + RuntimeEnvironment.Type.IOS, + RuntimeEnvironment.Type.MOBILEWEB, + RuntimeEnvironment.Type.UNKNOWN)); + eventProcessingRegistration.setPushMessagingProviderId("itbl"); + + List eventSettings = new ArrayList<>(); + List audienceSettings = new ArrayList<>(); + Setting apiKey = + new TextSetting(SETTING_API_KEY, "API Key") + .setIsRequired(true) + .setIsConfidential(true) + .setDescription( + "API key used to connect to the Iterable API - see the Integrations section of your Iterable account."); + Setting userIdField = + new TextSetting(SETTING_USER_ID_FIELD, "User ID") + .setIsRequired(true) + .setDefaultValue(USER_ID_FIELD_CUSTOMER_ID) + .setDescription( + "Select which user identity to forward to Iterable as your customer's user ID."); + + audienceSettings.add(apiKey); + audienceSettings.add(userIdField); + + eventSettings.add(apiKey); + eventSettings.add( + new TextSetting(SETTING_GCM_NAME_KEY, "GCM Push Integration Name") + .setIsRequired(false) + .setDescription( + "GCM integration name set up in the Mobile Push section of your Iterable account.")); + eventSettings.add( + new TextSetting(SETTING_APNS_SANDBOX_KEY, "APNS Sandbox Integration Name") + .setIsRequired(false) + .setDescription( + "APNS Sandbox integration name set up in the Mobile Push section of your Iterable account.")); + eventSettings.add( + new TextSetting(SETTING_APNS_KEY, "APNS Production Integration Name") + .setIsRequired(false) + .setDescription( + "APNS Production integration name set up in the Mobile Push section of your Iterable account.")); + eventSettings.add( + new BooleanSetting(SETTING_COERCE_STRINGS_TO_SCALARS, "Coerce Strings to Scalars") + .setIsChecked(true) + .setDescription( + "If enabled, mParticle will attempt to coerce string attributes into scalar types (integer, boolean, and float).")); + eventProcessingRegistration.setAccountSettings(eventSettings); + + List connectionSettings = new ArrayList<>(); + connectionSettings.add(userIdField); + eventProcessingRegistration.setConnectionSettings(connectionSettings); + + // Specify supported event types + List supportedEventTypes = + Arrays.asList( + Event.Type.CUSTOM_EVENT, + Event.Type.PUSH_SUBSCRIPTION, + Event.Type.PUSH_MESSAGE_RECEIPT, + Event.Type.PUSH_MESSAGE_OPEN, + Event.Type.USER_IDENTITY_CHANGE, + Event.Type.PRODUCT_ACTION); + + eventProcessingRegistration.setSupportedEventTypes(supportedEventTypes); + response.setEventProcessingRegistration(eventProcessingRegistration); + AudienceProcessingRegistration audienceRegistration = new AudienceProcessingRegistration(); + audienceRegistration.setAccountSettings(audienceSettings); + List subscriptionSettings = new LinkedList<>(); + IntegerSetting listIdSetting = new IntegerSetting(SETTING_LIST_ID, "List ID"); + listIdSetting.setIsRequired(true); + listIdSetting.setDescription( + "The ID of the Iterable list to populate with the users from this segment."); + subscriptionSettings.add(listIdSetting); + audienceRegistration.setAudienceConnectionSettings(subscriptionSettings); + response.setAudienceProcessingRegistration(audienceRegistration); + + return response; + } + + /** + * When a MessageProcessor is given a batch of data/events, it will first call this method. This + * is a good time to do some setup. + */ + @Override + public EventProcessingResponse processEventProcessingRequest(EventProcessingRequest request) + throws IOException { + // do some setup, then call super. if you don't call super, you'll effectively short circuit + // the whole thing, which isn't really fun for anyone. + return super.processEventProcessingRequest(request); + } + + @Override + public void processPushMessageReceiptEvent(PushMessageReceiptEvent event) throws IOException { + super.processPushMessageReceiptEvent(event); + } + + @Override + public void processPushSubscriptionEvent(PushSubscriptionEvent event) throws IOException { + super.processPushSubscriptionEvent(event); + } + + @Override + public void processUserIdentityChangeEvent(UserIdentityChangeEvent event) throws IOException { + super.processUserIdentityChangeEvent(event); + } + + @Override + public void processCustomEvent(CustomEvent event) throws IOException { + super.processCustomEvent(event); + } + + @Override + public AudienceMembershipChangeResponse processAudienceMembershipChangeRequest( + AudienceMembershipChangeRequest request) throws IOException { + return super.processAudienceMembershipChangeRequest(request); + } + + @Override + public AudienceSubscriptionResponse processAudienceSubscriptionRequest( + AudienceSubscriptionRequest request) throws IOException { + return super.processAudienceSubscriptionRequest(request); + } } diff --git a/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IngressQueueManager.java b/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IngressQueueManager.java index 91a3e4f..a75d9c1 100644 --- a/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IngressQueueManager.java +++ b/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IngressQueueManager.java @@ -1,29 +1,28 @@ package com.mparticle.ext.iterable; +import java.util.Objects; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.sqs.SqsClient; import software.amazon.awssdk.services.sqs.model.SendMessageRequest; -import java.util.Objects; - public class IngressQueueManager { - private SqsClient sqsClient; - private String queueUrl; + private SqsClient sqsClient; + private String queueUrl; - public IngressQueueManager(SqsClient sqsClient, String queueUrl) { - this.sqsClient = sqsClient; - this.queueUrl = queueUrl; - } + public IngressQueueManager(SqsClient sqsClient, String queueUrl) { + this.sqsClient = sqsClient; + this.queueUrl = queueUrl; + } - public void enqueueMessage(String message) { - SendMessageRequest req = - SendMessageRequest.builder().queueUrl(queueUrl).messageBody(message).build(); - sqsClient.sendMessage(req); - } + public void enqueueMessage(String message) { + SendMessageRequest req = + SendMessageRequest.builder().queueUrl(queueUrl).messageBody(message).build(); + sqsClient.sendMessage(req); + } - public static IngressQueueManager create() { - SqsClient sqsClient = SqsClient.builder().region(Region.US_EAST_1).build(); - String queueUrl = Objects.requireNonNull(System.getenv("QUEUE_URL")); - return new IngressQueueManager(sqsClient, queueUrl); - } + public static IngressQueueManager create() { + SqsClient sqsClient = SqsClient.builder().region(Region.US_EAST_1).build(); + String queueUrl = Objects.requireNonNull(System.getenv("QUEUE_URL")); + return new IngressQueueManager(sqsClient, queueUrl); + } } diff --git a/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IterableLambdaEndpoint.java b/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IterableLambdaEndpoint.java index 29fe7ae..9a230d8 100644 --- a/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IterableLambdaEndpoint.java +++ b/iterable-ingress-extension/src/main/java/com/mparticle/ext/iterable/IterableLambdaEndpoint.java @@ -4,29 +4,28 @@ import com.amazonaws.services.lambda.runtime.RequestStreamHandler; import com.mparticle.sdk.model.Message; import com.mparticle.sdk.model.MessageSerializer; -import org.apache.commons.io.IOUtils; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import org.apache.commons.io.IOUtils; public class IterableLambdaEndpoint implements RequestStreamHandler { - public static final MessageSerializer serializer = new MessageSerializer(); - public static final IngressExtension processor = new IngressExtension(); - public IngressQueueManager queueManager; + public static final MessageSerializer serializer = new MessageSerializer(); + public static final IngressExtension processor = new IngressExtension(); + public IngressQueueManager queueManager; - @Override - public void handleRequest(InputStream input, OutputStream output, Context context) - throws IOException { - if (queueManager == null) { - queueManager = IngressQueueManager.create(); - } - String mparticleRequest = IOUtils.toString(input, "UTF-8"); - queueManager.enqueueMessage(mparticleRequest); + @Override + public void handleRequest(InputStream input, OutputStream output, Context context) + throws IOException { + if (queueManager == null) { + queueManager = IngressQueueManager.create(); + } + String mparticleRequest = IOUtils.toString(input, "UTF-8"); + queueManager.enqueueMessage(mparticleRequest); - Message request = serializer.deserialize(mparticleRequest, Message.class); - Message response = processor.processMessage(request); - serializer.serialize(output, response); - } + Message request = serializer.deserialize(mparticleRequest, Message.class); + Message response = processor.processMessage(request); + serializer.serialize(output, response); + } } diff --git a/iterable-ingress-extension/src/test/java/com/mparticle/ext/iterable/IngressExtensionTest.java b/iterable-ingress-extension/src/test/java/com/mparticle/ext/iterable/IngressExtensionTest.java index fb40bc8..6c8dd49 100644 --- a/iterable-ingress-extension/src/test/java/com/mparticle/ext/iterable/IngressExtensionTest.java +++ b/iterable-ingress-extension/src/test/java/com/mparticle/ext/iterable/IngressExtensionTest.java @@ -1,110 +1,112 @@ package com.mparticle.ext.iterable; +import static com.mparticle.ext.iterable.IngressExtension.SETTING_API_KEY; +import static com.mparticle.ext.iterable.IngressExtension.SETTING_USER_ID_FIELD; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import com.mparticle.sdk.model.MessageSerializer; import com.mparticle.sdk.model.audienceprocessing.AudienceMembershipChangeRequest; import com.mparticle.sdk.model.audienceprocessing.AudienceMembershipChangeResponse; import com.mparticle.sdk.model.eventprocessing.*; import com.mparticle.sdk.model.registration.*; -import org.junit.Before; -import org.junit.Test; - import java.util.HashMap; import java.util.LinkedList; import java.util.List; - -import static com.mparticle.ext.iterable.IngressExtension.SETTING_API_KEY; -import static com.mparticle.ext.iterable.IngressExtension.SETTING_USER_ID_FIELD; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; public class IngressExtensionTest { - private static final String TEST_API_KEY = "foo api key"; - private static MessageSerializer serializer; - private static IngressExtension ingressExtension; - - @Before - public void setup() { - serializer = new MessageSerializer(); - ingressExtension = new IngressExtension(); - } - - @Test - public void testProcessRegistrationRequest() throws Exception { - ModuleRegistrationResponse response = - ingressExtension.processRegistrationRequest(new ModuleRegistrationRequest()); - List userIdentities = response.getPermissions().getUserIdentities(); - assertEquals(2, userIdentities.size()); - boolean email, customer; - email = - userIdentities.get(0).getType().equals(UserIdentity.Type.EMAIL) - || userIdentities.get(1).getType().equals(UserIdentity.Type.EMAIL); - - customer = - userIdentities.get(0).getType().equals(UserIdentity.Type.CUSTOMER) - || userIdentities.get(1).getType().equals(UserIdentity.Type.CUSTOMER); - - assertTrue("Iterable Extension should register for email permission", email); - assertTrue("Iterable Extension should register for customer id permission", customer); - - List accountSettings = response.getEventProcessingRegistration().getAccountSettings(); - assertTrue( - "There should be a single text setting (api key) for iterable", - accountSettings.get(0).getType().equals(Setting.Type.TEXT)); - - List eventTypes = - response.getEventProcessingRegistration().getSupportedEventTypes(); - assertTrue( - "Iterable should support custom events", eventTypes.contains(Event.Type.CUSTOM_EVENT)); - assertTrue( - "Iterable should support push subscriptions", - eventTypes.contains(Event.Type.PUSH_SUBSCRIPTION)); - assertTrue( - "Iterable should support push receipts", - eventTypes.contains(Event.Type.PUSH_MESSAGE_RECEIPT)); - assertTrue( - "Iterable should support user identity changes", - eventTypes.contains(Event.Type.USER_IDENTITY_CHANGE)); - - Setting setting = - response.getAudienceProcessingRegistration().getAudienceConnectionSettings().get(0); - assertTrue( - "Iterable audiences should have a single Integer setting", - setting.getType().equals(Setting.Type.INTEGER)); - } - - @Test - public void testProcessEventProcessingRequest() throws Exception { - EventProcessingRequest request = createEventProcessingRequest(); - List events = new LinkedList<>(); - events.add(new UserAttributeChangeEvent()); - request.setEvents(events); - - EventProcessingResponse response = ingressExtension.processEventProcessingRequest(request); - System.out.println(); - System.out.println(serializer.serialize(response)); - System.out.println(); - } - - @Test - public void testProcessAudienceMembershipChangeRequest() throws Exception { - AudienceMembershipChangeResponse response = - ingressExtension.processAudienceMembershipChangeRequest(new AudienceMembershipChangeRequest()); - System.out.println(); - System.out.println(serializer.serialize(response)); - System.out.println(); - } - - private EventProcessingRequest createEventProcessingRequest() { - EventProcessingRequest request = new EventProcessingRequest(); - Account account = new Account(); - HashMap settings = new HashMap(); - settings.put(SETTING_API_KEY, TEST_API_KEY); - settings.put(SETTING_USER_ID_FIELD, "customerId"); - account.setAccountSettings(settings); - request.setAccount(account); - request.setMpId("1234567890"); - - return request; - } + private static final String TEST_API_KEY = "foo api key"; + private static MessageSerializer serializer; + private static IngressExtension ingressExtension; + + @Before + public void setup() { + serializer = new MessageSerializer(); + ingressExtension = new IngressExtension(); + } + + @Test + public void testProcessRegistrationRequest() throws Exception { + ModuleRegistrationResponse response = + ingressExtension.processRegistrationRequest(new ModuleRegistrationRequest()); + List userIdentities = response.getPermissions().getUserIdentities(); + assertEquals(2, userIdentities.size()); + boolean email, customer; + email = + userIdentities.get(0).getType().equals(UserIdentity.Type.EMAIL) + || userIdentities.get(1).getType().equals(UserIdentity.Type.EMAIL); + + customer = + userIdentities.get(0).getType().equals(UserIdentity.Type.CUSTOMER) + || userIdentities.get(1).getType().equals(UserIdentity.Type.CUSTOMER); + + assertTrue("Iterable Extension should register for email permission", email); + assertTrue("Iterable Extension should register for customer id permission", customer); + + List accountSettings = + response.getEventProcessingRegistration().getAccountSettings(); + assertTrue( + "There should be a single text setting (api key) for iterable", + accountSettings.get(0).getType().equals(Setting.Type.TEXT)); + + List eventTypes = + response.getEventProcessingRegistration().getSupportedEventTypes(); + assertTrue( + "Iterable should support custom events", + eventTypes.contains(Event.Type.CUSTOM_EVENT)); + assertTrue( + "Iterable should support push subscriptions", + eventTypes.contains(Event.Type.PUSH_SUBSCRIPTION)); + assertTrue( + "Iterable should support push receipts", + eventTypes.contains(Event.Type.PUSH_MESSAGE_RECEIPT)); + assertTrue( + "Iterable should support user identity changes", + eventTypes.contains(Event.Type.USER_IDENTITY_CHANGE)); + + Setting setting = + response.getAudienceProcessingRegistration().getAudienceConnectionSettings().get(0); + assertTrue( + "Iterable audiences should have a single Integer setting", + setting.getType().equals(Setting.Type.INTEGER)); + } + + @Test + public void testProcessEventProcessingRequest() throws Exception { + EventProcessingRequest request = createEventProcessingRequest(); + List events = new LinkedList<>(); + events.add(new UserAttributeChangeEvent()); + request.setEvents(events); + + EventProcessingResponse response = ingressExtension.processEventProcessingRequest(request); + System.out.println(); + System.out.println(serializer.serialize(response)); + System.out.println(); + } + + @Test + public void testProcessAudienceMembershipChangeRequest() throws Exception { + AudienceMembershipChangeResponse response = + ingressExtension.processAudienceMembershipChangeRequest( + new AudienceMembershipChangeRequest()); + System.out.println(); + System.out.println(serializer.serialize(response)); + System.out.println(); + } + + private EventProcessingRequest createEventProcessingRequest() { + EventProcessingRequest request = new EventProcessingRequest(); + Account account = new Account(); + HashMap settings = new HashMap(); + settings.put(SETTING_API_KEY, TEST_API_KEY); + settings.put(SETTING_USER_ID_FIELD, "customerId"); + account.setAccountSettings(settings); + request.setAccount(account); + request.setMpId("1234567890"); + + return request; + } } diff --git a/iterable-ingress-extension/src/test/java/com/mparticle/ext/iterable/IterableLambdaEndpointTest.java b/iterable-ingress-extension/src/test/java/com/mparticle/ext/iterable/IterableLambdaEndpointTest.java index f09fc78..a169722 100644 --- a/iterable-ingress-extension/src/test/java/com/mparticle/ext/iterable/IterableLambdaEndpointTest.java +++ b/iterable-ingress-extension/src/test/java/com/mparticle/ext/iterable/IterableLambdaEndpointTest.java @@ -1,76 +1,76 @@ package com.mparticle.ext.iterable; +import static org.junit.Assert.assertNotNull; + import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.*; +import java.util.Map; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; -import java.io.*; -import java.util.Map; - -import static org.junit.Assert.assertNotNull; - public class IterableLambdaEndpointTest { - private static final ObjectMapper mapper = new ObjectMapper(); - private static final String PATH_TO_FIXTURES = "src/test/resources/"; - private IterableLambdaEndpoint lambda; + private static final ObjectMapper mapper = new ObjectMapper(); + private static final String PATH_TO_FIXTURES = "src/test/resources/"; + private IterableLambdaEndpoint lambda; - @Before - public void setup() { - lambda = new IterableLambdaEndpoint(); - lambda.queueManager = Mockito.mock(IngressQueueManager.class); - } + @Before + public void setup() { + lambda = new IterableLambdaEndpoint(); + lambda.queueManager = Mockito.mock(IngressQueueManager.class); + } - @Test - public void testProcessEventProcessingRequest() throws IOException { - InputStream input = readTestFixture("EventProcessingRequest_ios.json"); - ByteArrayOutputStream output = new ByteArrayOutputStream(); - Map expectedResponse = getFixtureAsMap("EventProcessingResponse.json"); - lambda.handleRequest(input, output, null); - Map lambdaResponse = - mapper.readValue(output.toString(), new TypeReference>() {}); - for (String key : expectedResponse.keySet()) { - assertNotNull(lambdaResponse.get(key)); + @Test + public void testProcessEventProcessingRequest() throws IOException { + InputStream input = readTestFixture("EventProcessingRequest_ios.json"); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + Map expectedResponse = getFixtureAsMap("EventProcessingResponse.json"); + lambda.handleRequest(input, output, null); + Map lambdaResponse = + mapper.readValue(output.toString(), new TypeReference>() {}); + for (String key : expectedResponse.keySet()) { + assertNotNull(lambdaResponse.get(key)); + } } - } - @Test - public void testProcessModuleRegistrationRequest() throws IOException { - InputStream input = readTestFixture("ModuleRegistrationRequest.json"); - Map expectedResponse = getFixtureAsMap("ModuleRegistrationResponse.json"); - ByteArrayOutputStream output = new ByteArrayOutputStream(); - lambda.handleRequest(input, output, null); - Map lambdaResponse = - mapper.readValue(output.toString(), new TypeReference>() {}); - for (String key : expectedResponse.keySet()) { - assertNotNull(lambdaResponse.get(key)); + @Test + public void testProcessModuleRegistrationRequest() throws IOException { + InputStream input = readTestFixture("ModuleRegistrationRequest.json"); + Map expectedResponse = getFixtureAsMap("ModuleRegistrationResponse.json"); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + lambda.handleRequest(input, output, null); + Map lambdaResponse = + mapper.readValue(output.toString(), new TypeReference>() {}); + for (String key : expectedResponse.keySet()) { + assertNotNull(lambdaResponse.get(key)); + } } - } - @Test - public void testProcessAudienceMembershipChangeRequest() throws IOException { - InputStream input = readTestFixture("AudienceMembershipChangeRequest.json"); - Map expectedResponse = getFixtureAsMap("AudienceMembershipChangeResponse.json"); - ByteArrayOutputStream output = new ByteArrayOutputStream(); - lambda.handleRequest(input, output, null); - Map lambdaResponse = - mapper.readValue(output.toString(), new TypeReference>() {}); - for (String key : expectedResponse.keySet()) { - assertNotNull(lambdaResponse.get(key)); + @Test + public void testProcessAudienceMembershipChangeRequest() throws IOException { + InputStream input = readTestFixture("AudienceMembershipChangeRequest.json"); + Map expectedResponse = + getFixtureAsMap("AudienceMembershipChangeResponse.json"); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + lambda.handleRequest(input, output, null); + Map lambdaResponse = + mapper.readValue(output.toString(), new TypeReference>() {}); + for (String key : expectedResponse.keySet()) { + assertNotNull(lambdaResponse.get(key)); + } } - } - private static Map getFixtureAsMap(String fileName) throws IOException { - InputStream fixture = readTestFixture(fileName); - Map fixtureMap = - mapper.readValue(fixture, new TypeReference>() {}); - return fixtureMap; - } + private static Map getFixtureAsMap(String fileName) throws IOException { + InputStream fixture = readTestFixture(fileName); + Map fixtureMap = + mapper.readValue(fixture, new TypeReference>() {}); + return fixtureMap; + } - private static InputStream readTestFixture(String fileName) throws IOException { - File initialFile = new File(PATH_TO_FIXTURES + fileName); - InputStream fixtureInputStream = new FileInputStream(initialFile); - return fixtureInputStream; - } + private static InputStream readTestFixture(String fileName) throws IOException { + File initialFile = new File(PATH_TO_FIXTURES + fileName); + InputStream fixtureInputStream = new FileInputStream(initialFile); + return fixtureInputStream; + } } diff --git a/iterable-java-sdk/build.gradle b/iterable-java-sdk/build.gradle index 64c3df9..8ca6cf4 100644 --- a/iterable-java-sdk/build.gradle +++ b/iterable-java-sdk/build.gradle @@ -1,8 +1,11 @@ +plugins { + id 'java' + id 'com.github.sherter.google-java-format' version '0.8' +} + group 'com.mparticle' version '1.0-SNAPSHOT' -apply plugin: 'java' - repositories { mavenCentral() } @@ -13,3 +16,9 @@ dependencies { testCompile('junit:junit:4.12') testCompile('org.mockito:mockito-core:1.10.19') } + +tasks.verifyGoogleJavaFormat.ignoreFailures = true + +googleJavaFormat { + options style: 'AOSP' +} \ No newline at end of file diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/ApiUser.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/ApiUser.java index d271f30..47d89e1 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/ApiUser.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/ApiUser.java @@ -1,9 +1,7 @@ package com.mparticle.iterable; - import java.util.Map; public class ApiUser extends UserRequest { public Map dataFields; - } diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/CommerceItem.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/CommerceItem.java index 68fc981..632e489 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/CommerceItem.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/CommerceItem.java @@ -11,9 +11,8 @@ public class CommerceItem { public String description; public List categories; public BigDecimal price; - //iterable will error if this is not present + // iterable will error if this is not present public Integer quantity = 1; public String imageUrl; public Map dataFields; - } diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/Device.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/Device.java index 6d3d259..80d1d81 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/Device.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/Device.java @@ -1,6 +1,5 @@ package com.mparticle.iterable; - import java.util.Map; public class Device { diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableErrorHandler.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableErrorHandler.java index d00e778..518810f 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableErrorHandler.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableErrorHandler.java @@ -3,9 +3,8 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; -import retrofit2.Response; - import java.io.IOException; +import retrofit2.Response; public class IterableErrorHandler { diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableRequest.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableRequest.java index 1c0c429..6b5937d 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableRequest.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableRequest.java @@ -5,16 +5,13 @@ public abstract class IterableRequest extends UserRequest { /** - * Time event happened. Set to the time event was received if unspecified. Expects a unix timestamp., + * Time event happened. Set to the time event was received if unspecified. Expects a unix + * timestamp., */ public Integer createdAt; - /** - * Additional data associated with event (i.e. item id, item amount), - */ + /** Additional data associated with event (i.e. item id, item amount), */ public Map dataFields; - /** - * Campaign tied to conversion - */ + /** Campaign tied to conversion */ public Integer campaignId; public Integer templateId; @@ -22,6 +19,4 @@ public abstract class IterableRequest extends UserRequest { public IterableRequest() { super(); } - - } diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableService.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableService.java index b7b081a..57e15c6 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableService.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/IterableService.java @@ -1,7 +1,7 @@ package com.mparticle.iterable; - - +import java.io.IOException; +import java.util.concurrent.TimeUnit; import okhttp3.*; import retrofit2.Call; import retrofit2.Retrofit; @@ -11,14 +11,10 @@ import retrofit2.http.POST; import retrofit2.http.Query; -import java.io.IOException; -import java.util.concurrent.TimeUnit; - /** * Iterable API defined here: * - * https://api.iterable.com/api/docs - * + *

https://api.iterable.com/api/docs */ public interface IterableService { @@ -27,35 +23,50 @@ public interface IterableService { long SERVICE_TIMEOUT_SECONDS = 60; @POST("api/events/track") - Call track(@Query(IterableService.PARAM_API_KEY) String apiKey, @Body TrackRequest trackRequest); + Call track( + @Query(IterableService.PARAM_API_KEY) String apiKey, @Body TrackRequest trackRequest); @POST("api/events/trackPushOpen") - Call trackPushOpen(@Query(IterableService.PARAM_API_KEY) String apiKey, @Body TrackPushOpenRequest registerRequest); + Call trackPushOpen( + @Query(IterableService.PARAM_API_KEY) String apiKey, + @Body TrackPushOpenRequest registerRequest); @POST("api/users/update") - Call userUpdate(@Query(IterableService.PARAM_API_KEY) String apiKey, @Body UserUpdateRequest trackRequest); + Call userUpdate( + @Query(IterableService.PARAM_API_KEY) String apiKey, + @Body UserUpdateRequest trackRequest); @POST("api/users/updateEmail") - Call updateEmail(@Query(IterableService.PARAM_API_KEY) String apiKey, @Body UpdateEmailRequest updateEmailRequest); + Call updateEmail( + @Query(IterableService.PARAM_API_KEY) String apiKey, + @Body UpdateEmailRequest updateEmailRequest); @POST("api/users/registerDeviceToken") - Call registerToken(@Query(IterableService.PARAM_API_KEY) String apiKey, @Body RegisterDeviceTokenRequest registerRequest); + Call registerToken( + @Query(IterableService.PARAM_API_KEY) String apiKey, + @Body RegisterDeviceTokenRequest registerRequest); @POST("api/lists/subscribe") - Call listSubscribe(@Query(IterableService.PARAM_API_KEY) String apiKey, @Body SubscribeRequest subscribeRequest); + Call listSubscribe( + @Query(IterableService.PARAM_API_KEY) String apiKey, + @Body SubscribeRequest subscribeRequest); @POST("api/lists/unsubscribe") - Call listUnsubscribe(@Query(IterableService.PARAM_API_KEY) String apiKey, @Body UnsubscribeRequest unsubscribeRequest); + Call listUnsubscribe( + @Query(IterableService.PARAM_API_KEY) String apiKey, + @Body UnsubscribeRequest unsubscribeRequest); @POST("api/commerce/trackPurchase") - Call trackPurchase(@Query(IterableService.PARAM_API_KEY) String apiKey, @Body TrackPurchaseRequest purchaseRequest); + Call trackPurchase( + @Query(IterableService.PARAM_API_KEY) String apiKey, + @Body TrackPurchaseRequest purchaseRequest); @POST("api/users/updateSubscriptions") - Call updateSubscriptions(@Query(IterableService.PARAM_API_KEY) String apiKey, @Body UpdateSubscriptionsRequest userUpdateRequest); + Call updateSubscriptions( + @Query(IterableService.PARAM_API_KEY) String apiKey, + @Body UpdateSubscriptionsRequest userUpdateRequest); - /** - * At the moment this is only used for unit testing the list subscribe/unsubscribe API calls - */ + /** At the moment this is only used for unit testing the list subscribe/unsubscribe API calls */ @GET("api/lists") Call lists(); @@ -63,28 +74,27 @@ class HeadersInterceptor implements Interceptor { @Override public Response intercept(Interceptor.Chain chain) throws IOException { Request original = chain.request(); - Request requestWithHeaders = original.newBuilder() - .header("User-Agent", "mparticle-lambda") - .build(); + Request requestWithHeaders = + original.newBuilder().header("User-Agent", "mparticle-lambda").build(); return chain.proceed(requestWithHeaders); } } static IterableService newInstance() { - final OkHttpClient client = new OkHttpClient.Builder() - .addInterceptor(new HeadersInterceptor()) - .connectTimeout(SERVICE_TIMEOUT_SECONDS, TimeUnit.SECONDS) - .readTimeout(SERVICE_TIMEOUT_SECONDS, TimeUnit.SECONDS) - .build(); - final HttpUrl url = new HttpUrl.Builder() - .scheme("https") - .host(IterableService.HOST) - .build(); - final Retrofit retrofit = new Retrofit.Builder() - .baseUrl(url) - .client(client) - .addConverterFactory(GsonConverterFactory.create()) - .build(); + final OkHttpClient client = + new OkHttpClient.Builder() + .addInterceptor(new HeadersInterceptor()) + .connectTimeout(SERVICE_TIMEOUT_SECONDS, TimeUnit.SECONDS) + .readTimeout(SERVICE_TIMEOUT_SECONDS, TimeUnit.SECONDS) + .build(); + final HttpUrl url = + new HttpUrl.Builder().scheme("https").host(IterableService.HOST).build(); + final Retrofit retrofit = + new Retrofit.Builder() + .baseUrl(url) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .build(); return retrofit.create(IterableService.class); } -} \ No newline at end of file +} diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/ListResponse.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/ListResponse.java index 2d23d8a..596f65d 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/ListResponse.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/ListResponse.java @@ -1,6 +1,5 @@ package com.mparticle.iterable; - public class ListResponse { public int successCount = -1; public int failCount = -1; diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/RegisterDeviceTokenRequest.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/RegisterDeviceTokenRequest.java index fa8718b..abef08b 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/RegisterDeviceTokenRequest.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/RegisterDeviceTokenRequest.java @@ -1,6 +1,5 @@ package com.mparticle.iterable; - public class RegisterDeviceTokenRequest extends UserRequest { public boolean preferUserId; public Device device; diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/SubscribeRequest.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/SubscribeRequest.java index a28373f..4019d16 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/SubscribeRequest.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/SubscribeRequest.java @@ -1,6 +1,5 @@ package com.mparticle.iterable; - import java.util.List; public class SubscribeRequest { diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackPurchaseRequest.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackPurchaseRequest.java index 8ad3f1e..afa2dd0 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackPurchaseRequest.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackPurchaseRequest.java @@ -1,15 +1,16 @@ package com.mparticle.iterable; - import java.math.BigDecimal; import java.util.List; import java.util.Map; public class TrackPurchaseRequest { /** - * Optional purchase id. If a purchase event already exists with this id, the event will be updated. + * Optional purchase id. If a purchase event already exists with this id, the event will be + * updated. */ public String id; + public ApiUser user; public List items; public Integer campaignId; diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackPushOpenRequest.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackPushOpenRequest.java index c9ca5dc..61bb395 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackPushOpenRequest.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackPushOpenRequest.java @@ -3,5 +3,4 @@ public class TrackPushOpenRequest extends IterableRequest { public String messageId; - } diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackRequest.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackRequest.java index 066ce9b..231a7de 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackRequest.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/TrackRequest.java @@ -7,24 +7,19 @@ public class TrackRequest extends UserRequest { /** * Required * - * Name of event, + *

Name of event, */ private String eventName; /** - * Time event happened. Set to the time event was received if unspecified. Expects a unix timestamp. + * Time event happened. Set to the time event was received if unspecified. Expects a unix + * timestamp. */ public Integer createdAt; - /** - * Optional event id. If an event already exists with this id, the event will be updated. - */ + /** Optional event id. If an event already exists with this id, the event will be updated. */ public String id; - /** - * Additional data associated with event (i.e. item id, item amount), - */ + /** Additional data associated with event (i.e. item id, item amount), */ public Map dataFields; - /** - * Campaign tied to conversion - */ + /** Campaign tied to conversion */ public Integer campaignId; public Integer templateId; diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/UpdateEmailRequest.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/UpdateEmailRequest.java index 7781d8b..ef16ea8 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/UpdateEmailRequest.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/UpdateEmailRequest.java @@ -1,8 +1,6 @@ package com.mparticle.iterable; -/** - * Created by sdozor on 10/12/15. - */ +/** Created by sdozor on 10/12/15. */ public class UpdateEmailRequest { public String currentEmail; public String currentUserId; diff --git a/iterable-java-sdk/src/main/java/com/mparticle/iterable/UserRequest.java b/iterable-java-sdk/src/main/java/com/mparticle/iterable/UserRequest.java index 8f84583..509a25f 100644 --- a/iterable-java-sdk/src/main/java/com/mparticle/iterable/UserRequest.java +++ b/iterable-java-sdk/src/main/java/com/mparticle/iterable/UserRequest.java @@ -2,12 +2,14 @@ public abstract class UserRequest { /** - * Either email or userId must be passed in to identify the user. If both are passed in, email takes precedence. + * Either email or userId must be passed in to identify the user. If both are passed in, email + * takes precedence. */ public String email; /** - * Optional userId, typically your database generated id. Either email or userId must be specified. + * Optional userId, typically your database generated id. Either email or userId must be + * specified. */ public String userId; } diff --git a/iterable-java-sdk/src/test/java/com/mparticle/iterable/IterableServiceTest.java b/iterable-java-sdk/src/test/java/com/mparticle/iterable/IterableServiceTest.java index 285796a..b49f9a0 100644 --- a/iterable-java-sdk/src/test/java/com/mparticle/iterable/IterableServiceTest.java +++ b/iterable-java-sdk/src/test/java/com/mparticle/iterable/IterableServiceTest.java @@ -1,5 +1,10 @@ package com.mparticle.iterable; +import static org.junit.Assert.*; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.*; import okhttp3.MediaType; import okhttp3.ResponseBody; import org.junit.Before; @@ -8,25 +13,20 @@ import retrofit2.Call; import retrofit2.Response; -import java.io.IOException; -import java.math.BigDecimal; -import java.util.*; - -import static org.junit.Assert.*; - /** - * This is an *integration* test, testing: - * 1. Model serialization/deserialization - * 2. Iterable service authentication - *

- * If there's no API key specified in setup, these tests aren't particularly useful - nearly everything will be mocked. + * This is an *integration* test, testing: 1. Model serialization/deserialization 2. Iterable + * service authentication + * + *

If there's no API key specified in setup, these tests aren't particularly useful - nearly + * everything will be mocked. */ public class IterableServiceTest { private static final String TEST_EMAIL = "testing@mparticle.com"; private static final String TEST_USER_ID = "123456"; - private static final String ITERABLE_API_KEY = ""; //put your API key here - private static final String ERROR_JSON = "{\"code\":\"BadApiKey\",\"msg\":\"No API key found on request\",\"params\":{\"endpoint\":\"\\/api\\/events\\/track\",\"ip\": \"45.29.69.159\"}}"; + private static final String ITERABLE_API_KEY = ""; // put your API key here + private static final String ERROR_JSON = + "{\"code\":\"BadApiKey\",\"msg\":\"No API key found on request\",\"params\":{\"endpoint\":\"\\/api\\/events\\/track\",\"ip\": \"45.29.69.159\"}}"; private IterableService iterableService; @@ -39,8 +39,7 @@ public void setUp() throws Exception { Call callMock = Mockito.mock(Call.class); Mockito.when(iterableService.userUpdate(Mockito.any(), Mockito.any())) .thenReturn(callMock); - Mockito.when(iterableService.track(Mockito.any(),Mockito.any())) - .thenReturn(callMock); + Mockito.when(iterableService.track(Mockito.any(), Mockito.any())).thenReturn(callMock); Mockito.when(iterableService.registerToken(Mockito.any(), Mockito.any())) .thenReturn(callMock); Mockito.when(iterableService.trackPushOpen(Mockito.any(), Mockito.any())) @@ -73,9 +72,17 @@ public void testTrack() throws Exception { TrackRequest trackRequest = new TrackRequest("Test Event"); trackRequest.email = TEST_EMAIL; trackRequest.userId = TEST_USER_ID; - Response response = iterableService.track(ITERABLE_API_KEY, trackRequest).execute(); - assertTrue("Retrofit request not successful:\nMessage: " + response.message() + "\nCode: " + response.code(), response.isSuccessful()); - assertTrue("Iterable response was not successful:\n" + response.body().toString(), response.body().isSuccess()); + Response response = + iterableService.track(ITERABLE_API_KEY, trackRequest).execute(); + assertTrue( + "Retrofit request not successful:\nMessage: " + + response.message() + + "\nCode: " + + response.code(), + response.isSuccessful()); + assertTrue( + "Iterable response was not successful:\n" + response.body().toString(), + response.body().isSuccess()); } @org.junit.Test @@ -83,14 +90,25 @@ public void testTrackPushOpen() throws Exception { TrackPushOpenRequest pushOpenRequest = new TrackPushOpenRequest(); pushOpenRequest.email = TEST_EMAIL; pushOpenRequest.userId = TEST_USER_ID; - pushOpenRequest.campaignId = 17703; //this correlates to the "Test Campaign" set up in Iterable - pushOpenRequest.messageId= "eac02374a90d46a2901cea2f52edbd70"; // This needs to be a valid messageId in the project you're testing. + pushOpenRequest.campaignId = + 17703; // this correlates to the "Test Campaign" set up in Iterable + pushOpenRequest.messageId = + "eac02374a90d46a2901cea2f52edbd70"; // This needs to be a valid messageId in the + // project you're testing. Map attributes = new HashMap(); attributes.put("test push open attribute key", "test push open attribute value"); pushOpenRequest.dataFields = attributes; - Response response = iterableService.trackPushOpen(ITERABLE_API_KEY, pushOpenRequest).execute(); - assertTrue("Retrofit request not successful:\nMessage: " + response.message() + "\nCode: " + response.code(), response.isSuccessful()); - assertTrue("Iterable response was not successful:\n" + response.body().toString(), response.body().isSuccess()); + Response response = + iterableService.trackPushOpen(ITERABLE_API_KEY, pushOpenRequest).execute(); + assertTrue( + "Retrofit request not successful:\nMessage: " + + response.message() + + "\nCode: " + + response.code(), + response.isSuccessful()); + assertTrue( + "Iterable response was not successful:\n" + response.body().toString(), + response.body().isSuccess()); } @org.junit.Test @@ -105,9 +123,17 @@ public void testUserUpdate() throws Exception { attributes.put("test double key", 1234.56D); userUpdateRequest.dataFields = attributes; - Response response = iterableService.userUpdate(ITERABLE_API_KEY, userUpdateRequest).execute(); - assertTrue("Retrofit request not successful:\nMessage: " + response.message() + "\nCode: " + response.code(), response.isSuccessful()); - assertTrue("Iterable response was not successful:\n" + response.body().toString(), response.body().isSuccess()); + Response response = + iterableService.userUpdate(ITERABLE_API_KEY, userUpdateRequest).execute(); + assertTrue( + "Retrofit request not successful:\nMessage: " + + response.message() + + "\nCode: " + + response.code(), + response.isSuccessful()); + assertTrue( + "Iterable response was not successful:\n" + response.body().toString(), + response.body().isSuccess()); } @org.junit.Test @@ -118,9 +144,17 @@ public void testRegisterToken() throws Exception { registerRequest.device.platform = Device.PLATFORM_GCM; registerRequest.device.applicationName = "test"; registerRequest.device.token = "thisisatestGCMtoken"; - Response response = iterableService.registerToken(ITERABLE_API_KEY, registerRequest).execute(); - assertTrue("Retrofit request not successful:\nMessage: " + response.message() + "\nCode: " + response.code(), response.isSuccessful()); - assertTrue("Iterable response was not successful:\n" + response.body().toString(), response.body().isSuccess()); + Response response = + iterableService.registerToken(ITERABLE_API_KEY, registerRequest).execute(); + assertTrue( + "Retrofit request not successful:\nMessage: " + + response.message() + + "\nCode: " + + response.code(), + response.isSuccessful()); + assertTrue( + "Iterable response was not successful:\n" + response.body().toString(), + response.body().isSuccess()); } @org.junit.Test @@ -148,9 +182,20 @@ public void testListSubscribe() throws Exception { subscribeRequest.subscribers.add(user1); subscribeRequest.subscribers.add(user2); - Response response = iterableService.listSubscribe(ITERABLE_API_KEY, subscribeRequest).execute(); - assertTrue("Retrofit request not successful:\nMessage: " + response.message() + "\nCode: " + response.code(), response.isSuccessful()); - assertTrue("Iterable response was not successful:\nSuccess Count: " + response.body().successCount + "\nFail Count: " + response.body().failCount, response.body().failCount < 1); + Response response = + iterableService.listSubscribe(ITERABLE_API_KEY, subscribeRequest).execute(); + assertTrue( + "Retrofit request not successful:\nMessage: " + + response.message() + + "\nCode: " + + response.code(), + response.isSuccessful()); + assertTrue( + "Iterable response was not successful:\nSuccess Count: " + + response.body().successCount + + "\nFail Count: " + + response.body().failCount, + response.body().failCount < 1); } @org.junit.Test @@ -162,10 +207,19 @@ public void testListUnsubscribe() throws Exception { user.userId = "newtestsubscriber"; unsubscribeRequest.subscribers = new LinkedList<>(); unsubscribeRequest.subscribers.add(user); - Response response = iterableService.listUnsubscribe(ITERABLE_API_KEY, unsubscribeRequest).execute(); - assertTrue("Retrofit request not successful:\nMessage: " + response.message() + "\nCode: " + response.code(), response.isSuccessful()); - //just check for 200 since it's not feasible in an automated test to wait for Iterable to update its lists such an an unsubscribe will always work. - // assertTrue("Iterable response was not successful:\nSuccess Count: " + response.body().successCount + "\nFail Count: " + response.body().failCount, response.body().failCount < 1); + Response response = + iterableService.listUnsubscribe(ITERABLE_API_KEY, unsubscribeRequest).execute(); + assertTrue( + "Retrofit request not successful:\nMessage: " + + response.message() + + "\nCode: " + + response.code(), + response.isSuccessful()); + // just check for 200 since it's not feasible in an automated test to wait for Iterable to + // update its lists such an an unsubscribe will always work. + // assertTrue("Iterable response was not successful:\nSuccess Count: " + + // response.body().successCount + "\nFail Count: " + response.body().failCount, + // response.body().failCount < 1); } @org.junit.Test @@ -184,28 +238,46 @@ public void testTrackPurchase() throws Exception { item.name = "test product name"; request.items.add(item); request.total = new BigDecimal(100d); - Response response = iterableService.trackPurchase(ITERABLE_API_KEY, request).execute(); - assertTrue("Retrofit request not successful:\nMessage: " + response.message() + "\nCode: " + response.code(), response.isSuccessful()); - assertTrue("Iterable response was not successful:\n" + response.body().toString(), response.body().isSuccess()); + Response response = + iterableService.trackPurchase(ITERABLE_API_KEY, request).execute(); + assertTrue( + "Retrofit request not successful:\nMessage: " + + response.message() + + "\nCode: " + + response.code(), + response.isSuccessful()); + assertTrue( + "Iterable response was not successful:\n" + response.body().toString(), + response.body().isSuccess()); } @Test public void testUpdateSubscriptions() throws Exception { UpdateSubscriptionsRequest request = new UpdateSubscriptionsRequest(); request.email = TEST_EMAIL; - request.unsubscribedChannelIds = Arrays.asList(1,2,3); - request.unsubscribedMessageTypeIds = Arrays.asList(1,2,3); - request.emailListIds = Arrays.asList(1,2,3); - Response response = iterableService.updateSubscriptions(ITERABLE_API_KEY, request).execute(); - assertTrue("Retrofit request not successful:\nMessage: " + response.message() + "\nCode: " + response.code(), response.isSuccessful()); - assertTrue("Iterable response was not successful:\n" + response.body().toString(), response.body().isSuccess()); - + request.unsubscribedChannelIds = Arrays.asList(1, 2, 3); + request.unsubscribedMessageTypeIds = Arrays.asList(1, 2, 3); + request.emailListIds = Arrays.asList(1, 2, 3); + Response response = + iterableService.updateSubscriptions(ITERABLE_API_KEY, request).execute(); + assertTrue( + "Retrofit request not successful:\nMessage: " + + response.message() + + "\nCode: " + + response.code(), + response.isSuccessful()); + assertTrue( + "Iterable response was not successful:\n" + response.body().toString(), + response.body().isSuccess()); } @Test public void testParseIterableError() throws IOException { - Response testErrorResponse = Response.error(400, ResponseBody.create( - MediaType.parse("application/json; charset=utf-8"), ERROR_JSON)); + Response testErrorResponse = + Response.error( + 400, + ResponseBody.create( + MediaType.parse("application/json; charset=utf-8"), ERROR_JSON)); IterableApiResponse error = IterableErrorHandler.parseError(testErrorResponse); assertEquals("BadApiKey", error.code); assertEquals("No API key found on request", error.msg); @@ -214,8 +286,12 @@ public void testParseIterableError() throws IOException { @Test(expected = IOException.class) public void testParseMalformedIterableError() throws IOException { - Response testErrorResponse = Response.error(400, ResponseBody.create( - MediaType.parse("application/json; charset=utf-8"), "

that's not JSON

")); + Response testErrorResponse = + Response.error( + 400, + ResponseBody.create( + MediaType.parse("application/json; charset=utf-8"), + "

that's not JSON

")); IterableApiResponse error = IterableErrorHandler.parseError(testErrorResponse); assertNotNull(error); }