From 1766486dc7515fa6c694e70e78c5a9086d04d521 Mon Sep 17 00:00:00 2001 From: Marton Matusek Date: Tue, 16 Apr 2024 16:08:30 +0200 Subject: [PATCH] feat(multi-id): add MerchantIdHeaderMapper to add x-merchant-id header to setContact and refreshContactToken requests SUITEDEV-35599 Co-authored-by: LasOri <24588073+LasOri@users.noreply.github.com> Co-authored-by: megamegax --- .../com/emarsys/di/DefaultEmarsysComponent.kt | 2 + .../mapper/MerchantIdHeaderMapperTest.kt | 182 ++++++++++++++++++ .../emarsys/mapper/MerchantIdHeaderMapper.kt | 32 +++ 3 files changed, 216 insertions(+) create mode 100644 emarsys/src/androidTest/java/com/emarsys/mapper/MerchantIdHeaderMapperTest.kt create mode 100644 emarsys/src/main/java/com/emarsys/mapper/MerchantIdHeaderMapper.kt diff --git a/emarsys-sdk/src/main/java/com/emarsys/di/DefaultEmarsysComponent.kt b/emarsys-sdk/src/main/java/com/emarsys/di/DefaultEmarsysComponent.kt index 35511447..a7d79ae1 100644 --- a/emarsys-sdk/src/main/java/com/emarsys/di/DefaultEmarsysComponent.kt +++ b/emarsys-sdk/src/main/java/com/emarsys/di/DefaultEmarsysComponent.kt @@ -91,6 +91,7 @@ import com.emarsys.inapp.InApp import com.emarsys.inapp.InAppApi import com.emarsys.inbox.MessageInbox import com.emarsys.inbox.MessageInboxApi +import com.emarsys.mapper.MerchantIdHeaderMapper import com.emarsys.mobileengage.DefaultMobileEngageInternal import com.emarsys.mobileengage.LoggingMobileEngageInternal import com.emarsys.mobileengage.MobileEngage @@ -1045,6 +1046,7 @@ open class DefaultEmarsysComponent(config: EmarsysConfig) : EmarsysComponent { MobileEngageHeaderMapper(requestContext, requestModelHelper), OpenIdTokenRequestMapper(requestContext, requestModelHelper), ContactTokenHeaderMapper(requestContext, requestModelHelper), + MerchantIdHeaderMapper(requestContext, requestModelHelper, predictRequestContext), DefaultRequestHeaderMapper(requestContext), DeviceEventStateRequestMapper( requestContext, diff --git a/emarsys/src/androidTest/java/com/emarsys/mapper/MerchantIdHeaderMapperTest.kt b/emarsys/src/androidTest/java/com/emarsys/mapper/MerchantIdHeaderMapperTest.kt new file mode 100644 index 00000000..b8dceddd --- /dev/null +++ b/emarsys/src/androidTest/java/com/emarsys/mapper/MerchantIdHeaderMapperTest.kt @@ -0,0 +1,182 @@ +package com.emarsys.mapper + +import com.emarsys.core.request.model.RequestMethod +import com.emarsys.core.request.model.RequestModel +import com.emarsys.mobileengage.MobileEngageRequestContext +import com.emarsys.mobileengage.util.RequestModelHelper +import com.emarsys.predict.request.PredictRequestContext +import com.emarsys.testUtil.AnnotationSpec +import io.kotest.matchers.shouldBe +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub + +class MerchantIdHeaderMapperTest : AnnotationSpec() { + + private companion object { + const val TIMESTAMP = 123456789L + const val REQUEST_ID = "request_id" + const val MERCHANT_ID = "testMerchantId" + const val APPLICATION_CODE = "applicationCode" + } + + private lateinit var mockRequestContext: MobileEngageRequestContext + private lateinit var mockRequestModelHelper: RequestModelHelper + private lateinit var mockPredictRequestContext: PredictRequestContext + + private lateinit var merchantIdHeaderMapper: MerchantIdHeaderMapper + + @Before + fun setUp() { + mockRequestContext = mock { + on { applicationCode } doReturn APPLICATION_CODE + } + mockRequestModelHelper = mock { + on { isMobileEngageSetContactRequest(any()) } doReturn false + on { isRefreshContactTokenRequest(any()) } doReturn false + } + + mockPredictRequestContext = mock() + + merchantIdHeaderMapper = + MerchantIdHeaderMapper( + mockRequestContext, + mockRequestModelHelper, + mockPredictRequestContext + ) + } + + @Test + fun testMap_shouldAddMerchantIdHeader_whenMobileEngageSetContactRequest_andMerchantIdIsPresentInPredictRequestContext() { + val originalRequestModel = createSetContactRequest() + mockPredictRequestContext.stub { + on { merchantId } doReturn MERCHANT_ID + } + mockRequestModelHelper.stub { + on { isMobileEngageSetContactRequest(originalRequestModel) } doReturn true + on { isRefreshContactTokenRequest(originalRequestModel) } doReturn false + } + + val updatedRequestModel = merchantIdHeaderMapper.map(originalRequestModel) + + updatedRequestModel shouldBe createSetContactRequest( + extraHeaders = mapOf( + MerchantIdHeaderMapper.MERCHANT_ID_HEADER to MERCHANT_ID + ) + ) + } + + @Test + fun testMap_shouldAddMerchantIdHeader_whenMobileEngageRefreshContactTokenRequest_andMerchantIdIsPresentInPredictRequestContext() { + val originalRequestModel = createRefreshContactTokenRequest() + mockPredictRequestContext.stub { + on { merchantId } doReturn MERCHANT_ID + } + mockRequestModelHelper.stub { + on { isMobileEngageSetContactRequest(originalRequestModel) } doReturn false + on { isRefreshContactTokenRequest(originalRequestModel) } doReturn true + } + + val updatedRequestModel = merchantIdHeaderMapper.map(originalRequestModel) + + updatedRequestModel shouldBe createRefreshContactTokenRequest( + extraHeaders = mapOf( + MerchantIdHeaderMapper.MERCHANT_ID_HEADER to MERCHANT_ID + ) + ) + } + + @Test + fun testMap_whenNotSetContactOrRefreshContactTokenRequest_shouldIgnoreRequest() { + val originalRequestModel = RequestModel( + "https://me-client.eservice.emarsys.net/v3/notSetContactOrRefreshContactTokenRequest", + RequestMethod.POST, + null, + mapOf(), + TIMESTAMP, + Long.MAX_VALUE, + REQUEST_ID + ) + mockRequestModelHelper.stub { + on { isMobileEngageSetContactRequest(originalRequestModel) } doReturn false + on { isRefreshContactTokenRequest(originalRequestModel) } doReturn false + } + + val updatedRequestModel = merchantIdHeaderMapper.map(originalRequestModel) + + updatedRequestModel shouldBe originalRequestModel + } + + + @Test + fun testMap_shouldNotAddMerchantIdHeader_whenMobileEngageSetContactRequest_andMerchantIdIsMissingFromPredictRequestContext() { + val originalRequestModel = createSetContactRequest() + mockPredictRequestContext.stub { + on { merchantId } doReturn null + } + mockRequestModelHelper.stub { + on { isMobileEngageSetContactRequest(originalRequestModel) } doReturn true + on { isRefreshContactTokenRequest(originalRequestModel) } doReturn false + } + + val updatedRequestModel = merchantIdHeaderMapper.map(originalRequestModel) + + updatedRequestModel shouldBe originalRequestModel + } + + @Test + fun testMap_shouldNotAddMerchantIdHeader_whenMobileEngageRefreshContactTokenRequest_andMerchantIdIsMissingFromPredictRequestContext() { + val originalRequestModel = createRefreshContactTokenRequest() + mockPredictRequestContext.stub { + on { merchantId } doReturn null + } + mockRequestModelHelper.stub { + on { isMobileEngageSetContactRequest(originalRequestModel) } doReturn false + on { isRefreshContactTokenRequest(originalRequestModel) } doReturn true + } + + val updatedRequestModel = merchantIdHeaderMapper.map(originalRequestModel) + + updatedRequestModel shouldBe originalRequestModel + } + + @Test + fun testMap_shouldNotAddMerchantIdHeader_whenMobileEngageSetContactRequest_andMerchantIdIsEmptyInPredictRequestContext() { + val originalRequestModel = createSetContactRequest() + mockPredictRequestContext.stub { + on { merchantId } doReturn "" + } + mockRequestModelHelper.stub { + on { isMobileEngageSetContactRequest(originalRequestModel) } doReturn true + on { isRefreshContactTokenRequest(originalRequestModel) } doReturn false + } + + val updatedRequestModel = merchantIdHeaderMapper.map(originalRequestModel) + + updatedRequestModel shouldBe originalRequestModel + } + + + private fun createSetContactRequest(extraHeaders: Map = mapOf()) = RequestModel( + "https://me-client.eservice.emarsys.net/v3/apps/$APPLICATION_CODE/client/contact", + RequestMethod.POST, + null, + extraHeaders, + TIMESTAMP, + Long.MAX_VALUE, + REQUEST_ID + ) + + private fun createRefreshContactTokenRequest(extraHeaders: Map = mapOf()) = + RequestModel( + "https://me-client.eservice.emarsys.net/v3/apps/${APPLICATION_CODE}/client/contact-token", + RequestMethod.POST, + null, + extraHeaders, + TIMESTAMP, + Long.MAX_VALUE, + REQUEST_ID + ) + +} \ No newline at end of file diff --git a/emarsys/src/main/java/com/emarsys/mapper/MerchantIdHeaderMapper.kt b/emarsys/src/main/java/com/emarsys/mapper/MerchantIdHeaderMapper.kt new file mode 100644 index 00000000..84aff005 --- /dev/null +++ b/emarsys/src/main/java/com/emarsys/mapper/MerchantIdHeaderMapper.kt @@ -0,0 +1,32 @@ +package com.emarsys.mapper + +import com.emarsys.core.request.model.RequestModel +import com.emarsys.mobileengage.MobileEngageRequestContext +import com.emarsys.mobileengage.request.mapper.AbstractRequestMapper +import com.emarsys.mobileengage.util.RequestModelHelper +import com.emarsys.predict.request.PredictRequestContext + +class MerchantIdHeaderMapper( + override val requestContext: MobileEngageRequestContext, + override val requestModelHelper: RequestModelHelper, + private val predictRequestContext: PredictRequestContext +) : AbstractRequestMapper(requestContext, requestModelHelper) { + + companion object { + const val MERCHANT_ID_HEADER = "X-Merchant-Id" + } + + override fun createHeaders(requestModel: RequestModel): Map { + val headers: MutableMap = requestModel.headers.toMutableMap() + if(!predictRequestContext.merchantId.isNullOrBlank()) { + headers[MERCHANT_ID_HEADER] = predictRequestContext.merchantId!! + } + + return headers + } + + override fun shouldMapRequestModel(requestModel: RequestModel): Boolean { + return requestModelHelper.isMobileEngageSetContactRequest(requestModel) || + requestModelHelper.isRefreshContactTokenRequest(requestModel) + } +} \ No newline at end of file