diff --git a/Documentation/api-reference.md b/Documentation/api-reference.md index 58133b3..ac8168e 100644 --- a/Documentation/api-reference.md +++ b/Documentation/api-reference.md @@ -381,8 +381,8 @@ TargetRequest request2 = new TargetRequest("mboxName2", parameters2, "defaultCon // and click metric analytics payload, if available if (data != null && !data.isEmpty()) { - Map responseTokens = data.containsKey("responseTokens") ? - (Map) data.get("responseTokens") : + Map responseTokens = data.containsKey("responseTokens") ? + (Map) data.get("responseTokens") : null; Map analyticsPayload = data.containsKey("analytics.payload") ? diff --git a/code/gradle.properties b/code/gradle.properties index 42ebeed..de85860 100644 --- a/code/gradle.properties +++ b/code/gradle.properties @@ -28,7 +28,7 @@ android.useAndroidX=true moduleProjectName=target moduleName=target moduleAARName=target-phone-release.aar -moduleVersion=2.0.2 +moduleVersion=2.0.3 mavenRepoName=AdobeMobileTargetSdk mavenRepoDescription=Adobe Experience Platform Target extension for the Adobe Experience Platform Mobile SDK diff --git a/code/target/src/androidTest/java/com/adobe/marketing/mobile/target/TargetTestConstants.java b/code/target/src/androidTest/java/com/adobe/marketing/mobile/target/TargetTestConstants.java index 2b8d875..c71fdc0 100644 --- a/code/target/src/androidTest/java/com/adobe/marketing/mobile/target/TargetTestConstants.java +++ b/code/target/src/androidTest/java/com/adobe/marketing/mobile/target/TargetTestConstants.java @@ -14,7 +14,7 @@ public class TargetTestConstants { - static final String EXTENSION_VERSION = "2.0.2"; + static final String EXTENSION_VERSION = "2.0.3"; public final static class EventType { public static final String TARGET = "com.adobe.eventType.target"; diff --git a/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetExtension.java b/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetExtension.java index 1e56145..1108f61 100644 --- a/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetExtension.java +++ b/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetExtension.java @@ -1022,7 +1022,7 @@ List processCachedTargetRequest(final List batchRe final String content = targetResponseParser.extractMboxContent(cachedMboxJson); final Map a4tParams = targetResponseParser.getAnalyticsForTargetPayload(cachedMboxJson); - final Map responseTokens = targetResponseParser.getResponseTokens(cachedMboxJson); + final Map responseTokens = targetResponseParser.getResponseTokens(cachedMboxJson); final Map clickMetricA4TParams = targetResponseParser.extractClickMetricAnalyticsPayload( cachedMboxJson); @@ -1107,7 +1107,7 @@ private void processTargetRequestResponse(final List batchRequest final JSONObject mboxJson = batchedMboxes.get(targetRequest.getMboxName()); final String content = targetResponseParser.extractMboxContent(mboxJson); - final Map responseTokens = targetResponseParser.getResponseTokens(mboxJson); + final Map responseTokens = targetResponseParser.getResponseTokens(mboxJson); final Map clickMetricA4TParams = targetResponseParser.extractClickMetricAnalyticsPayload(mboxJson); final Map a4tParams = targetResponseParser.getAnalyticsForTargetPayload(mboxJson); @@ -1325,7 +1325,7 @@ private void dispatchMboxPrefetchResult(final String error, final Event event) { void dispatchMboxContent(final String content, final Map a4tParams, final Map clickMetricA4TParams, - final Map responseTokens, + final Map responseTokens, final String pairId, final Event event) { final Map data = new HashMap<>(); diff --git a/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetResponseParser.java b/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetResponseParser.java index dc28f0a..c4d4acd 100644 --- a/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetResponseParser.java +++ b/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetResponseParser.java @@ -292,9 +292,9 @@ Map getAnalyticsForTargetPayload(final JSONObject json) { * Parse the Mbox JSON object to read Response Tokens from the Options. The data will be read from the first option in the options list. * * @param mboxJson Mbox {@link JSONObject} - * @return Response Tokens from options payload as {@code Map} OR null if Response Tokens are not activated on Target. + * @return Response tokens from options payload as {@code Map}, or null if response tokens are not activated on Target. */ - Map getResponseTokens(final JSONObject mboxJson) { + Map getResponseTokens(final JSONObject mboxJson) { if (mboxJson == null) { return null; } @@ -319,7 +319,14 @@ Map getResponseTokens(final JSONObject mboxJson) { return null; } - return TargetUtils.toStringMap(responseTokens); + Map responseTokensMap = null; + try { + responseTokensMap = JSONUtils.toMap(responseTokens); + } catch (final JSONException e) { + Log.debug(TargetConstants.LOG_TAG, CLASS_NAME, + "Exception (%s) is thrown when parsing response tokens to create an object Map.", e); + } + return responseTokensMap; } /** diff --git a/code/target/src/phone/java/com/adobe/marketing/mobile/Target.java b/code/target/src/phone/java/com/adobe/marketing/mobile/Target.java index 51d1e0e..04605db 100644 --- a/code/target/src/phone/java/com/adobe/marketing/mobile/Target.java +++ b/code/target/src/phone/java/com/adobe/marketing/mobile/Target.java @@ -44,7 +44,7 @@ public class Target { static final String LOG_TAG = "Target"; private static final String CLASS_NAME = "Target"; - static final String EXTENSION_VERSION = "2.0.2"; + static final String EXTENSION_VERSION = "2.0.3"; static final class EventName { static final String PREFETCH_REQUEST = "TargetPrefetchRequest"; @@ -885,7 +885,8 @@ private static Map createMboxPayloadMap(final Map responseTokens = DataReader.optStringMap(data, + final Map responseTokens = DataReader.optTypedMap(Object.class, + data, EventDataKeys.RESPONSE_TOKENS, null); if (responseTokens != null) { diff --git a/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetExtensionTests.java b/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetExtensionTests.java index cc99175..bee86e5 100644 --- a/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetExtensionTests.java +++ b/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetExtensionTests.java @@ -60,6 +60,8 @@ import java.net.HttpURLConnection; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -70,38 +72,38 @@ public class TargetExtensionTests { // Mock Constants - private static String MOCKED_CLIENT_CODE = "clientCode"; - private static String MOCKED_TARGET_SERVER = "targetServer"; - private static String MOCK_EDGE_HOST = "mboxedge35.tt.omtrdc.net"; - private static String MOCK_THIRD_PARTY_ID = "thirdPartyId"; - private static String MOCK_THIRD_PARTY_ID_1 = "thirdPartyID_1"; - private static String MOCK_TNT_ID = "66E5C681-4F70-41A2-86AE-F1E151443B10.35_0"; - private static String MOCK_TNT_ID_1 = "66E5C681-4F70-41A2-86AE-F1E151443B10.32_0"; - private static String MOCK_TNT_ID_2 = "4DBCC39D-4ACA-47D4-A7D2-A85C1C0CC382.32_0"; - private static String MOCK_TNT_ID_INVALID = "66E5C681-4F70-41A2-86AE-F1E151443B10.a1a_0"; - private static String MOCK_SESSION_ID = "mockSessionID"; - private static Integer MOCK_NETWORK_TIMEOUT = 5; - - private static HashMap targetParameters = new HashMap() { + private static final String MOCKED_CLIENT_CODE = "clientCode"; + private static final String MOCKED_TARGET_SERVER = "targetServer"; + private static final String MOCK_EDGE_HOST = "mboxedge35.tt.omtrdc.net"; + private static final String MOCK_THIRD_PARTY_ID = "thirdPartyId"; + private static final String MOCK_THIRD_PARTY_ID_1 = "thirdPartyID_1"; + private static final String MOCK_TNT_ID = "66E5C681-4F70-41A2-86AE-F1E151443B10.35_0"; + private static final String MOCK_TNT_ID_1 = "66E5C681-4F70-41A2-86AE-F1E151443B10.32_0"; + private static final String MOCK_TNT_ID_2 = "4DBCC39D-4ACA-47D4-A7D2-A85C1C0CC382.32_0"; + private static final String MOCK_TNT_ID_INVALID = "66E5C681-4F70-41A2-86AE-F1E151443B10.a1a_0"; + private static final String MOCK_SESSION_ID = "mockSessionID"; + private static final Integer MOCK_NETWORK_TIMEOUT = 5; + + private static final HashMap targetParameters = new HashMap() { { put("paramKey", "paramValue"); } }; - private static HashMap targetSharedState = new HashMap() { + private static final HashMap targetSharedState = new HashMap() { { put("tntid", MOCK_TNT_ID); put("sessionid", MOCK_SESSION_ID); } }; - private static HashMap lifecycleSharedState = new HashMap() { + private static final HashMap lifecycleSharedState = new HashMap() { { put("lifecycleKey", "lifecycleValue"); } }; - private static HashMap identitySharedState = new HashMap() { + private static final HashMap identitySharedState = new HashMap() { { put("mid", "samplemid"); put("blob", "sampleBlob"); @@ -109,7 +111,7 @@ public class TargetExtensionTests { } }; - private static HashMap eventHubSharedState = new HashMap() { + private static final HashMap eventHubSharedState = new HashMap() { { put("version", "x.y.z"); put("wrapper", new HashMap() { @@ -121,16 +123,28 @@ public class TargetExtensionTests { } }; - private static Map responseTokens = new HashMap() {{ + private static final Map responseTokens = new HashMap() {{ put("responseTokens.Key", "responseTokens.Value"); + put("profile.categoryAffinities", new ArrayList(){ + { + add("books"); + } + }); + put("someKey", new ArrayList(){ + { + add("someValue"); + add(true); + add(42); + } + }); }}; - private static Map clickMetricA4TParams = new HashMap() {{ + private static final Map clickMetricA4TParams = new HashMap() {{ put("pe", "tnt"); put("tnta", "1234|1234"); }}; - private static Map a4tParams = new HashMap() {{ + private static final Map a4tParams = new HashMap() {{ put("pe", "tnt"); put("tnta", "1234|1234"); }}; @@ -233,7 +247,7 @@ public void test_getFriendlyName() { public void test_getVersion() { // test final String extensionVersion = extension.getVersion(); - assertEquals("getVersion should return the correct extension version.", "2.0.2", extensionVersion); + assertEquals("getVersion should return the correct extension version.", "2.0.3", extensionVersion); } //********************************************************************************************** @@ -618,7 +632,15 @@ public void testLoadRequests_whenValidResponse() throws Exception { // verify the dispatched mbox content event assertEquals("mbox0content", extractMboxContentFromEvent(mboxContentEvent)); - assertEquals(responseTokens, extractResponseToken(mboxContentEvent)); + final Map responseTokens = extractResponseToken(mboxContentEvent); + assertEquals(3, responseTokens.size()); + assertEquals("responseTokens.Value", responseTokens.get("responseTokens.Key")); + assertEquals(new ArrayList(Collections.singletonList("books")), responseTokens.get("profile.categoryAffinities")); + final List someList = (List)responseTokens.get("someKey"); + assertEquals(3, someList.size()); + assertEquals("someValue", someList.get(0)); + assertTrue((Boolean)someList.get(1)); + assertEquals(42, (int)someList.get(2)); assertEquals(a4tParams, extractAnalyticsPayload(mboxContentEvent)); assertEquals(clickMetricA4TParams, extractClickMetric(mboxContentEvent)); } @@ -1962,7 +1984,6 @@ public void testHandleConfigurationResponseContentEvent_whenPrivacyOptedOut() { // verify verify(targetState, times(2)).updateEdgeHost(null); verify(targetState).resetSession(); - ; verify(targetState).updateTntId(null); verify(targetState).updateThirdPartyId(null); verify(mockExtensionApi).createSharedState(eq(targetSharedState), eq(event)); @@ -2135,12 +2156,11 @@ Map getTargetRawRequestForNotifications(int count) { for (int i = 0; i < count; i++) { final String notificationId = String.valueOf(i); - ; final String mboxName = "mbox" + i; final Map notification = new HashMap() { { put("id", notificationId); - put("timestamp", (long) (System.currentTimeMillis())); + put("timestamp", System.currentTimeMillis()); put("type", "click"); put("mbox", new HashMap() { { @@ -2424,7 +2444,7 @@ private String extractMboxContentFromEvent(final Event event) { ""); } - private Map extractResponseToken(final Event event) { + private Map extractResponseToken(final Event event) { Map data = DataReader.optTypedMap(Map.class, event.getEventData(), EventDataKeys.TARGET_DATA_PAYLOAD, null); return data.get(EventDataKeys.RESPONSE_TOKENS); } diff --git a/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetResponseParserTest.java b/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetResponseParserTest.java index 90f3c71..246c8bb 100644 --- a/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetResponseParserTest.java +++ b/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetResponseParserTest.java @@ -20,12 +20,15 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import static org.junit.Assert.*; import com.adobe.marketing.mobile.services.HttpConnecting; +import com.adobe.marketing.mobile.util.JSONUtils; import com.adobe.marketing.mobile.util.StreamUtils; public class TargetResponseParserTest { @@ -758,6 +761,7 @@ public void testExtractResponseTokens_Will_Return_Valid_Map_When_Response_Tokens " \"responseTokens\":{\n" + " \"geo.connectionSpeed\":\"broadband\",\n" + " \"geo.state\":\"california\",\n" + + " \"profile.categoryAffinities\":[\"shoes\"],\n" + " },\n" + " \"sourceType\":\"target\"\n" + " }\n" + @@ -773,12 +777,13 @@ public void testExtractResponseTokens_Will_Return_Valid_Map_When_Response_Tokens final JSONObject mBoxPayloadObject = new JSONObject(mboxPayload); //Assertions - Map responseTokens = responseParser.getResponseTokens(mBoxPayloadObject); + Map responseTokens = responseParser.getResponseTokens(mBoxPayloadObject); assertNotNull(responseTokens); - assertEquals(2, responseTokens.size()); + assertEquals(3, responseTokens.size()); assertEquals("broadband", responseTokens.get("geo.connectionSpeed")); assertEquals("california", responseTokens.get("geo.state")); + assertEquals(new ArrayList(Arrays.asList("shoes")), responseTokens.get("profile.categoryAffinities")); } @Test @@ -807,10 +812,62 @@ public void testExtractResponseTokens_Will_Return_Null_When_response_Tokens_Payl final JSONObject mBoxPayloadObject = new JSONObject(mboxPayload); //Assertions - Map responseTokens = responseParser.getResponseTokens(mBoxPayloadObject); + Map responseTokens = responseParser.getResponseTokens(mBoxPayloadObject); assertNull(responseTokens); } + @Test + public void testExtractResponseTokens_Will_Return_Null_When_Mbox_Payload_Is_Null() throws JSONException { + // setup + final JSONObject mBoxPayloadObject = null; + + // test + Map responseTokens = responseParser.getResponseTokens(mBoxPayloadObject); + + // verify + assertNull(responseTokens); + } + + @Test + public void testExtractResponseTokens_Will_Return_Null_When_Response_Tokens_Payload_Is_Invalid() throws JSONException { + try (MockedStatic jsonUtilsMock = Mockito.mockStatic(JSONUtils.class)) { + // setup + jsonUtilsMock.when(() -> JSONUtils.toMap(Mockito.any())) + .thenThrow(new JSONException("Invalid JSON")); + + final String mboxPayload = "{\n" + + " \"index\":0,\n" + + " \"name\":\"ryan_a4t2\",\n" + + " \"options\":[\n" + + " {\n" + + " \"content\":{\n" + + " \"key2\":\"value2\"\n" + + " },\n" + + " \"type\":\"json\",\n" + + " \"responseTokens\":{\n" + + " \"geo.connectionSpeed\":\"broadband\"\n" + + " },\n" + + " \"sourceType\":\"target\"\n" + + " }\n" + + " ],\n" + + " \"analytics\":{\n" + + " \"payload\":{\n" + + " \"pe\":\"tnt\",\n" + + " \"tnta\":\"333911:0:0:0|2|4445.12,333911:0:0:0|1|4445.12\"\n" + + " }\n" + + " }\n" + + "}"; + + final JSONObject mBoxPayloadObject = new JSONObject(mboxPayload); + + // test + Map responseTokens = responseParser.getResponseTokens(mBoxPayloadObject); + + // verify + assertNull(responseTokens); + } + } + // ===================================== // Test extract Click Metric A4T Params // ===================================== diff --git a/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetTests.java b/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetTests.java index 516fa94..f7b9e02 100644 --- a/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetTests.java +++ b/code/target/src/test/java/com/adobe/marketing/mobile/target/TargetTests.java @@ -72,7 +72,7 @@ public void teardown() { public void test_extensionVersion() { // test final String extensionVersion = Target.extensionVersion(); - assertEquals("extensionVersion API should return the correct version string.", "2.0.2", + assertEquals("extensionVersion API should return the correct version string.", "2.0.3", extensionVersion); } diff --git a/code/testapp/build.gradle b/code/testapp/build.gradle index b8f9847..f67bd27 100644 --- a/code/testapp/build.gradle +++ b/code/testapp/build.gradle @@ -44,10 +44,10 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation project(':target') - implementation 'com.adobe.marketing.mobile:core:2.5.0' + implementation 'com.adobe.marketing.mobile:core:2.6.1' implementation 'com.adobe.marketing.mobile:identity:2.0.3' implementation 'com.adobe.marketing.mobile:lifecycle:2.0.4' - implementation 'com.adobe.marketing.mobile:assurance:2.1.1' + implementation 'com.adobe.marketing.mobile:assurance:2.2.0' implementation 'androidx.appcompat:appcompat:1.6.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' diff --git a/code/testapp/src/main/java/com/adobe/targettestapp/MboxPayload.java b/code/testapp/src/main/java/com/adobe/targettestapp/MboxPayload.java index 10f86f4..d69bc24 100644 --- a/code/testapp/src/main/java/com/adobe/targettestapp/MboxPayload.java +++ b/code/testapp/src/main/java/com/adobe/targettestapp/MboxPayload.java @@ -20,7 +20,7 @@ class MboxPayload { private String content = ""; private final Map a4tParams; private final Map clickMetricA4tParams; - private final Map responseTokens; + private final Map responseTokens; public MboxPayload(final String content, final Map payload) { if (content != null) { @@ -33,7 +33,7 @@ public MboxPayload(final String content, final Map payload) { this.clickMetricA4tParams = payload.containsKey("clickmetric.analytics.payload") ? (Map) payload.get("clickmetric.analytics.payload") : null; - this.responseTokens = payload.containsKey("responseTokens") ? (Map) payload.get("responseTokens") : + this.responseTokens = payload.containsKey("responseTokens") ? (Map) payload.get("responseTokens") : null; } else { a4tParams = Collections.emptyMap();