Skip to content

Commit

Permalink
feat(push): store pushToken locally a track it when setup is finished
Browse files Browse the repository at this point in the history
SDK-226

Co-authored-by: davidSchuppa <[email protected]>
Co-authored-by: LasOri <[email protected]>
Co-authored-by: megamegax <[email protected]>
Co-authored-by: matusekma <[email protected]>
  • Loading branch information
5 people committed Feb 5, 2025
1 parent 1fb62ba commit 0f7a8ef
Show file tree
Hide file tree
Showing 13 changed files with 244 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@ import com.emarsys.core.request.model.RequestMethod
import com.emarsys.core.request.model.RequestModel
import com.emarsys.core.shard.ShardModel
import com.emarsys.testUtil.RandomTestUtils
import com.emarsys.testUtil.mockito.whenever
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.matchers.shouldBe
import io.mockk.every
import io.mockk.mockk
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock

class LogShardListMergerTest {
class LogShardListMergerTest {

private companion object {
const val ID = "id"
Expand All @@ -28,85 +26,44 @@ class LogShardListMergerTest {

private lateinit var merger: LogShardListMerger

private lateinit var timestampProvider: TimestampProvider
private lateinit var uuidProvider: UUIDProvider
private lateinit var deviceInfo: DeviceInfo
private lateinit var mockTimestampProvider: TimestampProvider
private lateinit var mockUuidProvider: UUIDProvider
private lateinit var mockDeviceInfo: DeviceInfo


@Before
fun setUp() {
timestampProvider = mock()
whenever(timestampProvider.provideTimestamp()).thenReturn(TIMESTAMP)

uuidProvider = mock()
whenever(uuidProvider.provideId()).thenReturn(ID)

deviceInfo = mock {
on { platform } doReturn "android"
on { applicationVersion } doReturn "1.0.0"
on { osVersion } doReturn "8.0"
on { model } doReturn "Pixel"
on { clientId } doReturn "clientId"
on { sdkVersion } doReturn "1.6.1"
}
mockTimestampProvider = mockk(relaxed = true)
every { mockTimestampProvider.provideTimestamp() } returns TIMESTAMP

mockUuidProvider = mockk(relaxed = true)
every { mockUuidProvider.provideId() } returns ID

mockDeviceInfo = mockk(relaxed = true)
every { mockDeviceInfo.platform } returns "android"
every { mockDeviceInfo.applicationVersion } returns "1.0.0"
every { mockDeviceInfo.osVersion } returns "8.0"
every { mockDeviceInfo.model } returns "Pixel"
every { mockDeviceInfo.clientId } returns "clientId"
every { mockDeviceInfo.sdkVersion } returns "1.6.1"


merger = LogShardListMerger(
timestampProvider,
uuidProvider,
deviceInfo,
mockTimestampProvider,
mockUuidProvider,
mockDeviceInfo,
APPLICATION_CODE,
MERCHANT_ID
)
}

@Test
fun testMap_shards_mustNotBeNull() {
shouldThrow<IllegalArgumentException> {
merger.map(null)
}
}

@Test
fun testMap_shards_mustNotContainNullElements() {
shouldThrow<IllegalArgumentException> {
merger.map(
listOf(
Mockito.mock(ShardModel::class.java),
null,
Mockito.mock(ShardModel::class.java)
)
)
}
}

@Test
fun testMap_shards_mustContainAtLeastOneElement() {
shouldThrow<IllegalArgumentException> {
merger.map(listOf())
}
}

@Test
fun testConstructor_timestampProvider_mustNotBeNull() {
shouldThrow<IllegalArgumentException> {
LogShardListMerger(null, uuidProvider, deviceInfo, APPLICATION_CODE, MERCHANT_ID)
}
}

@Test
fun testConstructor_uuidProvider_mustNotBeNull() {
shouldThrow<IllegalArgumentException> {
LogShardListMerger(timestampProvider, null, deviceInfo, APPLICATION_CODE, MERCHANT_ID)
}
}

@Test
fun testConstructor_deviceInfo_mustNotBeNull() {
shouldThrow<IllegalArgumentException> {
LogShardListMerger(timestampProvider, uuidProvider, null, APPLICATION_CODE, MERCHANT_ID)
}
}

@Test
fun testMap_singletonList() {
val shardData = RandomTestUtils.randomMap()
Expand All @@ -124,12 +81,16 @@ class LogShardListMergerTest {
fun testMap_multipleElementsInList() {
val shards = (1..5).map { randomShardModel() }

val logDatas =
shards.map { it.data + mapOf("type" to it.type) + mapOf("deviceInfo" to createDeviceInfo()) }
val logData =
shards.map { mapOf("type" to it.type) + mapOf("deviceInfo" to createDeviceInfo()) + it.data }

val expectedRequestModel = requestModel(mapOf("logs" to logData))

val expectedRequestModel = requestModel(mapOf("logs" to logDatas))
val result = merger.map(shards)

merger.map(shards) shouldBe expectedRequestModel
result.payload?.keys?.forEach { key ->
expectedRequestModel.payload?.get(key) shouldBe result.payload?.get(key)
}
}

private fun randomShardModel() = ShardModel(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class FakeFirebaseDependencyContainer(
override val contactTokenStorage: Storage<String?> = mockk(relaxed = true),
override val clientStateStorage: Storage<String?> = mockk(relaxed = true),
override val pushTokenStorage: Storage<String?> = mockk(relaxed = true),
override val localPushTokenStorage: Storage<String?> = mockk(relaxed = true),
override val refreshTokenStorage: Storage<String?> = mockk(relaxed = true),
override val clientServiceStorage: Storage<String?> = mockk(relaxed = true),
override val eventServiceStorage: Storage<String?> = mockk(relaxed = true),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class FakeHuaweiDependencyContainer(
override val contactTokenStorage: Storage<String?> = mock(),
override val clientStateStorage: Storage<String?> = mock(),
override val pushTokenStorage: Storage<String?> = mock(),
override val localPushTokenStorage: Storage<String?> = mock(),
override val refreshTokenStorage: Storage<String?> = mock(),
override val clientServiceStorage: Storage<String?> = mock(),
override val eventServiceStorage: Storage<String?> = mock(),
Expand Down
25 changes: 24 additions & 1 deletion emarsys-sdk/src/androidTest/java/com/emarsys/EmarsysTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.emarsys.core.provider.clientid.ClientIdProvider
import com.emarsys.core.provider.version.VersionProvider
import com.emarsys.core.request.RequestManager
import com.emarsys.core.response.ResponseHandlersProcessor
import com.emarsys.core.storage.Storage
import com.emarsys.core.storage.StringStorage
import com.emarsys.deeplink.DeepLinkApi
import com.emarsys.di.DefaultEmarsysComponent
Expand Down Expand Up @@ -92,7 +93,7 @@ import org.junit.Rule
import org.junit.Test
import java.util.concurrent.CountDownLatch

class EmarsysTest {
class EmarsysTest {
@Rule
@JvmField
val duplicateThreadRule = DuplicatedThreadRule("CoreSDKHandlerThread")
Expand All @@ -109,6 +110,7 @@ class EmarsysTest {
private const val SDK_VERSION = "sdkVersion"
private const val CONTACT_FIELD_VALUE = "CONTACT_ID"
private const val OPEN_ID_TOKEN = "testIdToken"
private const val LOCAL_PUSH_TOKEN = "testPushToken"
}

private lateinit var mockActivityLifecycleWatchdog: ActivityLifecycleWatchdog
Expand Down Expand Up @@ -154,6 +156,7 @@ class EmarsysTest {
private lateinit var mobileEngageConfig: EmarsysConfig
private lateinit var predictConfig: EmarsysConfig
private lateinit var mobileEngageAndPredictConfig: EmarsysConfig
private lateinit var mockLocalPushTokenStorage: Storage<String?>
private lateinit var deviceInfo: DeviceInfo
private lateinit var latch: CountDownLatch
private lateinit var predictResultListenerCallback: (Try<List<Product>>) -> Unit
Expand Down Expand Up @@ -184,6 +187,8 @@ class EmarsysTest {
mockContactTokenStorage = mockk(relaxed = true)
mockClientStateStorage = mockk(relaxed = true)
mockNotificationManagerHelper = mockk(relaxed = true)
mockLocalPushTokenStorage = mockk(relaxed = true)
every { mockLocalPushTokenStorage.get() } returns LOCAL_PUSH_TOKEN

baseConfig = createConfig().build()
mobileEngageConfig = createConfig()
Expand Down Expand Up @@ -272,6 +277,7 @@ class EmarsysTest {
config = mockConfig,
configInternal = mockConfigInternal,
eventService = mockEventServiceApi,
localPushTokenStorage = mockLocalPushTokenStorage,
loggingEventService = mockLoggingEventServiceApi,
deepLink = mockDeepLinkApi,
logger = mockk(relaxed = true)
Expand Down Expand Up @@ -601,6 +607,23 @@ class EmarsysTest {
verify { mockMobileEngageApi.clearContact(null) }
}

@Test
fun testSetup_shouldCall_trackPushToken_ifLocalPushStorage_isNotEmpty() {

setup(mobileEngageConfig)

verify { mockPush.setPushToken(LOCAL_PUSH_TOKEN) }
}

@Test
fun testSetup_shouldNotCall_trackPushToken_ifLocalPushStorage_isEmpty() {
every { mockLocalPushTokenStorage.get() } returns null

setup(mobileEngageConfig)

confirmVerified(mockPush)
}

@Test
fun testSetup_sendDeviceInfoAndAnonymousContact_inOrder() {
every { mockClientStateStorage.get() } returns null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ class FakeDependencyContainer(
override val contactTokenStorage: Storage<String?> = mock(),
override val clientStateStorage: Storage<String?> = mock(),
override val pushTokenStorage: Storage<String?> = mock(),
override val localPushTokenStorage: Storage<String?> = mock(),
override val refreshTokenStorage: Storage<String?> = mock(),
override val clientServiceStorage: Storage<String?> = mock(),
override val eventServiceStorage: Storage<String?> = mock(),
Expand Down
6 changes: 6 additions & 0 deletions emarsys-sdk/src/main/java/com/emarsys/Emarsys.kt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ object Emarsys {
registerDatabaseTriggers()

if (FeatureRegistry.isFeatureEnabled(MOBILE_ENGAGE)) {
trackLocalPushToken()
initializeMobileEngageContact()
}
}
Expand Down Expand Up @@ -232,6 +233,11 @@ object Emarsys {
}
}

private fun trackLocalPushToken() {
val localToken = emarsys().localPushTokenStorage.get()
localToken?.let { EmarsysDependencyInjection.push().proxyWithLogExceptions().setPushToken(it) }
}

private fun refreshRemoteConfig(applicationCode: String?) {
if (!listOf(
"",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,10 @@ open class DefaultEmarsysComponent(config: EmarsysConfig) : EmarsysComponent {
StringStorage(MobileEngageStorageKey.PUSH_TOKEN, sharedPreferencesV3)
}

override val localPushTokenStorage: Storage<String?> by lazy {
StringStorage(MobileEngageStorageKey.LOCAL_PUSH_TOKEN, sharedPreferencesV3)
}

override val uuidProvider: UUIDProvider by lazy {
UUIDProvider()
}
Expand Down Expand Up @@ -754,10 +758,12 @@ open class DefaultEmarsysComponent(config: EmarsysConfig) : EmarsysComponent {
mobileEngageRequestModelFactory,
eventServiceInternal,
pushTokenStorage,
localPushTokenStorage,
notificationCacheableEventHandler,
silentMessageCacheableEventHandler,
notificationInformationListenerProvider,
silentNotificationInformationListenerProvider
silentNotificationInformationListenerProvider,
config.automaticPushTokenSendingEnabled
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class FakeEmarsysDependencyContainer(
override val contactTokenStorage: Storage<String?> = mock(),
override val clientStateStorage: Storage<String?> = mock(),
override val pushTokenStorage: Storage<String?> = mock(),
override val localPushTokenStorage: Storage<String?> = mock(),
override val refreshTokenStorage: Storage<String?> = mock(),
override val clientServiceStorage: Storage<String?> = mock(),
override val eventServiceStorage: Storage<String?> = mock(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class FakeMobileEngageDependencyContainer(
override val contactTokenStorage: Storage<String?> = mock(),
override val clientStateStorage: Storage<String?> = mock(),
override val pushTokenStorage: Storage<String?> = mock(),
override val localPushTokenStorage: Storage<String?> = mock(),
override val refreshTokenStorage: Storage<String?> = mock(),
override val clientServiceStorage: Storage<String?> = mock(),
override val eventServiceStorage: Storage<String?> = mock(),
Expand Down
Loading

0 comments on commit 0f7a8ef

Please sign in to comment.