From b4e9b6e25f8dfb46236ae4f16718de209bbfebd4 Mon Sep 17 00:00:00 2001 From: Rehan Date: Mon, 2 Oct 2023 17:28:49 +0500 Subject: [PATCH] added some tests --- .../processor/PushMessageProcessorTest.kt | 258 +++++++++++++++++- 1 file changed, 256 insertions(+), 2 deletions(-) diff --git a/messagingpush/src/sharedTest/java/io/customer/messagingpush/processor/PushMessageProcessorTest.kt b/messagingpush/src/sharedTest/java/io/customer/messagingpush/processor/PushMessageProcessorTest.kt index 893844f2c..814d8391f 100644 --- a/messagingpush/src/sharedTest/java/io/customer/messagingpush/processor/PushMessageProcessorTest.kt +++ b/messagingpush/src/sharedTest/java/io/customer/messagingpush/processor/PushMessageProcessorTest.kt @@ -1,12 +1,19 @@ package io.customer.messagingpush.processor import android.content.Intent +import android.net.Uri import android.os.Bundle +import androidx.core.app.TaskStackBuilder import androidx.test.ext.junit.runners.AndroidJUnit4 import io.customer.commontest.BaseTest import io.customer.messagingpush.MessagingPushModuleConfig import io.customer.messagingpush.ModuleMessagingPushFCM -import io.customer.messagingpush.di.moduleConfig +import io.customer.messagingpush.activity.NotificationClickReceiverActivity +import io.customer.messagingpush.config.PushClickBehavior +import io.customer.messagingpush.data.communication.CustomerIOPushNotificationCallback +import io.customer.messagingpush.data.model.CustomerIOParsedPushPayload +import io.customer.messagingpush.di.pushMessageProcessor +import io.customer.messagingpush.util.DeepLinkUtil import io.customer.messagingpush.util.PushTrackingUtil import io.customer.sdk.CustomerIOConfig import io.customer.sdk.CustomerIOInstance @@ -14,27 +21,70 @@ import io.customer.sdk.data.request.MetricEvent import io.customer.sdk.extensions.random import io.customer.sdk.module.CustomerIOModule import io.customer.sdk.repository.TrackRepository +import org.amshove.kluent.shouldBeEqualTo import org.amshove.kluent.shouldBeFalse import org.amshove.kluent.shouldBeTrue +import org.amshove.kluent.shouldNotBe +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any import org.mockito.kotlin.mock +import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.verifyNoInteractions import org.mockito.kotlin.whenever +import org.robolectric.Shadows @RunWith(AndroidJUnit4::class) class PushMessageProcessorTest : BaseTest() { private val modules = hashMapOf>() private val customerIOMock: CustomerIOInstance = mock() + private val deepLinkUtilMock: DeepLinkUtil = mock() private val trackRepositoryMock: TrackRepository = mock() override fun setupConfig(): CustomerIOConfig = createConfig( modules = modules ) + @Before + override fun setup() { + super.setup() + + di.overrideDependency(DeepLinkUtil::class.java, deepLinkUtilMock) + di.overrideDependency(TrackRepository::class.java, trackRepositoryMock) + } + private fun pushMessageProcessor(): PushMessageProcessorImpl { - return PushMessageProcessorImpl(di.logger, di.moduleConfig, trackRepositoryMock) + return di.pushMessageProcessor as PushMessageProcessorImpl + } + + private fun pushMessagePayload(deepLink: String? = null): CustomerIOParsedPushPayload { + return CustomerIOParsedPushPayload( + extras = Bundle.EMPTY, + deepLink = deepLink, + cioDeliveryId = String.random, + cioDeliveryToken = String.random, + title = String.random, + body = String.random + ) + } + + private fun setupModuleConfig( + pushClickBehavior: PushClickBehavior? = null, + autoTrackPushEvents: Boolean? = null, + notificationCallback: CustomerIOPushNotificationCallback? = null + ) { + modules[ModuleMessagingPushFCM.MODULE_NAME] = ModuleMessagingPushFCM( + overrideCustomerIO = customerIOMock, + overrideDiGraph = di, + moduleConfig = with(MessagingPushModuleConfig.Builder()) { + autoTrackPushEvents?.let { setAutoTrackPushEvents(it) } + notificationCallback?.let { setNotificationCallback(it) } + pushClickBehavior?.let { setPushClickBehavior(it) } + build() + } + ) } @Test @@ -194,4 +244,208 @@ class PushMessageProcessorTest : BaseTest() { givenDeviceToken ) } + + @Test + fun processNotificationClick_givenValidIntent_expectSuccessfulProcessing() { + setupModuleConfig(autoTrackPushEvents = true) + val processor = pushMessageProcessor() + val givenPayload = pushMessagePayload(deepLink = "https://cio.example.com/") + val intent = Intent().apply { + putExtra(NotificationClickReceiverActivity.NOTIFICATION_PAYLOAD_EXTRA, givenPayload) + } + + processor.processNotificationClick(context, intent) + + verify(trackRepositoryMock).trackMetric( + givenPayload.cioDeliveryId, + MetricEvent.opened, + givenPayload.cioDeliveryToken + ) + verify(deepLinkUtilMock).createDefaultHostAppIntent(context) + verify(deepLinkUtilMock).createDeepLinkHostAppIntent(context, givenPayload.deepLink) + verify(deepLinkUtilMock).createDeepLinkExternalIntent(context, givenPayload.deepLink!!) + } + + @Test + fun processNotificationClick_givenAutoTrackingDisabled_expectDoNotTrackOpened() { + setupModuleConfig(autoTrackPushEvents = false) + val processor = pushMessageProcessor() + val givenPayload = pushMessagePayload() + val intent = Intent().apply { + putExtra(NotificationClickReceiverActivity.NOTIFICATION_PAYLOAD_EXTRA, givenPayload) + } + + processor.processNotificationClick(context, intent) + + verifyNoInteractions(trackRepositoryMock) + } + + @Test + fun processNotificationClick_givenNoDeepLink_expectOpenLauncherIntent() { + val processor = pushMessageProcessor() + val givenPayload = pushMessagePayload() + val intent = Intent().apply { + putExtra(NotificationClickReceiverActivity.NOTIFICATION_PAYLOAD_EXTRA, givenPayload) + } + + processor.processNotificationClick(context, intent) + + verify(deepLinkUtilMock).createDefaultHostAppIntent(any()) + verify(deepLinkUtilMock, never()).createDeepLinkHostAppIntent(any(), any()) + verify(deepLinkUtilMock, never()).createDeepLinkExternalIntent(any(), any()) + } + + @Test + fun processNotificationClick_givenCallbackWithDeepLink_expectOpenCallbackIntent() { + val notificationCallback: CustomerIOPushNotificationCallback = mock() + whenever(notificationCallback.createTaskStackFromPayload(any(), any())).thenReturn( + TaskStackBuilder.create(context) + ) + val givenPayload = pushMessagePayload(deepLink = "https://cio.example.com/") + + // Make sure that the callback as expected for all behaviors + for (pushClickBehavior in PushClickBehavior.values()) { + setupModuleConfig( + notificationCallback = notificationCallback, + pushClickBehavior = pushClickBehavior + ) + val processor = pushMessageProcessor() + val intent = Intent().apply { + putExtra(NotificationClickReceiverActivity.NOTIFICATION_PAYLOAD_EXTRA, givenPayload) + } + + processor.processNotificationClick(context, intent) + + verifyNoInteractions(deepLinkUtilMock) + } + } + + @Test + fun processNotificationClick_givenCallbackWithoutDeepLink_expectOpenCallbackIntent() { + val notificationCallback: CustomerIOPushNotificationCallback = mock() + whenever(notificationCallback.createTaskStackFromPayload(any(), any())).thenReturn( + TaskStackBuilder.create(context) + ) + val givenPayload = pushMessagePayload() + + // Make sure that the callback as expected for all behaviors + for (pushClickBehavior in PushClickBehavior.values()) { + setupModuleConfig( + notificationCallback = notificationCallback, + pushClickBehavior = pushClickBehavior + ) + val processor = pushMessageProcessor() + val intent = Intent().apply { + putExtra(NotificationClickReceiverActivity.NOTIFICATION_PAYLOAD_EXTRA, givenPayload) + } + + processor.processNotificationClick(context, intent) + + verifyNoInteractions(deepLinkUtilMock) + } + } + + @Test + fun processNotificationClick_givenPushBehavior_expectResetTaskStack() { + setupModuleConfig( + autoTrackPushEvents = false, + pushClickBehavior = PushClickBehavior.RESET_TASK_STACK + ) + val givenPackageName = "io.customer.example" + val givenDeepLink = "https://cio.example.com/" + whenever(deepLinkUtilMock.createDeepLinkHostAppIntent(any(), any())).thenReturn( + Intent(Intent.ACTION_VIEW, Uri.parse(givenDeepLink)).apply { + setPackage(givenPackageName) + } + ) + val givenPayload = pushMessagePayload(deepLink = givenDeepLink) + val processor = pushMessageProcessor() + val intent = Intent().apply { + putExtra(NotificationClickReceiverActivity.NOTIFICATION_PAYLOAD_EXTRA, givenPayload) + } + + processor.processNotificationClick(context, intent) + + // The intent will be started with the default flags based on the activity launch mode + // Also, we cannot verify the back stack as it is not exposed by the testing framework + val expectedIntentFlags = + Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_TASK_ON_HOME + val nextStartedActivity = Shadows.shadowOf(application).nextStartedActivity + nextStartedActivity shouldNotBe null + nextStartedActivity.action shouldBeEqualTo Intent.ACTION_VIEW + nextStartedActivity.dataString shouldBeEqualTo givenDeepLink + nextStartedActivity.flags shouldBeEqualTo expectedIntentFlags + nextStartedActivity.`package` shouldBeEqualTo givenPackageName + } + + @Test + fun processNotificationClick_givenPushBehavior_expectPreventRestart() { + setupModuleConfig( + autoTrackPushEvents = false, + pushClickBehavior = PushClickBehavior.ACTIVITY_PREVENT_RESTART + ) + val givenPackageName = "io.customer.example" + val givenDeepLink = "https://cio.example.com/" + whenever(deepLinkUtilMock.createDeepLinkHostAppIntent(any(), any())).thenReturn( + Intent(Intent.ACTION_VIEW, Uri.parse(givenDeepLink)).apply { + setPackage(givenPackageName) + } + ) + val givenPayload = pushMessagePayload(deepLink = givenDeepLink) + val processor = pushMessageProcessor() + val intent = Intent().apply { + putExtra(NotificationClickReceiverActivity.NOTIFICATION_PAYLOAD_EXTRA, givenPayload) + } + + processor.processNotificationClick(context, intent) + + val expectedIntentFlags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP + val nextStartedActivity = Shadows.shadowOf(application).nextStartedActivity + nextStartedActivity shouldNotBe null + nextStartedActivity.action shouldBeEqualTo Intent.ACTION_VIEW + nextStartedActivity.dataString shouldBeEqualTo givenDeepLink + nextStartedActivity.flags shouldBeEqualTo expectedIntentFlags + nextStartedActivity.`package` shouldBeEqualTo givenPackageName + } + + @Test + fun processNotificationClick_givenPushBehavior_expectNoFlags() { + setupModuleConfig( + autoTrackPushEvents = false, + pushClickBehavior = PushClickBehavior.ACTIVITY_NO_FLAGS + ) + val givenPackageName = "io.customer.example" + val givenDeepLink = "https://cio.example.com/" + whenever(deepLinkUtilMock.createDeepLinkHostAppIntent(any(), any())).thenReturn( + Intent(Intent.ACTION_VIEW, Uri.parse(givenDeepLink)).apply { + setPackage(givenPackageName) + } + ) + val givenPayload = pushMessagePayload(deepLink = givenDeepLink) + val processor = pushMessageProcessor() + val intent = Intent().apply { + putExtra(NotificationClickReceiverActivity.NOTIFICATION_PAYLOAD_EXTRA, givenPayload) + } + + processor.processNotificationClick(context, intent) + + // The intent will be started with the default flags based on the activity launch mode + val nextStartedActivity = Shadows.shadowOf(application).nextStartedActivity + nextStartedActivity shouldNotBe null + nextStartedActivity.action shouldBeEqualTo Intent.ACTION_VIEW + nextStartedActivity.dataString shouldBeEqualTo givenDeepLink + nextStartedActivity.`package` shouldBeEqualTo givenPackageName + } + + @Test + fun processNotificationClick_givenEmptyIntent_expectNoProcessing() { + setupModuleConfig(autoTrackPushEvents = true) + val processor = pushMessageProcessor() + val intent = Intent() + + processor.processNotificationClick(context, intent) + + verifyNoInteractions(trackRepositoryMock) + verifyNoInteractions(deepLinkUtilMock) + } }