Skip to content

Commit

Permalink
feat(multi-id): implement predict only setContact
Browse files Browse the repository at this point in the history
SUITEDEV-35599

Co-authored-by: Andras Sarro <[email protected]>
Co-authored-by: davidSchuppa <[email protected]>
  • Loading branch information
3 people committed Apr 22, 2024
1 parent 3b39d6a commit ff7a60e
Show file tree
Hide file tree
Showing 18 changed files with 290 additions and 48 deletions.
4 changes: 2 additions & 2 deletions emarsys-sdk/src/androidTest/java/com/emarsys/EmarsysTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ class EmarsysTest : AnnotationSpec() {
runBlockingOnCoreSdkThread()

runBlockingOnCoreSdkThread {
verify(mockPredictRestricted).setContact(CONTACT_FIELD_ID, CONTACT_FIELD_VALUE)
verify(mockPredictRestricted).setContact(CONTACT_FIELD_ID, CONTACT_FIELD_VALUE, null)
verifyNoInteractions(mockMobileEngageApi)
}
}
Expand Down Expand Up @@ -760,7 +760,7 @@ class EmarsysTest : AnnotationSpec() {
setContact(CONTACT_FIELD_ID, CONTACT_FIELD_VALUE, completionListener)

runBlockingOnCoreSdkThread {
verify(mockPredictRestricted).setContact(CONTACT_FIELD_ID, CONTACT_FIELD_VALUE)
verify(mockPredictRestricted).setContact(CONTACT_FIELD_ID, CONTACT_FIELD_VALUE, null)
verify(mockMobileEngageApi).setContact(
CONTACT_FIELD_ID,
CONTACT_FIELD_VALUE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class PredictRestrictedTest : AnnotationSpec() {

@Test
fun testPredict_setContact_delegatesTo_Predict_Internal() {
predictRestricted.setContact(CONTACT_FIELD_ID, "contactId")
Mockito.verify(mockPredictInternal).setContact(CONTACT_FIELD_ID, "contactId")
predictRestricted.setContact(CONTACT_FIELD_ID, "contactId", null)
Mockito.verify(mockPredictInternal).setContact(CONTACT_FIELD_ID, "contactId", null)
}

@Test
Expand Down
5 changes: 2 additions & 3 deletions emarsys-sdk/src/main/java/com/emarsys/Emarsys.kt
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,10 @@ object Emarsys {
EmarsysDependencyInjection.mobileEngageApi()
.proxyApi(mobileEngage().concurrentHandlerHolder)
.setContact(contactFieldId, contactFieldValue, completionListener)
}
if (FeatureRegistry.isFeatureEnabled(PREDICT)) {
} else if (FeatureRegistry.isFeatureEnabled(PREDICT)) {
EmarsysDependencyInjection.predictRestrictedApi()
.proxyApi(mobileEngage().concurrentHandlerHolder)
.setContact(contactFieldId, contactFieldValue)
.setContact(contactFieldId, contactFieldValue, completionListener)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,10 @@ import com.emarsys.predict.PredictInternal
import com.emarsys.predict.PredictResponseMapper
import com.emarsys.predict.PredictRestricted
import com.emarsys.predict.PredictRestrictedApi
import com.emarsys.predict.endpoint.Endpoint.PREDICT_BASE_URL
import com.emarsys.predict.provider.PredictRequestModelBuilderProvider
import com.emarsys.predict.request.PredictHeaderFactory
import com.emarsys.predict.request.PredictMultiIdRequestModelFactory
import com.emarsys.predict.request.PredictRequestContext
import com.emarsys.predict.response.VisitorIdResponseHandler
import com.emarsys.predict.response.XPResponseHandler
Expand Down Expand Up @@ -935,7 +937,6 @@ open class DefaultEmarsysComponent(config: EmarsysConfig) : EmarsysComponent {
)
}


override val coreSQLiteDatabase: CoreSQLiteDatabase by lazy {
coreDbHelper.writableCoreDatabase
}
Expand Down Expand Up @@ -983,6 +984,7 @@ open class DefaultEmarsysComponent(config: EmarsysConfig) : EmarsysComponent {
DefaultPredictInternal(
predictRequestContext,
requestManager,
predictMultiIdRequestModelFactory,
concurrentHandlerHolder,
predictRequestModelBuilderProvider,
PredictResponseMapper()
Expand All @@ -1009,14 +1011,18 @@ open class DefaultEmarsysComponent(config: EmarsysConfig) : EmarsysComponent {
override val predictServiceProvider: ServiceEndpointProvider by lazy {
ServiceEndpointProvider(
predictServiceStorage,
com.emarsys.predict.endpoint.Endpoint.PREDICT_BASE_URL
PREDICT_BASE_URL
)
}

override val predictServiceStorage: Storage<String?> by lazy {
StringStorage(PredictStorageKey.PREDICT_SERVICE_URL, sharedPreferences)
}

private val predictMultiIdRequestModelFactory: PredictMultiIdRequestModelFactory by lazy {
PredictMultiIdRequestModelFactory(predictRequestContext, clientServiceEndpointProvider)
}

private fun createRequestModelRepository(
coreDbHelper: CoreDbHelper,
inAppEventHandler: InAppEventHandlerInternal
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.emarsys.predict

import com.emarsys.core.Mockable
import com.emarsys.core.api.result.CompletionListener
import com.emarsys.predict.di.predict

@Mockable
class PredictRestricted(private val loggingInstance: Boolean = false) : PredictRestrictedApi {
override fun setContact(contactFieldId: Int, contactFieldValue: String) {
override fun setContact(contactFieldId: Int, contactFieldValue: String, completionListener: CompletionListener?) {
(if (loggingInstance) predict().loggingPredictInternal else predict().predictInternal)
.setContact(contactFieldId, contactFieldValue)
.setContact(contactFieldId, contactFieldValue, completionListener)
}

override fun clearContact() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.emarsys.predict

import com.emarsys.core.api.result.CompletionListener

interface PredictRestrictedApi {

fun setContact(contactFieldId: Int, contactFieldValue: String)
fun setContact(contactFieldId: Int, contactFieldValue: String, completionListener: CompletionListener?)
fun clearContact()
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class MerchantIdHeaderMapper(

override fun shouldMapRequestModel(requestModel: RequestModel): Boolean {
return (requestModelHelper.isMobileEngageSetContactRequest(requestModel)
|| requestModelHelper.isRefreshContactTokenRequest(requestModel))
|| requestModelHelper.isRefreshContactTokenRequest(requestModel)
|| requestModelHelper.isPredictMultiIdContactRequest(requestModel))
&& !predictRequestContext.merchantId.isNullOrBlank()
}
}
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ androidx-navigation-compose = "2.7.6"
compose-compiler = "1.5.6"
compose-plugin = "1.6.0-dev1419"
android-compileSdk = "34"
android-minSdk = "26"
android-minSdk = "24"
android-targetSdk = "34"
androidx-activity = "1.8.2"
androidx-activityCompose = "1.8.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,26 @@ class RequestModelHelperTest : AnnotationSpec() {
result shouldBe false
}

@Test
fun testIsPredictMultiIdSetContactRequest_true_whenItIsPredictMultiIdSetContactRequest() {
val mockRequestModel = mock(RequestModel::class.java).apply {
whenever(url).thenReturn(URL("$CLIENT_HOST/contact-token"))
}
val result = requestModelHelper.isPredictMultiIdContactRequest(mockRequestModel)

result shouldBe true
}

@Test
fun testIsPredictMultiIdSetContactRequest_false_whenItIsNotPredictMultiIdSetContactRequest() {
val mockRequestModel = mock(RequestModel::class.java).apply {
whenever(url).thenReturn(URL("$CLIENT_BASE/contact-token"))
}
val result = requestModelHelper.isPredictMultiIdContactRequest(mockRequestModel)

result shouldBe false
}

@Test
fun testIsMobileEngageClientRequest_false_whenIsNotClientEndpoint() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ class RequestModelHelper(
val clientServiceUrl = clientServiceEndpointProvider.provideEndpointHost()

val url = requestModel.url.toString()
return url.startsWithOneOf(clientServiceUrl) && url.endsWith("/contact-token")
return url.startsWithOneOf(clientServiceUrl) && url.endsWith("/client/contact-token")
}

fun isPredictMultiIdContactRequest(requestModel: RequestModel): Boolean {
val clientServiceUrl = clientServiceEndpointProvider.provideEndpointHost()

val url = requestModel.url.toString()
return url.startsWith(clientServiceUrl) && !url.contains("apps") && url.endsWith("/contact-token")
}

fun isMobileEngageSetContactRequest(requestModel: RequestModel): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.emarsys.predict.fake.FakeRestClient
import com.emarsys.predict.fake.FakeResultListener
import com.emarsys.predict.model.LastTrackedItemContainer
import com.emarsys.predict.provider.PredictRequestModelBuilderProvider
import com.emarsys.predict.request.PredictMultiIdRequestModelFactory
import com.emarsys.predict.request.PredictRequestContext
import com.emarsys.predict.request.PredictRequestModelBuilder
import com.emarsys.testUtil.AnnotationSpec
Expand All @@ -46,6 +47,7 @@ import org.mockito.kotlin.doReturnConsecutively
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoInteractions
import java.util.concurrent.CountDownLatch

class DefaultPredictInternalTest : AnnotationSpec() {
Expand All @@ -61,12 +63,14 @@ class DefaultPredictInternalTest : AnnotationSpec() {
const val TYPE = "INCLUDE_OR_EXCLUDE"
val EXPECTATIONS = listOf<String>()
const val CONTACT_FIELD_ID = 999
const val CONTACT_FIELD_VALUE = "testContactFieldValue"
}


private lateinit var mockKeyValueStore: KeyValueStore
private lateinit var predictInternal: PredictInternal
private lateinit var mockRequestManager: RequestManager
private lateinit var mockPredictMultiIdRequestModelFactory: PredictMultiIdRequestModelFactory
private lateinit var mockTimestampProvider: TimestampProvider
private lateinit var mockUuidProvider: UUIDProvider
private lateinit var mockRequestContext: PredictRequestContext
Expand All @@ -82,6 +86,7 @@ class DefaultPredictInternalTest : AnnotationSpec() {
private lateinit var latch: CountDownLatch
private lateinit var mockResultListener: ResultListener<Try<List<Product>>>
private lateinit var mockLastTrackedItemContainer: LastTrackedItemContainer
private lateinit var mockCompletionListener: CompletionListener

@Before
@Suppress("UNCHECKED_CAST")
Expand All @@ -94,6 +99,7 @@ class DefaultPredictInternalTest : AnnotationSpec() {
mockResponseModel = mock()
mockKeyValueStore = mock()
mockRequestManager = mock()
mockPredictMultiIdRequestModelFactory = mock()
concurrentHandlerHolder = ConcurrentHandlerHolderFactory.create()
mockPredictResponseMapper = mock()
mockLogic = mock()
Expand Down Expand Up @@ -135,9 +141,12 @@ class DefaultPredictInternalTest : AnnotationSpec() {

mockLastTrackedItemContainer = mock()

mockCompletionListener = mock()

predictInternal = DefaultPredictInternal(
mockRequestContext,
mockRequestManager,
mockPredictMultiIdRequestModelFactory,
concurrentHandlerHolder,
mockRequestModelBuilderProvider,
mockPredictResponseMapper
Expand All @@ -151,12 +160,48 @@ class DefaultPredictInternalTest : AnnotationSpec() {
}

@Test
fun testSetContact_shouldPersistsWithKeyValueStore() {
val contactId = "contactId"
fun testSetContact_shouldCall_requestManager() {
whenever(
mockPredictMultiIdRequestModelFactory.createSetContactRequestModel(
CONTACT_FIELD_ID,
CONTACT_FIELD_VALUE
)
).thenReturn(mockRequestModel)

predictInternal.setContact(CONTACT_FIELD_ID, CONTACT_FIELD_VALUE, mockCompletionListener)

verify(mockRequestManager).submit(mockRequestModel, mockCompletionListener)
}

@Test
fun testSetContact_shouldCall_completionListener_whenExceptionIsThrown() {
val testException = IllegalArgumentException()
whenever(
mockPredictMultiIdRequestModelFactory.createSetContactRequestModel(
CONTACT_FIELD_ID,
CONTACT_FIELD_VALUE
)
).thenThrow(testException)

predictInternal.setContact(CONTACT_FIELD_ID, CONTACT_FIELD_VALUE, mockCompletionListener)

verify(mockCompletionListener).onCompleted(testException)
verifyNoInteractions(mockRequestManager)
}

@Test
fun testSetContact_shouldNotCrash_withException_whenCompletionListenerIsNull() {
val testException = IllegalArgumentException()
whenever(
mockPredictMultiIdRequestModelFactory.createSetContactRequestModel(
CONTACT_FIELD_ID,
CONTACT_FIELD_VALUE
)
).thenThrow(testException)

predictInternal.setContact(CONTACT_FIELD_ID, contactId)
predictInternal.setContact(CONTACT_FIELD_ID, CONTACT_FIELD_VALUE, null)

verify(mockKeyValueStore).putString("predict_contact_id", contactId)
verifyNoInteractions(mockRequestManager)
}

@Test
Expand Down Expand Up @@ -484,6 +529,7 @@ class DefaultPredictInternalTest : AnnotationSpec() {
FakeRestClient.Mode.SUCCESS
)
),
mockPredictMultiIdRequestModelFactory,
concurrentHandlerHolder,
mockRequestModelBuilderProvider,
mockPredictResponseMapper
Expand Down Expand Up @@ -521,6 +567,7 @@ class DefaultPredictInternalTest : AnnotationSpec() {
FakeRestClient.Mode.ERROR_RESPONSE_MODEL
)
),
mockPredictMultiIdRequestModelFactory,
concurrentHandlerHolder,
mockRequestModelBuilderProvider,
mockPredictResponseMapper
Expand All @@ -547,6 +594,7 @@ class DefaultPredictInternalTest : AnnotationSpec() {
FakeRestClient.Mode.ERROR_RESPONSE_MODEL
)
),
mockPredictMultiIdRequestModelFactory,
concurrentHandlerHolder,
mockRequestModelBuilderProvider,
mockPredictResponseMapper
Expand Down Expand Up @@ -574,6 +622,7 @@ class DefaultPredictInternalTest : AnnotationSpec() {
predictInternal = DefaultPredictInternal(
mockRequestContext,
requestManagerWithRestClient(FakeRestClient(mockException)),
mockPredictMultiIdRequestModelFactory,
concurrentHandlerHolder,
mockRequestModelBuilderProvider,
mockPredictResponseMapper
Expand All @@ -597,6 +646,7 @@ class DefaultPredictInternalTest : AnnotationSpec() {
predictInternal = DefaultPredictInternal(
mockRequestContext,
requestManagerWithRestClient(FakeRestClient(mockException)),
mockPredictMultiIdRequestModelFactory,
concurrentHandlerHolder,
mockRequestModelBuilderProvider,
mockPredictResponseMapper
Expand Down
Loading

0 comments on commit ff7a60e

Please sign in to comment.