diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index b8490463..a4019a3b 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -2,4 +2,5 @@
+
\ No newline at end of file
diff --git a/android/src/main/java/com/amplitude/android/Amplitude.kt b/android/src/main/java/com/amplitude/android/Amplitude.kt
index 79a5ff74..60e5b772 100644
--- a/android/src/main/java/com/amplitude/android/Amplitude.kt
+++ b/android/src/main/java/com/amplitude/android/Amplitude.kt
@@ -1,5 +1,6 @@
package com.amplitude.android
+import AndroidNetworkListener
import android.content.Context
import com.amplitude.android.migration.ApiKeyStorageMigration
import com.amplitude.android.migration.RemnantDataMigration
@@ -7,6 +8,7 @@ import com.amplitude.android.plugins.AnalyticsConnectorIdentityPlugin
import com.amplitude.android.plugins.AnalyticsConnectorPlugin
import com.amplitude.android.plugins.AndroidContextPlugin
import com.amplitude.android.plugins.AndroidLifecyclePlugin
+import com.amplitude.android.utilities.AndroidNetworkConnectivityChecker
import com.amplitude.core.Amplitude
import com.amplitude.core.events.BaseEvent
import com.amplitude.core.platform.plugins.AmplitudeDestination
@@ -16,11 +18,21 @@ import com.amplitude.id.IdentityConfiguration
import kotlinx.coroutines.launch
open class Amplitude(
- configuration: Configuration
-) : Amplitude(configuration) {
-
+ configuration: Configuration,
+) : Amplitude(configuration), AndroidNetworkListener.NetworkChangeCallback {
internal var inForeground = false
private lateinit var androidContextPlugin: AndroidContextPlugin
+ private var networkListener: AndroidNetworkListener
+ private val networkChangeHandler =
+ object : AndroidNetworkListener.NetworkChangeCallback {
+ override fun onNetworkAvailable() {
+ flush()
+ }
+
+ override fun onNetworkUnavailable() {
+ // Nothing to do so far
+ }
+ }
val sessionId: Long
get() {
@@ -29,6 +41,9 @@ open class Amplitude(
init {
registerShutdownHook()
+ networkListener = AndroidNetworkListener((this.configuration as Configuration).context)
+ networkListener.setNetworkChangeCallback(networkChangeHandler)
+ networkListener.startListening()
}
override fun createTimeline(): Timeline {
@@ -37,14 +52,18 @@ open class Amplitude(
override fun createIdentityConfiguration(): IdentityConfiguration {
val configuration = configuration as Configuration
- val storageDirectory = configuration.context.getDir("${FileStorage.STORAGE_PREFIX}-${configuration.instanceName}", Context.MODE_PRIVATE)
+ val storageDirectory =
+ configuration.context.getDir(
+ "${FileStorage.STORAGE_PREFIX}-${configuration.instanceName}",
+ Context.MODE_PRIVATE,
+ )
return IdentityConfiguration(
instanceName = configuration.instanceName,
apiKey = configuration.apiKey,
identityStorageProvider = configuration.identityStorageProvider,
storageDirectory = storageDirectory,
- logger = configuration.loggerProvider.getLogger(this)
+ logger = configuration.loggerProvider.getLogger(this),
)
}
@@ -62,7 +81,7 @@ open class Amplitude(
add(AndroidLifecyclePlugin())
add(AnalyticsConnectorIdentityPlugin())
add(AnalyticsConnectorPlugin())
- add(AmplitudeDestination())
+ add(AmplitudeDestination(AndroidNetworkConnectivityChecker(this.configuration.context, this.logger)))
(timeline as Timeline).start()
}
@@ -113,11 +132,14 @@ open class Amplitude(
}
private fun registerShutdownHook() {
- Runtime.getRuntime().addShutdownHook(object : Thread() {
- override fun run() {
- (this@Amplitude.timeline as Timeline).stop()
- }
- })
+ Runtime.getRuntime().addShutdownHook(
+ object : Thread() {
+ override fun run() {
+ (this@Amplitude.timeline as Timeline).stop()
+ (this@Amplitude.networkListener as AndroidNetworkListener).stopListening()
+ }
+ },
+ )
}
companion object {
@@ -125,6 +147,7 @@ open class Amplitude(
* The event type for start session events.
*/
const val START_SESSION_EVENT = "session_start"
+
/**
* The event type for end session events.
*/
@@ -134,12 +157,22 @@ open class Amplitude(
* The event type for dummy enter foreground events.
*/
internal const val DUMMY_ENTER_FOREGROUND_EVENT = "dummy_enter_foreground"
+
/**
* The event type for dummy exit foreground events.
*/
internal const val DUMMY_EXIT_FOREGROUND_EVENT = "dummy_exit_foreground"
}
+
+ override fun onNetworkAvailable() {
+ networkChangeHandler.onNetworkAvailable()
+ }
+
+ override fun onNetworkUnavailable() {
+ networkChangeHandler.onNetworkUnavailable()
+ }
}
+
/**
* constructor function to build amplitude in dsl format with config options
* Usage: Amplitude("123", context) {
@@ -153,7 +186,11 @@ open class Amplitude(
* @param configs Configuration
* @return Amplitude Android Instance
*/
-fun Amplitude(apiKey: String, context: Context, configs: Configuration.() -> Unit): com.amplitude.android.Amplitude {
+fun Amplitude(
+ apiKey: String,
+ context: Context,
+ configs: Configuration.() -> Unit,
+): com.amplitude.android.Amplitude {
val config = Configuration(apiKey, context)
configs.invoke(config)
return com.amplitude.android.Amplitude(config)
diff --git a/android/src/main/java/com/amplitude/android/utilities/AndroidNetworkConnectivityChecker.kt b/android/src/main/java/com/amplitude/android/utilities/AndroidNetworkConnectivityChecker.kt
new file mode 100644
index 00000000..9caf41ce
--- /dev/null
+++ b/android/src/main/java/com/amplitude/android/utilities/AndroidNetworkConnectivityChecker.kt
@@ -0,0 +1,46 @@
+package com.amplitude.android.utilities
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.pm.PackageManager
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
+import android.os.Build
+import com.amplitude.common.Logger
+import com.amplitude.core.platform.NetworkConnectivityChecker
+
+class AndroidNetworkConnectivityChecker(private val context: Context, private val logger: Logger) : NetworkConnectivityChecker {
+ companion object {
+ private const val ACCESS_NETWORK_STATE = "android.permission.ACCESS_NETWORK_STATE"
+ }
+
+ override suspend fun isConnected(): Boolean {
+ // Assume connection and proceed.
+ // Events will be treated like online
+ // regardless network connectivity
+ if (!hasPermission(context, ACCESS_NETWORK_STATE)) {
+ logger.warn("No ACCESS_NETWORK_STATE permission, offline mode is not supported.")
+ return true
+ }
+
+ val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ val network = cm.activeNetwork ?: return false
+ val capabilities = cm.getNetworkCapabilities(network) ?: return false
+
+ return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+ } else {
+ @SuppressLint("MissingPermission")
+ val networkInfo = cm.activeNetworkInfo
+ return networkInfo != null && networkInfo.isConnectedOrConnecting
+ }
+ }
+
+ private fun hasPermission(
+ context: Context,
+ permission: String,
+ ): Boolean {
+ return context.checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED
+ }
+}
diff --git a/android/src/main/java/com/amplitude/android/utilities/AndroidNetworkListener.kt b/android/src/main/java/com/amplitude/android/utilities/AndroidNetworkListener.kt
new file mode 100644
index 00000000..8bd16228
--- /dev/null
+++ b/android/src/main/java/com/amplitude/android/utilities/AndroidNetworkListener.kt
@@ -0,0 +1,97 @@
+import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkRequest
+import android.os.Build
+import java.lang.IllegalArgumentException
+
+class AndroidNetworkListener(private val context: Context) {
+ private var networkCallback: NetworkChangeCallback? = null
+ private var networkCallbackForLowerApiLevels: BroadcastReceiver? = null
+ private var networkCallbackForHigherApiLevels: ConnectivityManager.NetworkCallback? = null
+
+ interface NetworkChangeCallback {
+ fun onNetworkAvailable()
+
+ fun onNetworkUnavailable()
+ }
+
+ fun setNetworkChangeCallback(callback: NetworkChangeCallback) {
+ this.networkCallback = callback
+ }
+
+ fun startListening() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ setupNetworkCallback()
+ } else {
+ setupBroadcastReceiver()
+ }
+ }
+
+ @SuppressLint("NewApi")
+ private fun setupNetworkCallback() {
+ val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ val networkRequest =
+ NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build()
+
+ networkCallbackForHigherApiLevels =
+ object : ConnectivityManager.NetworkCallback() {
+ override fun onAvailable(network: Network) {
+ networkCallback?.onNetworkAvailable()
+ }
+
+ override fun onLost(network: Network) {
+ networkCallback?.onNetworkUnavailable()
+ }
+ }
+
+ connectivityManager.registerNetworkCallback(networkRequest, networkCallbackForHigherApiLevels!!)
+ }
+
+ private fun setupBroadcastReceiver() {
+ networkCallbackForLowerApiLevels =
+ object : BroadcastReceiver() {
+ override fun onReceive(
+ context: Context,
+ intent: Intent,
+ ) {
+ if (ConnectivityManager.CONNECTIVITY_ACTION == intent.action) {
+ val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ val activeNetwork = connectivityManager.activeNetworkInfo
+ val isConnected = activeNetwork?.isConnectedOrConnecting == true
+
+ if (isConnected) {
+ networkCallback?.onNetworkAvailable()
+ } else {
+ networkCallback?.onNetworkUnavailable()
+ }
+ }
+ }
+ }
+
+ val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
+ context.registerReceiver(networkCallbackForLowerApiLevels, filter)
+ }
+
+ fun stopListening() {
+ try {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ networkCallbackForHigherApiLevels?.let { connectivityManager.unregisterNetworkCallback(it) }
+ } else {
+ networkCallbackForLowerApiLevels?.let { context.unregisterReceiver(it) }
+ }
+ } catch (e: IllegalArgumentException) {
+ // callback was already unregistered.
+ } catch (e: IllegalStateException) {
+ // shutdown process is in progress and certain operations are not allowed.
+ }
+ }
+}
diff --git a/android/src/test/java/com/amplitude/android/AmplitudeRobolectricTests.kt b/android/src/test/java/com/amplitude/android/AmplitudeRobolectricTests.kt
index aa9cdce6..7cd43a07 100644
--- a/android/src/test/java/com/amplitude/android/AmplitudeRobolectricTests.kt
+++ b/android/src/test/java/com/amplitude/android/AmplitudeRobolectricTests.kt
@@ -2,6 +2,7 @@ package com.amplitude.android
import android.app.Application
import android.content.Context
+import android.net.ConnectivityManager
import com.amplitude.core.events.BaseEvent
import com.amplitude.core.utilities.ConsoleLoggerProvider
import com.amplitude.id.IMIdentityStorageProvider
@@ -23,6 +24,7 @@ import kotlin.io.path.absolutePathString
class AmplitudeRobolectricTests {
private lateinit var amplitude: Amplitude
private var context: Context? = null
+ private lateinit var connectivityManager: ConnectivityManager
var tempDir = TempDirectory()
@@ -30,8 +32,9 @@ class AmplitudeRobolectricTests {
@Before
fun setup() {
context = mockk(relaxed = true)
+ connectivityManager = mockk(relaxed = true)
every { context!!.getDir(any(), any()) } returns File(tempDir.create("data").absolutePathString())
-
+ every { context!!.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivityManager
amplitude = Amplitude(createConfiguration())
}
diff --git a/android/src/test/java/com/amplitude/android/AmplitudeSessionTest.kt b/android/src/test/java/com/amplitude/android/AmplitudeSessionTest.kt
index 7aded7e6..b25165ae 100644
--- a/android/src/test/java/com/amplitude/android/AmplitudeSessionTest.kt
+++ b/android/src/test/java/com/amplitude/android/AmplitudeSessionTest.kt
@@ -1,6 +1,8 @@
package com.amplitude.android
import android.app.Application
+import android.content.Context
+import android.net.ConnectivityManager
import com.amplitude.android.plugins.AndroidLifecyclePlugin
import com.amplitude.common.android.AndroidContextProvider
import com.amplitude.core.Storage
@@ -47,14 +49,18 @@ class AmplitudeSessionTest {
every { anyConstructed().mostRecentLocation } returns null
every { anyConstructed().appSetId } returns ""
- val configuration = IdentityConfiguration(
- instanceName,
- identityStorageProvider = IMIdentityStorageProvider()
- )
+ val configuration =
+ IdentityConfiguration(
+ instanceName,
+ identityStorageProvider = IMIdentityStorageProvider(),
+ )
IdentityContainer.getInstance(configuration)
}
- private fun setDispatcher(amplitude: Amplitude, testScheduler: TestCoroutineScheduler) {
+ private fun setDispatcher(
+ amplitude: Amplitude,
+ testScheduler: TestCoroutineScheduler,
+ ) {
val dispatcher = StandardTestDispatcher(testScheduler)
// inject the amplitudeDispatcher field with reflection, as the field is val (read-only)
val amplitudeDispatcherField = com.amplitude.core.Amplitude::class.java.getDeclaredField("amplitudeDispatcher")
@@ -64,6 +70,8 @@ class AmplitudeSessionTest {
private fun createConfiguration(storageProvider: StorageProvider? = null): Configuration {
val context = mockk(relaxed = true)
+ var connectivityManager = mockk(relaxed = true)
+ every { context!!.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivityManager
return Configuration(
apiKey = "api-key",
@@ -74,533 +82,549 @@ class AmplitudeSessionTest {
trackingSessionEvents = true,
loggerProvider = ConsoleLoggerProvider(),
identifyInterceptStorageProvider = InMemoryStorageProvider(),
- identityStorageProvider = IMIdentityStorageProvider()
+ identityStorageProvider = IMIdentityStorageProvider(),
)
}
@Test
- fun amplitude_closeBackgroundEventsShouldNotStartNewSession() = runTest {
- val amplitude = Amplitude(createConfiguration())
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_closeBackgroundEventsShouldNotStartNewSession() =
+ runTest {
+ val amplitude = Amplitude(createConfiguration())
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.track(createEvent(1000, "test event 1"))
- amplitude.track(createEvent(1050, "test event 2"))
+ amplitude.track(createEvent(1000, "test event 1"))
+ amplitude.track(createEvent(1050, "test event 2"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
- }
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
- tracks.sortBy { event -> event.eventId }
+ tracks.sortBy { event -> event.eventId }
- Assertions.assertEquals(3, tracks.count())
+ Assertions.assertEquals(3, tracks.count())
- var event = tracks[0]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ var event = tracks[0]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[1]
- Assertions.assertEquals("test event 1", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ event = tracks[1]
+ Assertions.assertEquals("test event 1", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[2]
- Assertions.assertEquals("test event 2", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1050, event.timestamp)
- }
+ event = tracks[2]
+ Assertions.assertEquals("test event 2", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1050, event.timestamp)
+ }
@Test
- fun amplitude_distantBackgroundEventsShouldStartNewSession() = runTest {
- val amplitude = Amplitude(createConfiguration())
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_distantBackgroundEventsShouldStartNewSession() =
+ runTest {
+ val amplitude = Amplitude(createConfiguration())
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.track(createEvent(1000, "test event 1"))
- amplitude.track(createEvent(2000, "test event 2"))
+ amplitude.track(createEvent(1000, "test event 1"))
+ amplitude.track(createEvent(2000, "test event 2"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
- }
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
- tracks.sortBy { event -> event.eventId }
+ tracks.sortBy { event -> event.eventId }
- Assertions.assertEquals(5, tracks.count())
+ Assertions.assertEquals(5, tracks.count())
- var event = tracks[0]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ var event = tracks[0]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[1]
- Assertions.assertEquals("test event 1", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ event = tracks[1]
+ Assertions.assertEquals("test event 1", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[2]
- Assertions.assertEquals(Amplitude.END_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ event = tracks[2]
+ Assertions.assertEquals(Amplitude.END_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[3]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(2000, event.sessionId)
- Assertions.assertEquals(2000, event.timestamp)
+ event = tracks[3]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(2000, event.sessionId)
+ Assertions.assertEquals(2000, event.timestamp)
- event = tracks[4]
- Assertions.assertEquals("test event 2", event.eventType)
- Assertions.assertEquals(2000, event.sessionId)
- Assertions.assertEquals(2000, event.timestamp)
- }
+ event = tracks[4]
+ Assertions.assertEquals("test event 2", event.eventType)
+ Assertions.assertEquals(2000, event.sessionId)
+ Assertions.assertEquals(2000, event.timestamp)
+ }
@Test
- fun amplitude_foregroundEventsShouldNotStartNewSession() = runTest {
- val amplitude = Amplitude(createConfiguration())
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_foregroundEventsShouldNotStartNewSession() =
+ runTest {
+ val amplitude = Amplitude(createConfiguration())
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.onEnterForeground(1000)
- amplitude.track(createEvent(1050, "test event 1"))
- amplitude.track(createEvent(2000, "test event 2"))
+ amplitude.onEnterForeground(1000)
+ amplitude.track(createEvent(1050, "test event 1"))
+ amplitude.track(createEvent(2000, "test event 2"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
- }
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
- tracks.sortBy { event -> event.eventId }
+ tracks.sortBy { event -> event.eventId }
- Assertions.assertEquals(3, tracks.count())
+ Assertions.assertEquals(3, tracks.count())
- var event = tracks[0]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ var event = tracks[0]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[1]
- Assertions.assertEquals("test event 1", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1050, event.timestamp)
+ event = tracks[1]
+ Assertions.assertEquals("test event 1", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1050, event.timestamp)
- event = tracks[2]
- Assertions.assertEquals("test event 2", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(2000, event.timestamp)
- }
+ event = tracks[2]
+ Assertions.assertEquals("test event 2", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(2000, event.timestamp)
+ }
@Test
- fun amplitude_closeBackgroundForegroundEventsShouldNotStartNewSession() = runTest {
- val amplitude = Amplitude(createConfiguration())
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_closeBackgroundForegroundEventsShouldNotStartNewSession() =
+ runTest {
+ val amplitude = Amplitude(createConfiguration())
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.track(createEvent(1000, "test event 1"))
- amplitude.onEnterForeground(1050)
- amplitude.track(createEvent(2000, "test event 2"))
+ amplitude.track(createEvent(1000, "test event 1"))
+ amplitude.onEnterForeground(1050)
+ amplitude.track(createEvent(2000, "test event 2"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
- }
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
- tracks.sortBy { event -> event.eventId }
+ tracks.sortBy { event -> event.eventId }
- Assertions.assertEquals(3, tracks.count())
+ Assertions.assertEquals(3, tracks.count())
- var event = tracks[0]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ var event = tracks[0]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[1]
- Assertions.assertEquals("test event 1", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ event = tracks[1]
+ Assertions.assertEquals("test event 1", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[2]
- Assertions.assertEquals("test event 2", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(2000, event.timestamp)
- }
+ event = tracks[2]
+ Assertions.assertEquals("test event 2", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(2000, event.timestamp)
+ }
@Test
- fun amplitude_distantBackgroundForegroundEventsShouldStartNewSession() = runTest {
- val amplitude = Amplitude(createConfiguration())
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_distantBackgroundForegroundEventsShouldStartNewSession() =
+ runTest {
+ val amplitude = Amplitude(createConfiguration())
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.track(createEvent(1000, "test event 1"))
- amplitude.onEnterForeground(2000)
- amplitude.track(createEvent(3000, "test event 2"))
+ amplitude.track(createEvent(1000, "test event 1"))
+ amplitude.onEnterForeground(2000)
+ amplitude.track(createEvent(3000, "test event 2"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
- }
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
- tracks.sortBy { event -> event.eventId }
+ tracks.sortBy { event -> event.eventId }
- Assertions.assertEquals(5, tracks.count())
+ Assertions.assertEquals(5, tracks.count())
- var event = tracks[0]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ var event = tracks[0]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[1]
- Assertions.assertEquals("test event 1", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ event = tracks[1]
+ Assertions.assertEquals("test event 1", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[2]
- Assertions.assertEquals(Amplitude.END_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ event = tracks[2]
+ Assertions.assertEquals(Amplitude.END_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[3]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(2000, event.sessionId)
- Assertions.assertEquals(2000, event.timestamp)
+ event = tracks[3]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(2000, event.sessionId)
+ Assertions.assertEquals(2000, event.timestamp)
- event = tracks[4]
- Assertions.assertEquals("test event 2", event.eventType)
- Assertions.assertEquals(2000, event.sessionId)
- Assertions.assertEquals(3000, event.timestamp)
- }
+ event = tracks[4]
+ Assertions.assertEquals("test event 2", event.eventType)
+ Assertions.assertEquals(2000, event.sessionId)
+ Assertions.assertEquals(3000, event.timestamp)
+ }
@Test
- fun amplitude_closeForegroundBackgroundEventsShouldNotStartNewSession() = runTest {
- val amplitude = Amplitude(createConfiguration())
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_closeForegroundBackgroundEventsShouldNotStartNewSession() =
+ runTest {
+ val amplitude = Amplitude(createConfiguration())
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.onEnterForeground(1000)
- amplitude.track(createEvent(1500, "test event 1"))
- amplitude.onExitForeground(2000)
- amplitude.track(createEvent(2050, "test event 2"))
+ amplitude.onEnterForeground(1000)
+ amplitude.track(createEvent(1500, "test event 1"))
+ amplitude.onExitForeground(2000)
+ amplitude.track(createEvent(2050, "test event 2"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
- }
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
- tracks.sortBy { event -> event.eventId }
+ tracks.sortBy { event -> event.eventId }
- Assertions.assertEquals(3, tracks.count())
+ Assertions.assertEquals(3, tracks.count())
- var event = tracks[0]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ var event = tracks[0]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[1]
- Assertions.assertEquals("test event 1", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1500, event.timestamp)
+ event = tracks[1]
+ Assertions.assertEquals("test event 1", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1500, event.timestamp)
- event = tracks[2]
- Assertions.assertEquals("test event 2", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(2050, event.timestamp)
- }
+ event = tracks[2]
+ Assertions.assertEquals("test event 2", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(2050, event.timestamp)
+ }
@Test
- fun amplitude_distantForegroundBackgroundEventsShouldStartNewSession() = runTest {
- val amplitude = Amplitude(createConfiguration())
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_distantForegroundBackgroundEventsShouldStartNewSession() =
+ runTest {
+ val amplitude = Amplitude(createConfiguration())
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.onEnterForeground(1000)
- amplitude.track(createEvent(1500, "test event 1"))
- amplitude.onExitForeground(2000)
- amplitude.track(createEvent(3000, "test event 2"))
+ amplitude.onEnterForeground(1000)
+ amplitude.track(createEvent(1500, "test event 1"))
+ amplitude.onExitForeground(2000)
+ amplitude.track(createEvent(3000, "test event 2"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
- }
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
- tracks.sortBy { event -> event.eventId }
+ tracks.sortBy { event -> event.eventId }
- Assertions.assertEquals(5, tracks.count())
+ Assertions.assertEquals(5, tracks.count())
- var event = tracks[0]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ var event = tracks[0]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[1]
- Assertions.assertEquals("test event 1", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1500, event.timestamp)
+ event = tracks[1]
+ Assertions.assertEquals("test event 1", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1500, event.timestamp)
- event = tracks[2]
- Assertions.assertEquals(Amplitude.END_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(2000, event.timestamp)
+ event = tracks[2]
+ Assertions.assertEquals(Amplitude.END_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(2000, event.timestamp)
- event = tracks[3]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(3000, event.sessionId)
- Assertions.assertEquals(3000, event.timestamp)
+ event = tracks[3]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(3000, event.sessionId)
+ Assertions.assertEquals(3000, event.timestamp)
- event = tracks[4]
- Assertions.assertEquals("test event 2", event.eventType)
- Assertions.assertEquals(3000, event.sessionId)
- Assertions.assertEquals(3000, event.timestamp)
- }
+ event = tracks[4]
+ Assertions.assertEquals("test event 2", event.eventType)
+ Assertions.assertEquals(3000, event.sessionId)
+ Assertions.assertEquals(3000, event.timestamp)
+ }
@Test
- fun amplitude_sessionDataShouldBePersisted() = runTest {
- val storageProvider = InstanceStorageProvider(InMemoryStorage())
+ fun amplitude_sessionDataShouldBePersisted() =
+ runTest {
+ val storageProvider = InstanceStorageProvider(InMemoryStorage())
- val amplitude1 = Amplitude(createConfiguration(storageProvider))
- setDispatcher(amplitude1, testScheduler)
- amplitude1.isBuilt.await()
+ val amplitude1 = Amplitude(createConfiguration(storageProvider))
+ setDispatcher(amplitude1, testScheduler)
+ amplitude1.isBuilt.await()
- amplitude1.onEnterForeground(1000)
+ amplitude1.onEnterForeground(1000)
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val timeline1 = amplitude1.timeline as Timeline
+ val timeline1 = amplitude1.timeline as Timeline
- Assertions.assertEquals(1000, amplitude1.sessionId)
- Assertions.assertEquals(1000, timeline1.sessionId)
- Assertions.assertEquals(1000, timeline1.lastEventTime)
- Assertions.assertEquals(1, timeline1.lastEventId)
+ Assertions.assertEquals(1000, amplitude1.sessionId)
+ Assertions.assertEquals(1000, timeline1.sessionId)
+ Assertions.assertEquals(1000, timeline1.lastEventTime)
+ Assertions.assertEquals(1, timeline1.lastEventId)
- amplitude1.track(createEvent(1200, "test event 1"))
+ amplitude1.track(createEvent(1200, "test event 1"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- Assertions.assertEquals(1000, amplitude1.sessionId)
- Assertions.assertEquals(1000, timeline1.sessionId)
- Assertions.assertEquals(1200, timeline1.lastEventTime)
- Assertions.assertEquals(2, timeline1.lastEventId)
+ Assertions.assertEquals(1000, amplitude1.sessionId)
+ Assertions.assertEquals(1000, timeline1.sessionId)
+ Assertions.assertEquals(1200, timeline1.lastEventTime)
+ Assertions.assertEquals(2, timeline1.lastEventId)
- val amplitude2 = Amplitude(createConfiguration(storageProvider))
- setDispatcher(amplitude2, testScheduler)
- amplitude2.isBuilt.await()
+ val amplitude2 = Amplitude(createConfiguration(storageProvider))
+ setDispatcher(amplitude2, testScheduler)
+ amplitude2.isBuilt.await()
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val timeline2 = amplitude2.timeline as Timeline
- Assertions.assertEquals(1000, amplitude2.sessionId)
- Assertions.assertEquals(1000, timeline2.sessionId)
- Assertions.assertEquals(1200, timeline2.lastEventTime)
- Assertions.assertEquals(2, timeline2.lastEventId)
- }
+ val timeline2 = amplitude2.timeline as Timeline
+ Assertions.assertEquals(1000, amplitude2.sessionId)
+ Assertions.assertEquals(1000, timeline2.sessionId)
+ Assertions.assertEquals(1200, timeline2.lastEventTime)
+ Assertions.assertEquals(2, timeline2.lastEventId)
+ }
@Test
- fun amplitude_explicitSessionForEventShouldBePreserved() = runTest {
- val amplitude = Amplitude(createConfiguration())
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_explicitSessionForEventShouldBePreserved() =
+ runTest {
+ val amplitude = Amplitude(createConfiguration())
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.track(createEvent(1000, "test event 1"))
- amplitude.track(createEvent(1050, "test event 2", 3000))
- amplitude.track(createEvent(1100, "test event 3"))
+ amplitude.track(createEvent(1000, "test event 1"))
+ amplitude.track(createEvent(1050, "test event 2", 3000))
+ amplitude.track(createEvent(1100, "test event 3"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
- }
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
- tracks.sortBy { event -> event.eventId }
+ tracks.sortBy { event -> event.eventId }
- Assertions.assertEquals(4, tracks.count())
+ Assertions.assertEquals(4, tracks.count())
- var event = tracks[0]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ var event = tracks[0]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[1]
- Assertions.assertEquals("test event 1", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ event = tracks[1]
+ Assertions.assertEquals("test event 1", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[2]
- Assertions.assertEquals("test event 2", event.eventType)
- Assertions.assertEquals(3000, event.sessionId)
- Assertions.assertEquals(1050, event.timestamp)
+ event = tracks[2]
+ Assertions.assertEquals("test event 2", event.eventType)
+ Assertions.assertEquals(3000, event.sessionId)
+ Assertions.assertEquals(1050, event.timestamp)
- event = tracks[3]
- Assertions.assertEquals("test event 3", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1100, event.timestamp)
- }
+ event = tracks[3]
+ Assertions.assertEquals("test event 3", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1100, event.timestamp)
+ }
@Test
- fun amplitude_explicitNoSessionForEventShouldBePreserved() = runTest {
- val amplitude = Amplitude(createConfiguration())
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_explicitNoSessionForEventShouldBePreserved() =
+ runTest {
+ val amplitude = Amplitude(createConfiguration())
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.track(createEvent(1000, "test event 1"))
- amplitude.track(createEvent(1050, "test event 2", -1))
- amplitude.track(createEvent(1100, "test event 3"))
+ amplitude.track(createEvent(1000, "test event 1"))
+ amplitude.track(createEvent(1050, "test event 2", -1))
+ amplitude.track(createEvent(1100, "test event 3"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
- }
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
- tracks.sortBy { event -> event.eventId }
+ tracks.sortBy { event -> event.eventId }
- Assertions.assertEquals(4, tracks.count())
+ Assertions.assertEquals(4, tracks.count())
- var event = tracks[0]
- Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ var event = tracks[0]
+ Assertions.assertEquals(Amplitude.START_SESSION_EVENT, event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[1]
- Assertions.assertEquals("test event 1", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1000, event.timestamp)
+ event = tracks[1]
+ Assertions.assertEquals("test event 1", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1000, event.timestamp)
- event = tracks[2]
- Assertions.assertEquals("test event 2", event.eventType)
- Assertions.assertEquals(-1, event.sessionId)
- Assertions.assertEquals(1050, event.timestamp)
+ event = tracks[2]
+ Assertions.assertEquals("test event 2", event.eventType)
+ Assertions.assertEquals(-1, event.sessionId)
+ Assertions.assertEquals(1050, event.timestamp)
- event = tracks[3]
- Assertions.assertEquals("test event 3", event.eventType)
- Assertions.assertEquals(1000, event.sessionId)
- Assertions.assertEquals(1100, event.timestamp)
- }
+ event = tracks[3]
+ Assertions.assertEquals("test event 3", event.eventType)
+ Assertions.assertEquals(1000, event.sessionId)
+ Assertions.assertEquals(1100, event.timestamp)
+ }
@Suppress("DEPRECATION")
@Test
- fun amplitude_noSessionEventsWhenDisabledWithTrackingSessionEvents() = runTest {
- val configuration = createConfiguration()
- configuration.trackingSessionEvents = false
- val amplitude = Amplitude(configuration)
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_noSessionEventsWhenDisabledWithTrackingSessionEvents() =
+ runTest {
+ val configuration = createConfiguration()
+ configuration.trackingSessionEvents = false
+ val amplitude = Amplitude(configuration)
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.track(createEvent(1000, "test event"))
+ amplitude.track(createEvent(1000, "test event"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
+ Assertions.assertEquals(1, tracks.count())
}
- Assertions.assertEquals(1, tracks.count())
- }
@Test
- fun amplitude_noSessionEventsWhenDisabledWithDefaultTrackingOptions() = runTest {
- val configuration = createConfiguration()
- configuration.defaultTracking.sessions = false
- val amplitude = Amplitude(configuration)
- setDispatcher(amplitude, testScheduler)
+ fun amplitude_noSessionEventsWhenDisabledWithDefaultTrackingOptions() =
+ runTest {
+ val configuration = createConfiguration()
+ configuration.defaultTracking.sessions = false
+ val amplitude = Amplitude(configuration)
+ setDispatcher(amplitude, testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
+ amplitude.isBuilt.await()
- amplitude.track(createEvent(1000, "test event"))
+ amplitude.track(createEvent(1000, "test event"))
- advanceUntilIdle()
- Thread.sleep(100)
+ advanceUntilIdle()
+ Thread.sleep(100)
- val tracks = mutableListOf()
+ val tracks = mutableListOf()
- verify {
- mockedPlugin.track(capture(tracks))
+ verify {
+ mockedPlugin.track(capture(tracks))
+ }
+ Assertions.assertEquals(1, tracks.count())
}
- Assertions.assertEquals(1, tracks.count())
- }
- private fun createEvent(timestamp: Long, eventType: String, sessionId: Long? = null): BaseEvent {
+ private fun createEvent(
+ timestamp: Long,
+ eventType: String,
+ sessionId: Long? = null,
+ ): BaseEvent {
val event = BaseEvent()
event.userId = "user"
event.timestamp = timestamp
@@ -615,7 +639,10 @@ class AmplitudeSessionTest {
}
class InstanceStorageProvider(private val instance: Storage) : StorageProvider {
- override fun getStorage(amplitude: com.amplitude.core.Amplitude, prefix: String?): Storage {
+ override fun getStorage(
+ amplitude: com.amplitude.core.Amplitude,
+ prefix: String?,
+ ): Storage {
return instance
}
}
diff --git a/android/src/test/java/com/amplitude/android/AmplitudeTest.kt b/android/src/test/java/com/amplitude/android/AmplitudeTest.kt
index 3faf6fcb..4636c773 100644
--- a/android/src/test/java/com/amplitude/android/AmplitudeTest.kt
+++ b/android/src/test/java/com/amplitude/android/AmplitudeTest.kt
@@ -2,6 +2,7 @@ package com.amplitude.android
import android.app.Application
import android.content.Context
+import android.net.ConnectivityManager
import com.amplitude.analytics.connector.AnalyticsConnector
import com.amplitude.analytics.connector.Identity
import com.amplitude.android.plugins.AndroidLifecyclePlugin
@@ -38,10 +39,14 @@ open class StubPlugin : EventPlugin {
class AmplitudeTest {
private var context: Context? = null
private var amplitude: Amplitude? = null
+ private lateinit var connectivityManager: ConnectivityManager
@BeforeEach
fun setUp() {
context = mockk(relaxed = true)
+ connectivityManager = mockk(relaxed = true)
+ every { context!!.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivityManager
+
mockkStatic(AndroidLifecyclePlugin::class)
mockkConstructor(AndroidContextProvider::class)
@@ -69,17 +74,21 @@ class AmplitudeTest {
amplitudeDispatcherField.set(amplitude, dispatcher)
}
- private fun createConfiguration(minTimeBetweenSessionsMillis: Long? = null, storageProvider: StorageProvider = InMemoryStorageProvider()): Configuration {
- val configuration = Configuration(
- apiKey = "api-key",
- context = context!!,
- instanceName = instanceName,
- storageProvider = storageProvider,
- trackingSessionEvents = minTimeBetweenSessionsMillis != null,
- loggerProvider = ConsoleLoggerProvider(),
- identifyInterceptStorageProvider = InMemoryStorageProvider(),
- identityStorageProvider = IMIdentityStorageProvider(),
- )
+ private fun createConfiguration(
+ minTimeBetweenSessionsMillis: Long? = null,
+ storageProvider: StorageProvider = InMemoryStorageProvider(),
+ ): Configuration {
+ val configuration =
+ Configuration(
+ apiKey = "api-key",
+ context = context!!,
+ instanceName = instanceName,
+ storageProvider = storageProvider,
+ trackingSessionEvents = minTimeBetweenSessionsMillis != null,
+ loggerProvider = ConsoleLoggerProvider(),
+ identifyInterceptStorageProvider = InMemoryStorageProvider(),
+ identityStorageProvider = IMIdentityStorageProvider(),
+ )
if (minTimeBetweenSessionsMillis != null) {
configuration.minTimeBetweenSessionsMillis = minTimeBetweenSessionsMillis
@@ -89,98 +98,101 @@ class AmplitudeTest {
}
@Test
- fun amplitude_reset_wipesUserIdDeviceId() = runTest {
- setDispatcher(testScheduler)
- if (amplitude?.isBuilt!!.await()) {
- amplitude?.setUserId("test user")
- amplitude?.setDeviceId("test device")
- advanceUntilIdle()
- Assertions.assertEquals("test user", amplitude?.store?.userId)
- Assertions.assertEquals("test device", amplitude?.store?.deviceId)
- Assertions.assertEquals("test user", amplitude?.getUserId())
- Assertions.assertEquals("test device", amplitude?.getDeviceId())
-
- amplitude?.reset()
- advanceUntilIdle()
- Assertions.assertNull(amplitude?.store?.userId)
- Assertions.assertNotEquals("test device", amplitude?.store?.deviceId)
- Assertions.assertNull(amplitude?.getUserId())
- Assertions.assertNotEquals("test device", amplitude?.getDeviceId())
+ fun amplitude_reset_wipesUserIdDeviceId() =
+ runTest {
+ setDispatcher(testScheduler)
+ if (amplitude?.isBuilt!!.await()) {
+ amplitude?.setUserId("test user")
+ amplitude?.setDeviceId("test device")
+ advanceUntilIdle()
+ Assertions.assertEquals("test user", amplitude?.store?.userId)
+ Assertions.assertEquals("test device", amplitude?.store?.deviceId)
+ Assertions.assertEquals("test user", amplitude?.getUserId())
+ Assertions.assertEquals("test device", amplitude?.getDeviceId())
+
+ amplitude?.reset()
+ advanceUntilIdle()
+ Assertions.assertNull(amplitude?.store?.userId)
+ Assertions.assertNotEquals("test device", amplitude?.store?.deviceId)
+ Assertions.assertNull(amplitude?.getUserId())
+ Assertions.assertNotEquals("test device", amplitude?.getDeviceId())
+ }
}
- }
@Test
- fun amplitude_unset_country_with_remote_ip() = runTest {
- setDispatcher(testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude?.add(mockedPlugin)
-
- if (amplitude?.isBuilt!!.await()) {
- val event = BaseEvent()
- event.eventType = "test event"
- amplitude?.track(event)
- advanceUntilIdle()
- Thread.sleep(100)
-
- val track = slot()
- verify { mockedPlugin.track(capture(track)) }
- track.captured.let {
- Assertions.assertEquals("\$remote", it.ip)
- Assertions.assertNull(it.country)
+ fun amplitude_unset_country_with_remote_ip() =
+ runTest {
+ setDispatcher(testScheduler)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude?.add(mockedPlugin)
+
+ if (amplitude?.isBuilt!!.await()) {
+ val event = BaseEvent()
+ event.eventType = "test event"
+ amplitude?.track(event)
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val track = slot()
+ verify { mockedPlugin.track(capture(track)) }
+ track.captured.let {
+ Assertions.assertEquals("\$remote", it.ip)
+ Assertions.assertNull(it.country)
+ }
}
}
- }
@Test
- fun amplitude_fetch_country_with_customized_ip() = runTest {
- setDispatcher(testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude?.add(mockedPlugin)
-
- if (amplitude?.isBuilt!!.await()) {
- val event = BaseEvent()
- event.eventType = "test event"
- event.ip = "127.0.0.1"
- amplitude?.track(event)
- advanceUntilIdle()
- Thread.sleep(100)
-
- val track = slot()
- verify { mockedPlugin.track(capture(track)) }
- track.captured.let {
- Assertions.assertEquals("127.0.0.1", it.ip)
- Assertions.assertEquals("US", it.country)
+ fun amplitude_fetch_country_with_customized_ip() =
+ runTest {
+ setDispatcher(testScheduler)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude?.add(mockedPlugin)
+
+ if (amplitude?.isBuilt!!.await()) {
+ val event = BaseEvent()
+ event.eventType = "test event"
+ event.ip = "127.0.0.1"
+ amplitude?.track(event)
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val track = slot()
+ verify { mockedPlugin.track(capture(track)) }
+ track.captured.let {
+ Assertions.assertEquals("127.0.0.1", it.ip)
+ Assertions.assertEquals("US", it.country)
+ }
}
}
- }
@Test
- fun test_analytics_connector() = runTest {
- setDispatcher(testScheduler)
- val mockedPlugin = spyk(StubPlugin())
- amplitude?.add(mockedPlugin)
-
- if (amplitude?.isBuilt!!.await()) {
-
- val connector = AnalyticsConnector.getInstance(instanceName)
- val connectorUserId = "connector user id"
- val connectorDeviceId = "connector device id"
- var connectorIdentitySet = false
- val identityListener = { _: Identity ->
- if (connectorIdentitySet) {
- Assertions.assertEquals(connectorUserId, connector.identityStore.getIdentity().userId)
- Assertions.assertEquals(connectorDeviceId, connector.identityStore.getIdentity().deviceId)
- connectorIdentitySet = false
+ fun test_analytics_connector() =
+ runTest {
+ setDispatcher(testScheduler)
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude?.add(mockedPlugin)
+
+ if (amplitude?.isBuilt!!.await()) {
+ val connector = AnalyticsConnector.getInstance(instanceName)
+ val connectorUserId = "connector user id"
+ val connectorDeviceId = "connector device id"
+ var connectorIdentitySet = false
+ val identityListener = { _: Identity ->
+ if (connectorIdentitySet) {
+ Assertions.assertEquals(connectorUserId, connector.identityStore.getIdentity().userId)
+ Assertions.assertEquals(connectorDeviceId, connector.identityStore.getIdentity().deviceId)
+ connectorIdentitySet = false
+ }
}
+ connector.identityStore.addIdentityListener(identityListener)
+ amplitude?.setUserId(connectorUserId)
+ amplitude?.setDeviceId(connectorDeviceId)
+ advanceUntilIdle()
+ connectorIdentitySet = true
+ connector.identityStore.removeIdentityListener(identityListener)
}
- connector.identityStore.addIdentityListener(identityListener)
- amplitude?.setUserId(connectorUserId)
- amplitude?.setDeviceId(connectorDeviceId)
- advanceUntilIdle()
- connectorIdentitySet = true
- connector.identityStore.removeIdentityListener(identityListener)
}
- }
companion object {
const val instanceName = "testInstance"
diff --git a/android/src/test/java/com/amplitude/android/plugins/AndroidLifecyclePluginTest.kt b/android/src/test/java/com/amplitude/android/plugins/AndroidLifecyclePluginTest.kt
index c30999d0..c3ce74e8 100644
--- a/android/src/test/java/com/amplitude/android/plugins/AndroidLifecyclePluginTest.kt
+++ b/android/src/test/java/com/amplitude/android/plugins/AndroidLifecyclePluginTest.kt
@@ -2,10 +2,12 @@ package com.amplitude.android.plugins
import android.app.Activity
import android.app.Application
+import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
+import android.net.ConnectivityManager
import android.net.Uri
import android.os.Bundle
import com.amplitude.android.Amplitude
@@ -44,6 +46,7 @@ class AndroidLifecyclePluginTest {
private val mockedContext = mockk(relaxed = true)
private var mockedPackageManager: PackageManager
+ private lateinit var connectivityManager: ConnectivityManager
init {
val packageInfo = PackageInfo()
@@ -51,9 +54,10 @@ class AndroidLifecyclePluginTest {
packageInfo.versionCode = 66
packageInfo.versionName = "6.0.0"
- mockedPackageManager = mockk {
- every { getPackageInfo("com.plugin.test", 0) } returns packageInfo
- }
+ mockedPackageManager =
+ mockk {
+ every { getPackageInfo("com.plugin.test", 0) } returns packageInfo
+ }
every { mockedContext.packageName } returns "com.plugin.test"
every { mockedContext.packageManager } returns mockedPackageManager
}
@@ -82,444 +86,469 @@ class AndroidLifecyclePluginTest {
every { anyConstructed().mostRecentLocation } returns null
every { anyConstructed().appSetId } returns ""
- configuration = Configuration(
- apiKey = "api-key",
- context = mockedContext,
- storageProvider = InMemoryStorageProvider(),
- loggerProvider = ConsoleLoggerProvider(),
- identifyInterceptStorageProvider = InMemoryStorageProvider(),
- identityStorageProvider = IMIdentityStorageProvider(),
- trackingSessionEvents = false,
- )
+ connectivityManager = mockk(relaxed = true)
+ every { mockedContext!!.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivityManager
+
+ configuration =
+ Configuration(
+ apiKey = "api-key",
+ context = mockedContext,
+ storageProvider = InMemoryStorageProvider(),
+ loggerProvider = ConsoleLoggerProvider(),
+ identifyInterceptStorageProvider = InMemoryStorageProvider(),
+ identityStorageProvider = IMIdentityStorageProvider(),
+ trackingSessionEvents = false,
+ )
amplitude = Amplitude(configuration)
}
@Test
- fun `test application installed event is tracked`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.appLifecycles = true
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedActivity = mockk()
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(1, tracks.count())
-
- with(tracks[0]) {
- Assertions.assertEquals(DefaultEventUtils.EventTypes.APPLICATION_INSTALLED, eventType)
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.BUILD), "66")
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.VERSION), "6.0.0")
+ fun `test application installed event is tracked`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.appLifecycles = true
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedActivity = mockk()
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(1, tracks.count())
+
+ with(tracks[0]) {
+ Assertions.assertEquals(DefaultEventUtils.EventTypes.APPLICATION_INSTALLED, eventType)
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.BUILD), "66")
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.VERSION), "6.0.0")
+ }
}
- }
@Test
- fun `test application installed event is not tracked when disabled`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.appLifecycles = false
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedActivity = mockk()
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(0, tracks.count())
- }
+ fun `test application installed event is not tracked when disabled`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.appLifecycles = false
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedActivity = mockk()
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(0, tracks.count())
+ }
@Test
- fun `test application updated event is tracked`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.appLifecycles = true
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- // Stored previous version/build
- amplitude.storage.write(Storage.Constants.APP_BUILD, "55")
- amplitude.storage.write(Storage.Constants.APP_VERSION, "5.0.0")
-
- val mockedActivity = mockk()
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(1, tracks.count())
-
- with(tracks[0]) {
- Assertions.assertEquals(DefaultEventUtils.EventTypes.APPLICATION_UPDATED, eventType)
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.BUILD), "66")
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.VERSION), "6.0.0")
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.PREVIOUS_BUILD), "55")
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.PREVIOUS_VERSION), "5.0.0")
+ fun `test application updated event is tracked`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.appLifecycles = true
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ // Stored previous version/build
+ amplitude.storage.write(Storage.Constants.APP_BUILD, "55")
+ amplitude.storage.write(Storage.Constants.APP_VERSION, "5.0.0")
+
+ val mockedActivity = mockk()
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(1, tracks.count())
+
+ with(tracks[0]) {
+ Assertions.assertEquals(DefaultEventUtils.EventTypes.APPLICATION_UPDATED, eventType)
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.BUILD), "66")
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.VERSION), "6.0.0")
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.PREVIOUS_BUILD), "55")
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.PREVIOUS_VERSION), "5.0.0")
+ }
}
- }
@Test
- fun `test application updated event is not tracked when disabled`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.appLifecycles = false
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- // Stored previous version/build
- amplitude.storage.write(Storage.Constants.APP_BUILD, "55")
- amplitude.storage.write(Storage.Constants.APP_VERSION, "5.0.0")
-
- val mockedActivity = mockk()
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(0, tracks.count())
- }
+ fun `test application updated event is not tracked when disabled`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.appLifecycles = false
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ // Stored previous version/build
+ amplitude.storage.write(Storage.Constants.APP_BUILD, "55")
+ amplitude.storage.write(Storage.Constants.APP_VERSION, "5.0.0")
+
+ val mockedActivity = mockk()
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(0, tracks.count())
+ }
@Test
- fun `test application opened event is tracked`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.appLifecycles = true
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedActivity = mockk()
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
- androidLifecyclePlugin.onActivityStarted(mockedActivity)
- androidLifecyclePlugin.onActivityResumed(mockedActivity)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(2, tracks.count())
-
- with(tracks[0]) {
- Assertions.assertEquals(DefaultEventUtils.EventTypes.APPLICATION_INSTALLED, eventType)
- }
- with(tracks[1]) {
- Assertions.assertEquals(DefaultEventUtils.EventTypes.APPLICATION_OPENED, eventType)
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.BUILD), "66")
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.VERSION), "6.0.0")
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.FROM_BACKGROUND), false)
+ fun `test application opened event is tracked`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.appLifecycles = true
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedActivity = mockk()
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+ androidLifecyclePlugin.onActivityStarted(mockedActivity)
+ androidLifecyclePlugin.onActivityResumed(mockedActivity)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(2, tracks.count())
+
+ with(tracks[0]) {
+ Assertions.assertEquals(DefaultEventUtils.EventTypes.APPLICATION_INSTALLED, eventType)
+ }
+ with(tracks[1]) {
+ Assertions.assertEquals(DefaultEventUtils.EventTypes.APPLICATION_OPENED, eventType)
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.BUILD), "66")
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.VERSION), "6.0.0")
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.FROM_BACKGROUND), false)
+ }
}
- }
@Test
- fun `test application opened event is not tracked when disabled`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.appLifecycles = false
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedActivity = mockk()
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
- androidLifecyclePlugin.onActivityStarted(mockedActivity)
- androidLifecyclePlugin.onActivityResumed(mockedActivity)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(0, tracks.count())
- }
+ fun `test application opened event is not tracked when disabled`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.appLifecycles = false
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedActivity = mockk()
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+ androidLifecyclePlugin.onActivityStarted(mockedActivity)
+ androidLifecyclePlugin.onActivityResumed(mockedActivity)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(0, tracks.count())
+ }
@Test
- fun `test application backgrounded event is tracked`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.appLifecycles = true
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedActivity = mockk()
- androidLifecyclePlugin.onActivityPaused(mockedActivity)
- androidLifecyclePlugin.onActivityStopped(mockedActivity)
- androidLifecyclePlugin.onActivityDestroyed(mockedActivity)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(1, tracks.count())
-
- with(tracks[0]) {
- Assertions.assertEquals(DefaultEventUtils.EventTypes.APPLICATION_BACKGROUNDED, eventType)
+ fun `test application backgrounded event is tracked`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.appLifecycles = true
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedActivity = mockk()
+ androidLifecyclePlugin.onActivityPaused(mockedActivity)
+ androidLifecyclePlugin.onActivityStopped(mockedActivity)
+ androidLifecyclePlugin.onActivityDestroyed(mockedActivity)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(1, tracks.count())
+
+ with(tracks[0]) {
+ Assertions.assertEquals(DefaultEventUtils.EventTypes.APPLICATION_BACKGROUNDED, eventType)
+ }
}
- }
@Test
- fun `test application backgrounded event is not tracked when disabled`() = runTest {
- setDispatcher(testScheduler)
- (amplitude.configuration as Configuration).defaultTracking.appLifecycles = false
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedActivity = mockk()
- androidLifecyclePlugin.onActivityPaused(mockedActivity)
- androidLifecyclePlugin.onActivityStopped(mockedActivity)
- androidLifecyclePlugin.onActivityDestroyed(mockedActivity)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(0, tracks.count())
- }
+ fun `test application backgrounded event is not tracked when disabled`() =
+ runTest {
+ setDispatcher(testScheduler)
+ (amplitude.configuration as Configuration).defaultTracking.appLifecycles = false
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedActivity = mockk()
+ androidLifecyclePlugin.onActivityPaused(mockedActivity)
+ androidLifecyclePlugin.onActivityStopped(mockedActivity)
+ androidLifecyclePlugin.onActivityDestroyed(mockedActivity)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(0, tracks.count())
+ }
@Test
- fun `test screen viewed event is tracked`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.screenViews = true
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedActivity = mockk()
- every { mockedActivity.packageManager } returns mockedPackageManager
- every { mockedActivity.componentName } returns mockk()
- val mockedActivityInfo = mockk()
- every { mockedPackageManager.getActivityInfo(any(), any()) } returns mockedActivityInfo
- every { mockedActivityInfo.loadLabel(mockedPackageManager) } returns "test-label"
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
- androidLifecyclePlugin.onActivityStarted(mockedActivity)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(1, tracks.count())
-
- with(tracks[0]) {
- Assertions.assertEquals(DefaultEventUtils.EventTypes.SCREEN_VIEWED, eventType)
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.SCREEN_NAME), "test-label")
+ fun `test screen viewed event is tracked`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.screenViews = true
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedActivity = mockk()
+ every { mockedActivity.packageManager } returns mockedPackageManager
+ every { mockedActivity.componentName } returns mockk()
+ val mockedActivityInfo = mockk()
+ every { mockedPackageManager.getActivityInfo(any(), any()) } returns mockedActivityInfo
+ every { mockedActivityInfo.loadLabel(mockedPackageManager) } returns "test-label"
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+ androidLifecyclePlugin.onActivityStarted(mockedActivity)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(1, tracks.count())
+
+ with(tracks[0]) {
+ Assertions.assertEquals(DefaultEventUtils.EventTypes.SCREEN_VIEWED, eventType)
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.SCREEN_NAME), "test-label")
+ }
}
- }
@Test
- fun `test screen viewed event is not tracked when disabled`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.screenViews = false
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedActivity = mockk()
- every { mockedActivity.packageManager } returns mockedPackageManager
- every { mockedActivity.componentName } returns mockk()
- val mockedActivityInfo = mockk()
- every { mockedPackageManager.getActivityInfo(any(), any()) } returns mockedActivityInfo
- every { mockedActivityInfo.loadLabel(mockedPackageManager) } returns "test-label"
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
- androidLifecyclePlugin.onActivityStarted(mockedActivity)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(0, tracks.count())
- }
+ fun `test screen viewed event is not tracked when disabled`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.screenViews = false
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedActivity = mockk()
+ every { mockedActivity.packageManager } returns mockedPackageManager
+ every { mockedActivity.componentName } returns mockk()
+ val mockedActivityInfo = mockk()
+ every { mockedPackageManager.getActivityInfo(any(), any()) } returns mockedActivityInfo
+ every { mockedActivityInfo.loadLabel(mockedPackageManager) } returns "test-label"
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+ androidLifecyclePlugin.onActivityStarted(mockedActivity)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(0, tracks.count())
+ }
@Test
- fun `test deep link opened event is tracked`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.deepLinks = true
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedIntent = mockk()
- every { mockedIntent.data } returns Uri.parse("app://url.com/open")
- val mockedActivity = mockk()
- every { mockedActivity.intent } returns mockedIntent
- every { mockedActivity.referrer } returns Uri.parse("android-app://com.android.chrome")
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(1, tracks.count())
-
- with(tracks[0]) {
- Assertions.assertEquals(DefaultEventUtils.EventTypes.DEEP_LINK_OPENED, eventType)
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.LINK_URL), "app://url.com/open")
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.LINK_REFERRER), "android-app://com.android.chrome")
+ fun `test deep link opened event is tracked`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.deepLinks = true
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedIntent = mockk()
+ every { mockedIntent.data } returns Uri.parse("app://url.com/open")
+ val mockedActivity = mockk()
+ every { mockedActivity.intent } returns mockedIntent
+ every { mockedActivity.referrer } returns Uri.parse("android-app://com.android.chrome")
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(1, tracks.count())
+
+ with(tracks[0]) {
+ Assertions.assertEquals(DefaultEventUtils.EventTypes.DEEP_LINK_OPENED, eventType)
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.LINK_URL), "app://url.com/open")
+ Assertions.assertEquals(
+ eventProperties?.get(DefaultEventUtils.EventProperties.LINK_REFERRER),
+ "android-app://com.android.chrome",
+ )
+ }
}
- }
@Config(sdk = [21])
@Test
- fun `test deep link opened event is tracked when using sdk is between 17 and 21`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.deepLinks = true
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedIntent = mockk()
- every { mockedIntent.data } returns Uri.parse("app://url.com/open")
- every { mockedIntent.getParcelableExtra(any()) } returns Uri.parse("android-app://com.android.chrome")
- val mockedActivity = mockk()
- every { mockedActivity.intent } returns mockedIntent
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(1, tracks.count())
-
- with(tracks[0]) {
- Assertions.assertEquals(DefaultEventUtils.EventTypes.DEEP_LINK_OPENED, eventType)
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.LINK_URL), "app://url.com/open")
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.LINK_REFERRER), "android-app://com.android.chrome")
+ fun `test deep link opened event is tracked when using sdk is between 17 and 21`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.deepLinks = true
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedIntent = mockk()
+ every { mockedIntent.data } returns Uri.parse("app://url.com/open")
+ every { mockedIntent.getParcelableExtra(any()) } returns Uri.parse("android-app://com.android.chrome")
+ val mockedActivity = mockk()
+ every { mockedActivity.intent } returns mockedIntent
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(1, tracks.count())
+
+ with(tracks[0]) {
+ Assertions.assertEquals(DefaultEventUtils.EventTypes.DEEP_LINK_OPENED, eventType)
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.LINK_URL), "app://url.com/open")
+ Assertions.assertEquals(
+ eventProperties?.get(DefaultEventUtils.EventProperties.LINK_REFERRER),
+ "android-app://com.android.chrome",
+ )
+ }
}
- }
@Config(sdk = [16])
@Test
- fun `test deep link opened event is tracked when using sdk is lower than 17`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.deepLinks = true
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedIntent = mockk()
- every { mockedIntent.data } returns Uri.parse("app://url.com/open")
- every { mockedIntent.getParcelableExtra(any()) } returns Uri.parse("android-app://com.android.chrome")
- val mockedActivity = mockk()
- every { mockedActivity.intent } returns mockedIntent
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(1, tracks.count())
-
- with(tracks[0]) {
- Assertions.assertEquals(DefaultEventUtils.EventTypes.DEEP_LINK_OPENED, eventType)
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.LINK_URL), "app://url.com/open")
- Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.LINK_REFERRER), null)
+ fun `test deep link opened event is tracked when using sdk is lower than 17`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.deepLinks = true
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedIntent = mockk()
+ every { mockedIntent.data } returns Uri.parse("app://url.com/open")
+ every { mockedIntent.getParcelableExtra(any()) } returns Uri.parse("android-app://com.android.chrome")
+ val mockedActivity = mockk()
+ every { mockedActivity.intent } returns mockedIntent
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(1, tracks.count())
+
+ with(tracks[0]) {
+ Assertions.assertEquals(DefaultEventUtils.EventTypes.DEEP_LINK_OPENED, eventType)
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.LINK_URL), "app://url.com/open")
+ Assertions.assertEquals(eventProperties?.get(DefaultEventUtils.EventProperties.LINK_REFERRER), null)
+ }
}
- }
@Test
- fun `test deep link opened event is not tracked when disabled`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.deepLinks = false
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedIntent = mockk()
- every { mockedIntent.data } returns Uri.parse("app://url.com/open")
- val mockedActivity = mockk()
- every { mockedActivity.intent } returns mockedIntent
- every { mockedActivity.referrer } returns Uri.parse("android-app://com.android.chrome")
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(0, tracks.count())
- }
+ fun `test deep link opened event is not tracked when disabled`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.deepLinks = false
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedIntent = mockk()
+ every { mockedIntent.data } returns Uri.parse("app://url.com/open")
+ val mockedActivity = mockk()
+ every { mockedActivity.intent } returns mockedIntent
+ every { mockedActivity.referrer } returns Uri.parse("android-app://com.android.chrome")
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(0, tracks.count())
+ }
@Test
- fun `test deep link opened event is not tracked when URL is missing`() = runTest {
- setDispatcher(testScheduler)
- configuration.defaultTracking.deepLinks = true
- amplitude.add(androidLifecyclePlugin)
-
- val mockedPlugin = spyk(StubPlugin())
- amplitude.add(mockedPlugin)
- amplitude.isBuilt.await()
-
- val mockedIntent = mockk()
- every { mockedIntent.data } returns null
- val mockedActivity = mockk()
- every { mockedActivity.intent } returns mockedIntent
- every { mockedActivity.referrer } returns Uri.parse("android-app://com.android.unit-test")
- val mockedBundle = mockk()
- androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
-
- advanceUntilIdle()
- Thread.sleep(100)
-
- val tracks = mutableListOf()
- verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
- Assertions.assertEquals(0, tracks.count())
- }
+ fun `test deep link opened event is not tracked when URL is missing`() =
+ runTest {
+ setDispatcher(testScheduler)
+ configuration.defaultTracking.deepLinks = true
+ amplitude.add(androidLifecyclePlugin)
+
+ val mockedPlugin = spyk(StubPlugin())
+ amplitude.add(mockedPlugin)
+ amplitude.isBuilt.await()
+
+ val mockedIntent = mockk()
+ every { mockedIntent.data } returns null
+ val mockedActivity = mockk()
+ every { mockedActivity.intent } returns mockedIntent
+ every { mockedActivity.referrer } returns Uri.parse("android-app://com.android.unit-test")
+ val mockedBundle = mockk()
+ androidLifecyclePlugin.onActivityCreated(mockedActivity, mockedBundle)
+
+ advanceUntilIdle()
+ Thread.sleep(100)
+
+ val tracks = mutableListOf()
+ verify(exactly = 0) { mockedPlugin.track(capture(tracks)) }
+ Assertions.assertEquals(0, tracks.count())
+ }
}
diff --git a/core/src/main/java/com/amplitude/core/platform/EventPipeline.kt b/core/src/main/java/com/amplitude/core/platform/EventPipeline.kt
index 71d948d6..274727ac 100644
--- a/core/src/main/java/com/amplitude/core/platform/EventPipeline.kt
+++ b/core/src/main/java/com/amplitude/core/platform/EventPipeline.kt
@@ -14,8 +14,13 @@ import kotlinx.coroutines.withContext
import java.io.FileNotFoundException
import java.util.concurrent.atomic.AtomicInteger
+interface NetworkConnectivityChecker {
+ suspend fun isConnected(): Boolean
+}
+
class EventPipeline(
- private val amplitude: Amplitude
+ private val amplitude: Amplitude,
+ private val networkConnectivityChecker: NetworkConnectivityChecker? = null
) {
private val writeChannel: Channel
@@ -99,6 +104,13 @@ class EventPipeline(
}
}
+ // Skip flush when offline only if
+ // network connectivity is not null
+ // and network is not connected.
+ if (networkConnectivityChecker?.isConnected() == false) {
+ continue
+ }
+
// if flush condition met, generate paths
if (eventCount.incrementAndGet() >= getFlushCount() || triggerFlush) {
eventCount.set(0)
diff --git a/core/src/main/java/com/amplitude/core/platform/plugins/AmplitudeDestination.kt b/core/src/main/java/com/amplitude/core/platform/plugins/AmplitudeDestination.kt
index b4c5d251..d2a6f186 100644
--- a/core/src/main/java/com/amplitude/core/platform/plugins/AmplitudeDestination.kt
+++ b/core/src/main/java/com/amplitude/core/platform/plugins/AmplitudeDestination.kt
@@ -7,10 +7,11 @@ import com.amplitude.core.events.IdentifyEvent
import com.amplitude.core.events.RevenueEvent
import com.amplitude.core.platform.DestinationPlugin
import com.amplitude.core.platform.EventPipeline
+import com.amplitude.core.platform.NetworkConnectivityChecker
import com.amplitude.core.platform.intercept.IdentifyInterceptor
import kotlinx.coroutines.launch
-class AmplitudeDestination : DestinationPlugin() {
+class AmplitudeDestination(private val networkConnectivityChecker: NetworkConnectivityChecker? = null) : DestinationPlugin() {
private lateinit var pipeline: EventPipeline
private lateinit var identifyInterceptor: IdentifyInterceptor
@@ -66,7 +67,8 @@ class AmplitudeDestination : DestinationPlugin() {
with(amplitude) {
pipeline = EventPipeline(
- amplitude
+ amplitude,
+ networkConnectivityChecker
)
pipeline.start()
identifyInterceptor = IdentifyInterceptor(
diff --git a/core/src/test/kotlin/com/amplitude/core/platform/EventPipelineTest.kt b/core/src/test/kotlin/com/amplitude/core/platform/EventPipelineTest.kt
new file mode 100644
index 00000000..9f84253d
--- /dev/null
+++ b/core/src/test/kotlin/com/amplitude/core/platform/EventPipelineTest.kt
@@ -0,0 +1,74 @@
+package com.amplitude.core.platform
+
+import com.amplitude.core.Amplitude
+import com.amplitude.core.Configuration
+import com.amplitude.core.events.BaseEvent
+import io.mockk.coEvery
+import io.mockk.mockk
+import io.mockk.spyk
+import io.mockk.verify
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.jupiter.api.Test
+
+@ExperimentalCoroutinesApi
+class EventPipelineTest {
+ private lateinit var amplitude: Amplitude
+ private lateinit var networkConnectivityChecker: NetworkConnectivityChecker
+ private val config = Configuration(apiKey = "API_KEY", flushIntervalMillis = 5)
+
+ @Before
+ fun setup() {
+ amplitude = Amplitude(config)
+ networkConnectivityChecker = mockk(relaxed = true)
+ }
+
+ @Test
+ fun `should not flush when put and offline`() =
+ runBlocking {
+ coEvery { networkConnectivityChecker.isConnected() } returns false
+ val eventPipeline = spyk(EventPipeline(amplitude, networkConnectivityChecker))
+ val event = BaseEvent().apply { eventType = "test_event" }
+
+ eventPipeline.start()
+ eventPipeline.put(event)
+ delay(6)
+
+ verify(exactly = 0) { eventPipeline.flush() }
+ }
+
+ @Test
+ fun `should flush when put and online`() =
+ runBlocking {
+ coEvery { networkConnectivityChecker.isConnected() } returns true
+ val eventPipeline = spyk(EventPipeline(amplitude, networkConnectivityChecker))
+ val event = BaseEvent().apply { eventType = "test_event" }
+
+ eventPipeline.start()
+ eventPipeline.put(event)
+ delay(6)
+
+ verify(exactly = 1) { eventPipeline.flush() }
+ }
+
+ @Test
+ fun `should flush when back to online and an event is tracked`() =
+ runBlocking {
+ coEvery { networkConnectivityChecker.isConnected() } returns false
+ val eventPipeline = spyk(EventPipeline(amplitude, networkConnectivityChecker))
+ val event1 = BaseEvent().apply { eventType = "test_event1" }
+ val event2 = BaseEvent().apply { eventType = "test_event2" }
+
+ eventPipeline.start()
+ eventPipeline.put(event1)
+ delay(6)
+
+ coEvery { networkConnectivityChecker.isConnected() } returns true
+ eventPipeline.put(event2)
+ delay(6)
+
+ verify(exactly = 1) { eventPipeline.flush() }
+ }
+}