From aff0208a2b29f07fb3a8c5c384c2a4a9357aa2df Mon Sep 17 00:00:00 2001 From: Swarna Saraf Date: Fri, 20 Oct 2023 11:55:23 -0700 Subject: [PATCH] dev to staging (v2.0.2) (#30) (#32) * Added support for X-EXC-SDK and X-EXC-SDK-Version headers (#29) * Update build.gradle * Added support for X-EXC-SDK and X-EXC-SDK-Version headers * Fixed minor checkstyle issue * Fixed failing unit tests * Minor fixes * Using the Core API for fetching the extension version in functional tests * cleanup * Feedback updates --------- * Added tests to bump up coverage when using Target headers (#31) * Update build.gradle * Bump up coverage for MOB-18912 --------- --------- Co-authored-by: Ryan Morales Co-authored-by: Praveen --- code/build.gradle | 4 +- code/gradle.properties | 2 +- code/gradle/wrapper/gradle-wrapper.properties | 4 +- code/target/build.gradle | 7 +- .../mobile/target/TargetFunctionalTests.kt | 203 +++++++++++++++--- .../mobile/target/TargetTestConstants.java | 2 +- .../mobile/target/TargetConstants.java | 19 +- .../mobile/target/TargetExtension.java | 74 ++++++- .../com/adobe/marketing/mobile/Target.java | 2 +- .../mobile/target/TargetExtensionTests.java | 123 ++++++++++- .../marketing/mobile/target/TargetTests.java | 2 +- code/testapp/build.gradle | 8 +- 12 files changed, 394 insertions(+), 56 deletions(-) diff --git a/code/build.gradle b/code/build.gradle index 680a4c9..0efd986 100644 --- a/code/build.gradle +++ b/code/build.gradle @@ -23,7 +23,7 @@ buildscript { maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } } dependencies { - classpath 'com.android.tools.build:gradle:7.2.2' + classpath 'com.android.tools.build:gradle:7.3.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20" } } @@ -82,7 +82,7 @@ ext { // dependencies junitVersion = "1.1.3" - buildToolsVersion = "30.0.2" + mockitoCoreVersion = "4.5.1" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" jacocoVersion = "0.8.7" } \ No newline at end of file diff --git a/code/gradle.properties b/code/gradle.properties index 7be78ac..42ebeed 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.1 +moduleVersion=2.0.2 mavenRepoName=AdobeMobileTargetSdk mavenRepoDescription=Adobe Experience Platform Target extension for the Adobe Experience Platform Mobile SDK diff --git a/code/gradle/wrapper/gradle-wrapper.properties b/code/gradle/wrapper/gradle-wrapper.properties index 9eee00c..a6da2ae 100644 --- a/code/gradle/wrapper/gradle-wrapper.properties +++ b/code/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Aug 24 12:09:09 PDT 2021 +#Wed Oct 11 21:18:19 PDT 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip diff --git a/code/target/build.gradle b/code/target/build.gradle index f73c720..6671d89 100644 --- a/code/target/build.gradle +++ b/code/target/build.gradle @@ -27,7 +27,6 @@ jacoco { android { compileSdkVersion rootProject.ext.compileSdkVersion - buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { minSdkVersion rootProject.ext.minSdkVersion @@ -228,14 +227,14 @@ dependencies { implementation 'com.adobe.marketing.mobile:core:2.0.1' testImplementation "androidx.test.ext:junit:${rootProject.ext.junitVersion}" + testImplementation "org.mockito:mockito-core:${rootProject.ext.mockitoCoreVersion}" + testImplementation "org.mockito:mockito-inline:${rootProject.ext.mockitoCoreVersion}" testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.9.9' - testImplementation "org.mockito:mockito-core:4.5.1" - testImplementation 'org.mockito:mockito-inline:4.5.1' testImplementation 'org.json:json:20180813' androidTestImplementation 'com.adobe.marketing.mobile:identity:2.0.0' androidTestImplementation "androidx.test.ext:junit:${rootProject.ext.junitVersion}" - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'com.fasterxml.jackson.core:jackson-databind:2.9.9' } diff --git a/code/target/src/androidTest/java/com/adobe/marketing/mobile/target/TargetFunctionalTests.kt b/code/target/src/androidTest/java/com/adobe/marketing/mobile/target/TargetFunctionalTests.kt index 20cb93a..e1b96fb 100644 --- a/code/target/src/androidTest/java/com/adobe/marketing/mobile/target/TargetFunctionalTests.kt +++ b/code/target/src/androidTest/java/com/adobe/marketing/mobile/target/TargetFunctionalTests.kt @@ -124,6 +124,7 @@ class TargetFunctionalTests { private var mockedNetworkResponse: InputStream? = null private var networkRequestUrl: String? = null private var networkRequestBody: String? = null + private var networkRequestHeaders: Map? = null // callback result captures private var retrievedLocationResponse: String? = null @@ -177,6 +178,7 @@ class TargetFunctionalTests { mockedNetworkResponse = null networkRequestUrl = null networkRequestBody = null + networkRequestHeaders = null } private fun resetCallbackResponses() { @@ -223,6 +225,7 @@ class TargetFunctionalTests { // setup network capturer networkMonitor = { request -> networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } } @@ -275,6 +278,10 @@ class TargetFunctionalTests { val profileParams = mbox.getJSONObject("profileParameters") assertEquals("profile_parameter_value", profileParams.getString("profile_parameter_key")) assertEquals(defaultContent, retrievedLocationResponse) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 2 @@ -284,6 +291,7 @@ class TargetFunctionalTests { // setup networkMonitor = { request -> networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } @@ -312,6 +320,10 @@ class TargetFunctionalTests { "[\"no1\",\"no2\",\"no3\"]", orderParams.getString("purchasedProductIds") ) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 3 @@ -340,6 +352,10 @@ class TargetFunctionalTests { assertEquals("764334", productParams.getString("id")) assertEquals("Online", productParams.getString("categoryId")) assertEquals(defaultContent, retrievedLocationResponse) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 4 @@ -349,6 +365,7 @@ class TargetFunctionalTests { // setup networkMonitor = { request -> networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } @@ -381,6 +398,10 @@ class TargetFunctionalTests { assertEquals(2, productParams.length().toLong()) assertEquals("764334", productParams.getString("id")) assertEquals("Online", productParams.getString("categoryId")) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 5 @@ -390,6 +411,7 @@ class TargetFunctionalTests { // setup networkMonitor = { request -> networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } val thirdPartyID = "testID" @@ -413,6 +435,10 @@ class TargetFunctionalTests { val id = json.getJSONObject("id") assertEquals(thirdPartyID, id.getString("thirdPartyId")) assertEquals(defaultContent, retrievedLocationResponse) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 6 @@ -422,6 +448,7 @@ class TargetFunctionalTests { // setup networkMonitor = { request -> networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } @@ -447,6 +474,10 @@ class TargetFunctionalTests { val id = json.getJSONObject("id") assertFalse(id.has("thirdPartyId")) assertEquals(defaultContent, retrievedLocationResponse) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 7 @@ -458,6 +489,7 @@ class TargetFunctionalTests { // setup network networkMonitor = { request -> networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } mockedNetworkResponse = TargetTestHelper.getResponseForTarget(null, mboxNames, @@ -493,6 +525,10 @@ class TargetFunctionalTests { mbox2.getJSONObject("parameters").getString("mbox_parameter_key") ) assertNull(prefetchErrorStatus) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 8 @@ -511,6 +547,10 @@ class TargetFunctionalTests { val id = json.getJSONObject("id") assertFalse(id.has("thirdPartyId")) assertEquals(defaultContent, retrievedLocationResponse) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 9 @@ -564,7 +604,7 @@ class TargetFunctionalTests { // setup var mcid: String? = null waitForNetworkCall = CountDownLatch(3) - networkMonitor = { request -> + networkMonitor = { _ -> waitForNetworkCall?.countDown() } @@ -594,6 +634,7 @@ class TargetFunctionalTests { waitForNetworkCall = CountDownLatch(1) networkMonitor = { request -> networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } @@ -631,6 +672,10 @@ class TargetFunctionalTests { assertEquals("type3", ids.getJSONArray("customerIds").getJSONObject(2).getString("integrationCode")) assertEquals("value3", ids.getJSONArray("customerIds").getJSONObject(2).getString("id")) assertEquals(defaultContent, retrievedLocationResponse) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 13 @@ -648,6 +693,10 @@ class TargetFunctionalTests { assertEquals(mboxName, mbox.getString("name")) assertEquals("4455", json.getString("environmentId")) assertEquals(defaultContent, retrievedLocationResponse) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 14 @@ -677,6 +726,7 @@ class TargetFunctionalTests { // verify assertNull(networkRequestBody); + assertNull(networkRequestHeaders) assertEquals("prefetchedContent", retrievedLocationResponse) // test @@ -691,6 +741,10 @@ class TargetFunctionalTests { val loadedRequest = loadedRequests.getJSONObject(0) assertEquals("mbox1", loadedRequest.getString("name")) assertEquals("0", loadedRequest.getString("index")) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 18 @@ -710,10 +764,10 @@ class TargetFunctionalTests { targetClientCode, "prefetchedContent", null, null, null, null, true, true) - var requestString = "" val networkCountDownLatch = CountDownLatch(1) networkMonitor = { request -> - requestString = String(request.body, Charsets.UTF_8) + networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers networkCountDownLatch.countDown() } @@ -727,7 +781,7 @@ class TargetFunctionalTests { networkCountDownLatch.await(5, TimeUnit.SECONDS) // verify - val json = JSONObject(requestString) + val json = JSONObject(networkRequestBody) val prefetch = json.getJSONObject("prefetch").getJSONArray("mboxes") val mbox = prefetch.getJSONObject(0) assertEquals(1, prefetch.length().toLong()) @@ -749,6 +803,10 @@ class TargetFunctionalTests { assertEquals("764334", mbox.getJSONObject("product").getString("id")) assertEquals("Online", mbox.getJSONObject("product").getString("categoryId")) assertNull(prefetchErrorStatus) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 19 @@ -769,10 +827,10 @@ class TargetFunctionalTests { null, true, true) var callbackErrorStatus: String? = null - var prefetchRequestString = "" val networkCountDownLatch = CountDownLatch(1) networkMonitor = { request -> - prefetchRequestString = String(request.body, Charsets.UTF_8) + networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers networkCountDownLatch.countDown() } @@ -786,7 +844,7 @@ class TargetFunctionalTests { prefetchCountdownLatch.await(5, TimeUnit.SECONDS) // verify - var json = JSONObject(prefetchRequestString) + var json = JSONObject(networkRequestBody) val prefetch = json.getJSONObject("prefetch").getJSONArray("mboxes") assertEquals(1, prefetch.length().toLong()) val mbox = prefetch.getJSONObject(0) @@ -805,12 +863,15 @@ class TargetFunctionalTests { assertEquals("Online", mbox.getJSONObject("product").getString("categoryId")) assertNull(callbackErrorStatus) + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) + // setup val retrieveLocationCountdownLatch = CountDownLatch(1) - val targetRequestList = listOf(TargetRequest(mboxName, null, defaultContent) { status -> + val targetRequestList = listOf(TargetRequest(mboxName, null, defaultContent) { _ -> retrieveLocationCountdownLatch.countDown() }) - var retrieveLocationRequestString = "" val locationContentTargetParameters: TargetParameters = TargetParameters.Builder() .product(TargetProduct.fromEventData(productParameters2)) .order(TargetOrder.fromEventData(orderParameters2)) @@ -819,7 +880,8 @@ class TargetFunctionalTests { .build() val networkCountDownLatch2 = CountDownLatch(1) networkMonitor = { request -> - retrieveLocationRequestString = String(request.body, Charsets.UTF_8) + networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers networkCountDownLatch2.countDown() } @@ -829,7 +891,7 @@ class TargetFunctionalTests { retrieveLocationCountdownLatch.await(5, TimeUnit.SECONDS) // verify - json = JSONObject(retrieveLocationRequestString) + json = JSONObject(networkRequestBody) assertFalse(json.has("notifications")) val loadedRequests = json.getJSONObject("execute").getJSONArray("mboxes") assertEquals(1, loadedRequests.length().toLong()) @@ -851,6 +913,10 @@ class TargetFunctionalTests { "Offline", loadedRequest.getJSONObject("product").getString("categoryId") ) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 24 @@ -877,6 +943,7 @@ class TargetFunctionalTests { val networkCountDownLatch = CountDownLatch(1) networkMonitor = { request -> networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers networkCountDownLatch.countDown() } @@ -898,6 +965,10 @@ class TargetFunctionalTests { assertEquals("2", mbox3.getString("index")) assertEquals(defaultContent, retrieveLocationRequestString1) assertEquals(defaultContent, retrieveLocationRequestString2) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 25 @@ -906,13 +977,13 @@ class TargetFunctionalTests { fun test_Functional_Happy_Target_targetRetrieveLocationContent_VerifyWithoutTargetParameters() { // setup val retrieveLocationCountdownLatch = CountDownLatch(1) - val targetRequestList = listOf(TargetRequest(mboxName, null, defaultContent) { data -> + val targetRequestList = listOf(TargetRequest(mboxName, null, defaultContent) { _ -> retrieveLocationCountdownLatch.countDown() }) - var retrieveLocationRequestString = "" val networkCountDownLatch = CountDownLatch(1) networkMonitor = { request -> - retrieveLocationRequestString = String(request.body, Charsets.UTF_8) + networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers networkCountDownLatch.countDown() } @@ -922,7 +993,7 @@ class TargetFunctionalTests { retrieveLocationCountdownLatch.await(5, TimeUnit.SECONDS) // verify - val json = JSONObject(retrieveLocationRequestString) + val json = JSONObject(networkRequestBody) val mboxes = json.getJSONObject("execute").getJSONArray("mboxes") assertEquals(1, mboxes.length().toLong()) val mbox = mboxes.getJSONObject(0) @@ -931,6 +1002,10 @@ class TargetFunctionalTests { assertFalse(mbox.has("order")) assertFalse(mbox.has("product")) assertFalse(mbox.has("profileParameters")) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } //********************************************************************************************** @@ -952,6 +1027,9 @@ class TargetFunctionalTests { assertEquals("mbox1", mbox.getString("name")) assertNull(prefetchErrorStatus) + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) + // test resetNetworkMonitor() Target.clickedLocation("mbox1", targetParameters) @@ -970,23 +1048,23 @@ class TargetFunctionalTests { assertNotNull(tokenArray) assertEquals(1, tokenArray.length().toLong()) assertEquals("RandomClickTrackEventToken", tokenArray.getString(0)) - var orderParams: org.json.JSONObject? = mbox.getJSONObject("order") - orderParams = notificationObject.getJSONObject("order") + val orderParams = notificationObject.getJSONObject("order") assertEquals(3, orderParams.length().toLong()) assertEquals("SomeOrderID", orderParams.getString("id")) assertEquals(4445.12, orderParams.getDouble("total"), 0.001) assertEquals("[\"no1\",\"no2\",\"no3\"]", orderParams.getString("purchasedProductIds")) - var productParams = mbox.getJSONObject("product") - productParams = notificationObject.getJSONObject("product") + val productParams = notificationObject.getJSONObject("product") assertEquals(2, productParams.length().toLong()) assertEquals("764334", productParams.getString("id")) assertEquals("Online", productParams.getString("categoryId")) - var mboxParams = mbox.getJSONObject("parameters") - mboxParams = notificationObject.getJSONObject("parameters") + val mboxParams = notificationObject.getJSONObject("parameters") assertEquals("mbox_parameter_value", mboxParams.getString("mbox_parameter_key")) - var profileParams = mbox.getJSONObject("profileParameters") - profileParams = notificationObject.getJSONObject("profileParameters") + val profileParams = notificationObject.getJSONObject("profileParameters") assertEquals("profile_parameter_value", profileParams.getString("profile_parameter_key")) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 29 @@ -1019,6 +1097,10 @@ class TargetFunctionalTests { assertFalse(notificationObject.has("order")) assertFalse(notificationObject.has("product")) assertFalse(notificationObject.has("profileParameters")) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } @@ -1052,6 +1134,10 @@ class TargetFunctionalTests { assertEquals("profile_parameter_value", profileParams.getString("profile_parameter_key")) assertNull(prefetchErrorStatus) + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) + // reset resetNetworkMonitor() @@ -1085,6 +1171,10 @@ class TargetFunctionalTests { assertEquals("mbox_parameter_value", mboxParams.getString("mbox_parameter_key")) profileParams = notificationObject.getJSONObject("profileParameters") assertEquals("profile_parameter_value", profileParams.getString("profile_parameter_key")) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } // Test Case No : 38 @@ -1105,6 +1195,7 @@ class TargetFunctionalTests { // verify location display network call is not made assertNull(networkRequestBody) + assertNull(networkRequestHeaders) } // Test Case No : 39 @@ -1124,6 +1215,7 @@ class TargetFunctionalTests { // verify location display network call is not made assertNull(networkRequestBody) + assertNull(networkRequestHeaders) } @@ -1137,8 +1229,8 @@ class TargetFunctionalTests { val sessionId = "66E5C681-4F70-41A2-86AE-F1E151443B10" var retrievedSessionId = "" - Target.getSessionId() { sessionId -> - retrievedSessionId = sessionId + Target.getSessionId() { newSessionId -> + retrievedSessionId = newSessionId waitForCallback?.countDown() } waitForCallback?.await(5, TimeUnit.SECONDS) @@ -1154,8 +1246,8 @@ class TargetFunctionalTests { // verify the newly set sessionId waitForCallback = CountDownLatch(1) - Target.getSessionId() { sessionId -> - retrievedSessionId = sessionId + Target.getSessionId() { newSessionId -> + retrievedSessionId = newSessionId waitForCallback?.countDown() } waitForCallback?.await(5, TimeUnit.SECONDS) @@ -1293,6 +1385,10 @@ class TargetFunctionalTests { var json = JSONObject(networkRequestBody) assertNotNull(json) assertEquals("9093c11c-accd-41a1-9fa7-ea8c50882c41.32_0", json.getJSONObject("id").getString("tntId")) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } //********************************************************************************************** @@ -1328,6 +1424,7 @@ class TargetFunctionalTests { networkMonitor = { request -> networkRequestUrl = request.url networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } @@ -1387,6 +1484,10 @@ class TargetFunctionalTests { assertEquals("764334", productParameters.getString("id")) assertEquals("Online", productParameters.getString("categoryId")) + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) + // Verify server response assertEquals(1, responseDataList.size.toLong()) val responseData = responseDataList[0] @@ -1471,6 +1572,7 @@ class TargetFunctionalTests { // verify assertNull(responseData) assertNull(networkRequestUrl) + assertNull(networkRequestHeaders) } @Test @@ -1513,6 +1615,7 @@ class TargetFunctionalTests { networkMonitor = { request -> networkRequestUrl = request.url networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } @@ -1528,6 +1631,7 @@ class TargetFunctionalTests { // Verify server response assertNull(responseData) assertNull(networkRequestUrl) + assertNull(networkRequestHeaders) } @Test @@ -1595,6 +1699,10 @@ class TargetFunctionalTests { profileParameters.getString("profile_parameter_key") ) + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) + // Verify server response assertEquals(1, responseDataList.size.toLong()) val responseData = responseDataList[0] @@ -1672,6 +1780,10 @@ class TargetFunctionalTests { assertEquals(2, productParameters2.length().toLong()) assertEquals("765432", productParameters2.getString("id")) assertEquals("Offline", productParameters2.getString("categoryId")) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } @Test @@ -1690,7 +1802,7 @@ class TargetFunctionalTests { "product" to productParameters) val executeMboxes: MutableList> = ArrayList() executeMboxes.add(executeMbox1) - val request = mapOf( + val requestMap = mapOf( "execute" to mapOf( "mboxes" to executeMboxes )) @@ -1709,12 +1821,13 @@ class TargetFunctionalTests { networkMonitor = { request -> networkRequestUrl = request.url networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } // test Target.executeRawRequest( - request + requestMap ) { responseData -> responseDataList.add(responseData) localLatch.countDown() @@ -1745,6 +1858,10 @@ class TargetFunctionalTests { profileParameters.getString("profile_parameter_key") ) + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) + // Verify server response assertEquals(1, responseDataList.size.toLong()) val responseData = responseDataList[0] @@ -1821,6 +1938,10 @@ class TargetFunctionalTests { assertEquals(2, productParameters2.length().toLong()) assertEquals("765432", productParameters2.getString("id")) assertEquals("Offline", productParameters2.getString("categoryId")) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } @Test @@ -1852,6 +1973,7 @@ class TargetFunctionalTests { // verify no request is sent assertNull(networkRequestBody) + assertNull(networkRequestHeaders) } @Test @@ -1863,6 +1985,7 @@ class TargetFunctionalTests { // verify assertNull(networkRequestBody) + assertNull(networkRequestHeaders) } @Test @@ -1912,6 +2035,10 @@ class TargetFunctionalTests { assertEquals("RandomClickTrackEventToken", tokenArray.getString(0)) val parameters2 = notificationObject.getJSONObject("parameters") assertEquals("mbox_parameter_value2", parameters2.getString("mbox_parameter_key2")) + + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) } @Test @@ -1954,6 +2081,10 @@ class TargetFunctionalTests { assertEquals(1, propertyObject.length().toLong()) assertEquals("configPropertyToken", propertyObject.getString("token")) + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) + // reset the updated configuration // so that it doesn't get carry forwarded to other tests updateConfiguration(mapOf( @@ -1994,6 +2125,10 @@ class TargetFunctionalTests { assertEquals("male", profileParams.getString("gender")) assertEquals("targetContent", retrievedLocationResponse) + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) + // clear the rules resetRules() } @@ -2031,6 +2166,10 @@ class TargetFunctionalTests { assertEquals("female", profileParams.getString("gender")) assertEquals("targetContent", retrievedLocationResponse) + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) + // clear the rules resetRules() } @@ -2065,6 +2204,10 @@ class TargetFunctionalTests { assertEquals("male", profileParams.getString("gender")) assertNull(prefetchErrorStatus) + // verify request headers + assertEquals("AdobeTargetMobile-Android", networkRequestHeaders?.get("X-EXC-SDK")) + assertEquals(String.format("%s+%s", MobileCore.extensionVersion(), TargetTestConstants.EXTENSION_VERSION), networkRequestHeaders?.get("X-EXC-SDK-Version")) + // clear the rules resetRules() } @@ -2144,11 +2287,13 @@ class TargetFunctionalTests { private fun resetNetworkMonitor() { waitForNetworkCall = CountDownLatch(1) networkRequestBody = null + networkRequestHeaders = null networkRequestUrl = null networkMonitor = { request -> networkRequestUrl = request.url networkRequestBody = String(request.body, Charsets.UTF_8) + networkRequestHeaders = request.headers waitForNetworkCall?.countDown() } } 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 9cc5929..2b8d875 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.1"; + static final String EXTENSION_VERSION = "2.0.2"; 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/TargetConstants.java b/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetConstants.java index 0df5330..77119f2 100644 --- a/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetConstants.java +++ b/code/target/src/main/java/com/adobe/marketing/mobile/target/TargetConstants.java @@ -22,13 +22,20 @@ final class TargetConstants { static final String API_URL_HOST_BASE = "%s.tt.omtrdc.net"; static final String EDGE_HOST_BASE = "mboxedge%s"; static final String DELIVERY_API_URL_BASE = "https://%s/rest/v1/delivery/?client=%s&sessionId=%s"; - static final String REQUEST_CONTENT_TYPE = "application/json"; static final String MBOX_AT_PROPERTY_KEY = "at_property"; static final String A4T_ACTION_NAME = "AnalyticsForTarget"; static final int DEFAULT_NETWORK_TIMEOUT = 2; static final int DEFAULT_TARGET_SESSION_TIMEOUT_SEC = 30 * 60; // 30 mins + static final String HEADER_CONTENT_TYPE = "Content-Type"; + static final String HEADER_CONTENT_TYPE_JSON = "application/json"; + static final String HEADER_X_EXC_SDK = "X-EXC-SDK"; + static final String HEADER_X_EXC_SDK_VERSION = "X-EXC-SDK-Version"; + static final String HEADER_X_EXC_SDK_BASE_TARGET_MOBILE_ANDROID = "AdobeTargetMobile-Android"; + + static final String DEFAULT_WRAPPER_FRIENDLY_NAME = "None"; + private TargetConstants() {} static final HashMap MAP_TO_CONTEXT_DATA_KEYS = createMap(); @@ -241,6 +248,16 @@ static final class Lifecycle { private Lifecycle() {} } + static final class EventHub { + static final String EXTENSION_NAME = "com.adobe.module.eventhub"; + + static final String VERSION = "version"; + static final String WRAPPER = "wrapper"; + static final String WRAPPER_FRIENDLY_NAME = "friendlyName"; + + private EventHub() {} + } + static class PreviewKeys { // Target preview Constants static final String PREVIEW_PARAMETERS = "at_preview_params"; 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 5386fe0..1e56145 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 @@ -33,7 +33,6 @@ import com.adobe.marketing.mobile.services.NetworkCallback; import com.adobe.marketing.mobile.services.NetworkRequest; import com.adobe.marketing.mobile.services.Networking; -import com.adobe.marketing.mobile.services.NetworkingConstants; import com.adobe.marketing.mobile.services.ServiceProvider; import com.adobe.marketing.mobile.services.ui.UIService; import com.adobe.marketing.mobile.util.DataReader; @@ -414,11 +413,15 @@ void handleRawRequest(@NonNull final Event event) { return; } + final Map eventHubData = retrieveEventHubSharedState(event); + final Map headers = new HashMap<>(); + headers.put(TargetConstants.HEADER_CONTENT_TYPE, TargetConstants.HEADER_CONTENT_TYPE_JSON); + headers.put(TargetConstants.HEADER_X_EXC_SDK, getSdkInfo(eventHubData)); + headers.put(TargetConstants.HEADER_X_EXC_SDK_VERSION, getSdkVersion(eventHubData)); + final String url = getTargetRequestUrl(); final String payloadJsonString = payloadJson.toString(); final byte[] payload = payloadJsonString.getBytes(StandardCharsets.UTF_8); - final Map headers = new HashMap<>(); - headers.put(NetworkingConstants.Headers.CONTENT_TYPE, NetworkingConstants.HeaderValues.CONTENT_TYPE_JSON_APPLICATION); final int timeout = targetState.getNetworkTimeout(); final NetworkRequest networkRequest = new NetworkRequest(url, HttpMethod.POST, payload, headers, timeout, timeout); @@ -914,8 +917,12 @@ private String sendTargetRequest(final List batchRequests, return TargetErrors.REQUEST_GENERATION_FAILED; } + final Map eventHubData = retrieveEventHubSharedState(event); final Map headers = new HashMap<>(); - headers.put("Content-Type", TargetConstants.REQUEST_CONTENT_TYPE); + headers.put(TargetConstants.HEADER_CONTENT_TYPE, TargetConstants.HEADER_CONTENT_TYPE_JSON); + headers.put(TargetConstants.HEADER_X_EXC_SDK, getSdkInfo(eventHubData)); + headers.put(TargetConstants.HEADER_X_EXC_SDK_VERSION, getSdkVersion(eventHubData)); + final int timeout = targetState.getNetworkTimeout(); final String url = getTargetRequestUrl(); final String payloadJsonString = payloadJson.toString(); @@ -1653,6 +1660,54 @@ private void runDefaultCallbacks(final List batchRequests, final } } + /** + * Returns the version info by concatenating Mobile Core and Target SDK versions. + *

+ * If EventHub shared state is not available, or if version info is not present in the shared state, {@literal unknown} + * will be returned for Mobile Core version. + * + * @param eventHubData {@code Map} containing shared state data for EventHub. + * @return {@link String} containing Mobile Core and Target SDK versions. + */ + private String getSdkVersion(final Map eventHubData) { + if (TargetUtils.isNullOrEmpty(eventHubData)) { + return ""; + } + + final String coreVersion = DataReader.optString(eventHubData, TargetConstants.EventHub.VERSION, "unknown"); + + // sdkVersion is a combination of Mobile Core+Target SDK version + return String.format("%s+%s",coreVersion,Target.extensionVersion()); + } + + /** + * Returns the Target SDK info containing platform and wrapper details in the format {@literal AdobeTargetMobile-Android<-wrapperFriendlyName>}. + *

+ * If EventHub shared state is not available, or if an SDK wrapper is not used, the information will omit the wrapper details. + * + * @param eventHubData {@code Map} containing shared state data for EventHub. + * @return {@link String} containing SDK info. + */ + private String getSdkInfo(final Map eventHubData) { + final String sdkBase = TargetConstants.HEADER_X_EXC_SDK_BASE_TARGET_MOBILE_ANDROID; + if (TargetUtils.isNullOrEmpty(eventHubData)) { + return sdkBase; + } + + final Map wrapperMap = DataReader.optTypedMap(Object.class, eventHubData, TargetConstants.EventHub.WRAPPER, null); + if (TargetUtils.isNullOrEmpty(wrapperMap)) { + return sdkBase; + } + + final String wrapperFriendlyName = DataReader.optString(wrapperMap, TargetConstants.EventHub.WRAPPER_FRIENDLY_NAME, TargetConstants.DEFAULT_WRAPPER_FRIENDLY_NAME); + if (wrapperFriendlyName.equals(TargetConstants.DEFAULT_WRAPPER_FRIENDLY_NAME)) { + return sdkBase; + } + + // sdkVersion is a combination of Mobile Core+Target SDK version + return String.format("%s-%s",sdkBase,wrapperFriendlyName); + } + /** * Gets the latest valid {@code Lifecycle} shared state at the given {@code event} version. * @@ -1685,4 +1740,15 @@ private Map retrieveConfigurationSharedState(final Event event) final SharedStateResult configSharedState = getApi().getSharedState(TargetConstants.Configuration.EXTENSION_NAME, event, false, SharedStateResolution.ANY); return configSharedState != null ? configSharedState.getValue() : null; } + + /** + * Gets the latest valid {@code EventHub} shared state at the given {@code event} version. + * + * @param event for which the {@code EventHub} state version is to be retrieved. + * @return the last known valid {@code EventHub} state, may be null if no valid state was found. + */ + private Map retrieveEventHubSharedState(final Event event) { + final SharedStateResult eventHubSharedState = getApi().getSharedState(TargetConstants.EventHub.EXTENSION_NAME, event, false, SharedStateResolution.ANY); + return eventHubSharedState != null ? eventHubSharedState.getValue() : null; + } } \ No newline at end of file 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 d631a2f..51d1e0e 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.1"; + static final String EXTENSION_VERSION = "2.0.2"; static final class EventName { static final String PREFETCH_REQUEST = "TargetPrefetchRequest"; 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 6795126..cc99175 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 @@ -109,6 +109,18 @@ public class TargetExtensionTests { } }; + private static HashMap eventHubSharedState = new HashMap() { + { + put("version", "x.y.z"); + put("wrapper", new HashMap() { + { + put("friendlyName", "None"); + put("type", "N"); + } + }); + } + }; + private static Map responseTokens = new HashMap() {{ put("responseTokens.Key", "responseTokens.Value"); }}; @@ -221,7 +233,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.1", extensionVersion); + assertEquals("getVersion should return the correct extension version.", "2.0.2", extensionVersion); } //********************************************************************************************** @@ -396,6 +408,70 @@ public void testLoadRequests_attachesLifecycleAndIdentityData() { @Test public void testLoadRequests_makesCorrectNetworkRequest() throws Exception { + setEventHubSharedState(); + final JSONObject jsonObject = new JSONObject("{\n" + + "\"name\": \"mbox1\",\n" + + "\"options\": [{\"eventToken\":\"displayEventToken\"}]\n" + + "}\n"); + when(requestBuilder.getRequestPayload(any(), any(), any(), any(), any(), any(), any())).thenReturn(jsonObject); + + // test + final Event event = loadRequestEvent(getTargetRequestList(1), null); + extension.handleTargetRequestContentEvent(event); + + // verify + verify(networkService).connectAsync(networkRequestCaptor.capture(), networkCallbackCaptor.capture()); + assertEquals("https://" + MOCKED_TARGET_SERVER + "/rest/v1/delivery/?client=" + MOCKED_CLIENT_CODE + "&sessionId=" + MOCK_SESSION_ID, networkRequestCaptor.getValue().getUrl()); + assertEquals(HttpMethod.POST, networkRequestCaptor.getValue().getMethod()); + final Map headers = networkRequestCaptor.getValue().getHeaders(); + assertEquals(3, headers.size()); + assertEquals("application/json", headers.get("Content-Type")); + assertEquals("AdobeTargetMobile-Android", headers.get("X-EXC-SDK")); + assertEquals(String.format("%s+%s", "x.y.z", extension.getVersion()), headers.get("X-EXC-SDK-Version")); + assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getReadTimeout(), 0); + assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getConnectTimeout(), 0); + } + + @Test + public void testLoadRequests_makesNetworkRequest_wrapperInfoAvailable() throws Exception { + final Map eventHubState = new HashMap() { + { + put("version", "x.y.z"); + put("wrapper", new HashMap() { + { + put("friendlyName", "Flutter"); + put("type", "F"); + } + }); + } + }; + setEventHubSharedState(eventHubState); + final JSONObject jsonObject = new JSONObject("{\n" + + "\"name\": \"mbox1\",\n" + + "\"options\": [{\"eventToken\":\"displayEventToken\"}]\n" + + "}\n"); + when(requestBuilder.getRequestPayload(any(), any(), any(), any(), any(), any(), any())).thenReturn(jsonObject); + + // test + final Event event = loadRequestEvent(getTargetRequestList(1), null); + extension.handleTargetRequestContentEvent(event); + + // verify + verify(networkService).connectAsync(networkRequestCaptor.capture(), networkCallbackCaptor.capture()); + assertEquals("https://" + MOCKED_TARGET_SERVER + "/rest/v1/delivery/?client=" + MOCKED_CLIENT_CODE + "&sessionId=" + MOCK_SESSION_ID, networkRequestCaptor.getValue().getUrl()); + assertEquals(HttpMethod.POST, networkRequestCaptor.getValue().getMethod()); + final Map headers = networkRequestCaptor.getValue().getHeaders(); + assertEquals(3, headers.size()); + assertEquals("application/json", headers.get("Content-Type")); + assertEquals("AdobeTargetMobile-Android-Flutter", headers.get("X-EXC-SDK")); + assertEquals(String.format("%s+%s", "x.y.z", extension.getVersion()), headers.get("X-EXC-SDK-Version")); + assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getReadTimeout(), 0); + assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getConnectTimeout(), 0); + } + + @Test + public void testLoadRequests_makesNetworkRequest_eventHubSharedStateNotAvailable() throws Exception { + setEventHubSharedState(null); final JSONObject jsonObject = new JSONObject("{\n" + "\"name\": \"mbox1\",\n" + "\"options\": [{\"eventToken\":\"displayEventToken\"}]\n" + @@ -410,7 +486,11 @@ public void testLoadRequests_makesCorrectNetworkRequest() throws Exception { verify(networkService).connectAsync(networkRequestCaptor.capture(), networkCallbackCaptor.capture()); assertEquals("https://" + MOCKED_TARGET_SERVER + "/rest/v1/delivery/?client=" + MOCKED_CLIENT_CODE + "&sessionId=" + MOCK_SESSION_ID, networkRequestCaptor.getValue().getUrl()); assertEquals(HttpMethod.POST, networkRequestCaptor.getValue().getMethod()); - assertEquals(1, networkRequestCaptor.getValue().getHeaders().size()); + final Map headers = networkRequestCaptor.getValue().getHeaders(); + assertEquals(3, headers.size()); + assertEquals("application/json", headers.get("Content-Type")); + assertEquals("AdobeTargetMobile-Android", headers.get("X-EXC-SDK")); + assertEquals("", headers.get("X-EXC-SDK-Version")); assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getReadTimeout(), 0); assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getConnectTimeout(), 0); } @@ -1022,6 +1102,7 @@ public void testHandleRawRequest_NoRequest_When_RequestPayloadIsEmpty() throws J @Test public void testHandleRawRequest_SendRequest_When_RequestPayloadIsValid_sendsCorrectNetworkRequest() throws Exception { // setup + setEventHubSharedState(); JSONObject json = new JSONObject("{\"test\":\"value\"}"); when(requestBuilder.getRequestPayload(any(), any(), any(), any(), any())).thenReturn(json); @@ -1032,7 +1113,11 @@ public void testHandleRawRequest_SendRequest_When_RequestPayloadIsValid_sendsCor verify(networkService).connectAsync(networkRequestCaptor.capture(), networkCallbackCaptor.capture()); assertEquals("https://" + MOCKED_TARGET_SERVER + "/rest/v1/delivery/?client=" + MOCKED_CLIENT_CODE + "&sessionId=" + MOCK_SESSION_ID, networkRequestCaptor.getValue().getUrl()); assertEquals(HttpMethod.POST, networkRequestCaptor.getValue().getMethod()); - assertEquals(1, networkRequestCaptor.getValue().getHeaders().size()); + final Map headers = networkRequestCaptor.getValue().getHeaders(); + assertEquals(3, headers.size()); + assertEquals("application/json", headers.get("Content-Type")); + assertEquals("AdobeTargetMobile-Android", headers.get("X-EXC-SDK")); + assertEquals(String.format("%s+%s", "x.y.z", extension.getVersion()), headers.get("X-EXC-SDK-Version")); assertEquals(json.toString(), new String(networkRequestCaptor.getValue().getBody(), StandardCharsets.UTF_8)); assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getReadTimeout(), 0); assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getConnectTimeout(), 0); @@ -1466,6 +1551,9 @@ public void testHandlePrefetchContent_when_ConnectionIsNull() { @Test public void testHandlePrefetchContent_makesCorrectNetworkRequest() { + //setup + setEventHubSharedState(); + // test extension.handleTargetRequestContentEvent(prefetchContentEvent(getTargetPrefetchList(1), null)); @@ -1473,7 +1561,11 @@ public void testHandlePrefetchContent_makesCorrectNetworkRequest() { verify(networkService).connectAsync(networkRequestCaptor.capture(), networkCallbackCaptor.capture()); assertEquals("https://" + MOCKED_TARGET_SERVER + "/rest/v1/delivery/?client=" + MOCKED_CLIENT_CODE + "&sessionId=" + MOCK_SESSION_ID, networkRequestCaptor.getValue().getUrl()); assertEquals(HttpMethod.POST, networkRequestCaptor.getValue().getMethod()); - assertEquals(1, networkRequestCaptor.getValue().getHeaders().size()); + final Map headers = networkRequestCaptor.getValue().getHeaders(); + assertEquals(3, headers.size()); + assertEquals("application/json", headers.get("Content-Type")); + assertEquals("AdobeTargetMobile-Android", headers.get("X-EXC-SDK")); + assertEquals(String.format("%s+%s", "x.y.z", extension.getVersion()), headers.get("X-EXC-SDK-Version")); assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getReadTimeout(), 0); assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getConnectTimeout(), 0); } @@ -1640,6 +1732,7 @@ public void testHandleLocationsDisplayed_NoRequest_When_NoMboxes() { @Test public void testHandleLocationsDisplayed_sendsCorrectNetworkRequest() throws JSONException { // setup + setEventHubSharedState(); when(targetState.getPrefetchedMbox()).thenReturn(getMboxData(3)); when(targetState.getLoadedMbox()).thenReturn(getMboxData(1)); when(responseParser.getAnalyticsForTargetPayload(any(), any())).thenReturn(a4tParams); @@ -1656,7 +1749,11 @@ public void testHandleLocationsDisplayed_sendsCorrectNetworkRequest() throws JSO verify(networkService).connectAsync(networkRequestCaptor.capture(), networkCallbackCaptor.capture()); assertEquals("https://" + MOCKED_TARGET_SERVER + "/rest/v1/delivery/?client=" + MOCKED_CLIENT_CODE + "&sessionId=" + MOCK_SESSION_ID, networkRequestCaptor.getValue().getUrl()); assertEquals(HttpMethod.POST, networkRequestCaptor.getValue().getMethod()); - assertEquals(1, networkRequestCaptor.getValue().getHeaders().size()); + final Map headers = networkRequestCaptor.getValue().getHeaders(); + assertEquals(3, headers.size()); + assertEquals("application/json", headers.get("Content-Type")); + assertEquals("AdobeTargetMobile-Android", headers.get("X-EXC-SDK")); + assertEquals(String.format("%s+%s", "x.y.z", extension.getVersion()), headers.get("X-EXC-SDK-Version")); assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getReadTimeout(), 0); assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getConnectTimeout(), 0); } @@ -1822,6 +1919,7 @@ public void testHandleLocationsClicked_NoRequest_when_clickMetricNotAvailable() @Test public void testHandleLocationsClicked_sendsCorrectData() throws JSONException { // setup + setEventHubSharedState(); when(targetState.getPrefetchedMbox()).thenReturn(getMboxData(1)); when(responseParser.getClickMetric(any())).thenReturn(validJSONObject()); when(requestBuilder.getClickNotificationJsonObject(any(), any(), anyLong(), any())).thenReturn(validJSONObject()); @@ -1839,7 +1937,11 @@ public void testHandleLocationsClicked_sendsCorrectData() throws JSONException { verify(networkService).connectAsync(networkRequestCaptor.capture(), networkCallbackCaptor.capture()); assertEquals("https://" + MOCKED_TARGET_SERVER + "/rest/v1/delivery/?client=" + MOCKED_CLIENT_CODE + "&sessionId=" + MOCK_SESSION_ID, networkRequestCaptor.getValue().getUrl()); assertEquals(HttpMethod.POST, networkRequestCaptor.getValue().getMethod()); - assertEquals(1, networkRequestCaptor.getValue().getHeaders().size()); + final Map headers = networkRequestCaptor.getValue().getHeaders(); + assertEquals(3, headers.size()); + assertEquals("application/json", headers.get("Content-Type")); + assertEquals("AdobeTargetMobile-Android", headers.get("X-EXC-SDK")); + assertEquals(String.format("%s+%s", "x.y.z", extension.getVersion()), headers.get("X-EXC-SDK-Version")); assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getReadTimeout(), 0); assertEquals(MOCK_NETWORK_TIMEOUT, networkRequestCaptor.getValue().getConnectTimeout(), 0); } @@ -1959,6 +2061,15 @@ private void setIdentitySharedState() { .thenReturn(new SharedStateResult(SharedStateStatus.SET, identitySharedState)); } + private void setEventHubSharedState() { + setEventHubSharedState(eventHubSharedState); + } + + private void setEventHubSharedState(final Map sharedState) { + when(mockExtensionApi.getSharedState(eq("com.adobe.module.eventhub"), any(), anyBoolean(), any())) + .thenReturn(new SharedStateResult(SharedStateStatus.SET, sharedState)); + } + Map getTargetRawRequestForExecute(final int count) { if (count == 0) { return new HashMap<>(); 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 b175b98..516fa94 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.1", + assertEquals("extensionVersion API should return the correct version string.", "2.0.2", extensionVersion); } diff --git a/code/testapp/build.gradle b/code/testapp/build.gradle index d3dcce9..b8f9847 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.0.1' - implementation 'com.adobe.marketing.mobile:identity:2.0.0' - implementation 'com.adobe.marketing.mobile:lifecycle:2.0.0' - implementation 'com.adobe.marketing.mobile:assurance:2.0.0' + implementation 'com.adobe.marketing.mobile:core:2.5.0' + 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 'androidx.appcompat:appcompat:1.6.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'