diff --git a/android/measure/src/androidTest/java/sh/measure/android/applaunch/AppLaunchCollectorTest.kt b/android/measure/src/androidTest/java/sh/measure/android/applaunch/AppLaunchCollectorTest.kt deleted file mode 100644 index 38d2423a7..000000000 --- a/android/measure/src/androidTest/java/sh/measure/android/applaunch/AppLaunchCollectorTest.kt +++ /dev/null @@ -1,123 +0,0 @@ -package sh.measure.android.applaunch - -import android.app.Application -import android.os.Bundle -import androidx.lifecycle.Lifecycle -import androidx.test.core.app.ActivityScenario -import androidx.test.platform.app.InstrumentationRegistry -import org.junit.Assert -import org.junit.Assert.assertTrue -import org.junit.Ignore -import org.junit.Test -import sh.measure.android.TestActivity -import sh.measure.android.events.EventType -import sh.measure.android.fakes.FakeEventProcessor -import sh.measure.android.fakes.NoopConfigLoader -import sh.measure.android.fakes.NoopLogger -import sh.measure.android.utils.AndroidTimeProvider -import sh.measure.android.utils.ProcessInfoProviderImpl - -internal class AppLaunchCollectorTest { - - private val logger = NoopLogger() - private val processInfoProvider = ProcessInfoProviderImpl() - private val configLoader = NoopConfigLoader() - - @Test - fun tracks_cold_launch() { - val eventProcessor = FakeEventProcessor() - coldLaunch(eventProcessor) - Assert.assertEquals(1, eventProcessor.getTrackedEventsByType(EventType.COLD_LAUNCH).size) - } - - @Test - fun triggers_cold_launch_listener() { - val eventProcessor = FakeEventProcessor() - var invoked = false - val coldLaunchListener = object : ColdLaunchListener { - override fun onColdLaunch() { - invoked = true - } - } - coldLaunch(eventProcessor, coldLaunchListener = coldLaunchListener) - assertTrue(invoked) - } - - private fun coldLaunch( - eventProcessor: FakeEventProcessor, - coldLaunchListener: ColdLaunchListener = object : ColdLaunchListener { - override fun onColdLaunch() {} - }, - savedStateBundle: Bundle? = null, - ) { - ActivityScenario.launch(TestActivity::class.java, savedStateBundle).use { scenario -> - AppLaunchCollector( - application = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application, - logger = logger, - eventProcessor = eventProcessor, - timeProvider = AndroidTimeProvider(), - processInfo = processInfoProvider, - ).apply { - register() - setColdLaunchListener(listener = coldLaunchListener) - } - scenario.moveToState(Lifecycle.State.CREATED) - scenario.moveToState(Lifecycle.State.STARTED) - scenario.moveToState(Lifecycle.State.RESUMED) - } - } - - @Test - fun tracks_warm_launch() { - val eventProcessor = FakeEventProcessor() - warmLaunch(eventProcessor) - Assert.assertEquals(1, eventProcessor.getTrackedEventsByType(EventType.WARM_LAUNCH).size) - } - - @Test - fun warm_launch_has_saved_state() { - val eventProcessor = FakeEventProcessor() - warmLaunch(eventProcessor) - val data = eventProcessor.getTrackedEventsByType(EventType.WARM_LAUNCH)[0].data - assertTrue(data is WarmLaunchData) - assertTrue((data as WarmLaunchData).has_saved_state) - } - - private fun warmLaunch(eventProcessor: FakeEventProcessor) { - ActivityScenario.launch(TestActivity::class.java).use { scenario -> - AppLaunchCollector( - application = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application, - logger = logger, - eventProcessor = eventProcessor, - timeProvider = AndroidTimeProvider(), - processInfo = processInfoProvider, - ).register() - scenario.moveToState(Lifecycle.State.CREATED) - scenario.moveToState(Lifecycle.State.STARTED) - scenario.moveToState(Lifecycle.State.RESUMED) - scenario.recreate() - } - } - - @Test - @Ignore("Unable to reproduce a hot launch") - fun tracks_hot_launch() { - val eventProcessor = FakeEventProcessor() - ActivityScenario.launch(TestActivity::class.java).use { scenario -> - AppLaunchCollector( - application = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application, - logger = logger, - eventProcessor = eventProcessor, - timeProvider = AndroidTimeProvider(), - processInfo = processInfoProvider, - ).register() - - scenario.moveToState(Lifecycle.State.CREATED) - scenario.moveToState(Lifecycle.State.STARTED) - scenario.moveToState(Lifecycle.State.RESUMED) - scenario.moveToState(Lifecycle.State.STARTED) - scenario.moveToState(Lifecycle.State.RESUMED) - } - Assert.assertEquals(1, eventProcessor.getTrackedEventsByType(EventType.HOT_LAUNCH).size) - } -} diff --git a/android/measure/src/androidTest/java/sh/measure/android/fakes/FakeEventProcessor.kt b/android/measure/src/androidTest/java/sh/measure/android/fakes/FakeEventProcessor.kt deleted file mode 100644 index 7d783f37e..000000000 --- a/android/measure/src/androidTest/java/sh/measure/android/fakes/FakeEventProcessor.kt +++ /dev/null @@ -1,115 +0,0 @@ -package sh.measure.android.fakes - -import sh.measure.android.events.Attachment -import sh.measure.android.events.EventProcessor -import sh.measure.android.exceptions.ExceptionData - -internal data class TrackedEvent( - val data: T, - val timestamp: Long, - val type: String, - val attributes: MutableMap = mutableMapOf(), - val attachments: List? = null, - val sessionId: String? = null, - val userTriggered: Boolean = false, -) - -@Suppress("MemberVisibilityCanBePrivate") -internal class FakeEventProcessor : EventProcessor { - val trackedEventsMap: MutableMap>> = mutableMapOf() - - fun getTrackedEventsByType(type: String): MutableList> { - return trackedEventsMap[type] ?: mutableListOf() - } - - override fun track(data: T, timestamp: Long, type: String) { - track( - data, - timestamp, - type, - attributes = mutableMapOf(), - attachments = null, - sessionId = null, - ) - } - - override fun track(data: T, timestamp: Long, type: String, sessionId: String) { - track( - data, - timestamp, - type, - attributes = mutableMapOf(), - attachments = null, - sessionId = sessionId, - ) - } - - override fun track( - data: T, - timestamp: Long, - type: String, - attributes: MutableMap, - attachments: MutableList, - ) { - track( - data, - timestamp, - type, - attributes = attributes, - attachments = attachments, - sessionId = null, - ) - } - - override fun trackUserTriggered(data: T, timestamp: Long, type: String) { - track( - data, - timestamp, - type, - attributes = mutableMapOf(), - attachments = null, - sessionId = null, - userTriggered = true, - ) - } - - override fun trackCrash( - data: ExceptionData, - timestamp: Long, - type: String, - attributes: MutableMap, - attachments: MutableList, - ) { - track( - data, - timestamp, - type, - attributes = attributes, - attachments = attachments, - sessionId = null, - ) - } - - private fun track( - data: T, - timestamp: Long, - type: String, - attributes: MutableMap, - attachments: List?, - sessionId: String? = null, - userTriggered: Boolean = false, - ) { - val trackedEvents = trackedEventsMap.getOrPut(type) { mutableListOf() } - trackedEvents.add( - TrackedEvent( - data = data, - timestamp = timestamp, - type = type, - attributes = attributes, - attachments = attachments, - sessionId = sessionId, - userTriggered = userTriggered, - ), - ) - } -} diff --git a/android/measure/src/androidTest/java/sh/measure/android/fakes/FakeMeasureInitializer.kt b/android/measure/src/androidTest/java/sh/measure/android/fakes/FakeMeasureInitializer.kt deleted file mode 100644 index 62a447947..000000000 --- a/android/measure/src/androidTest/java/sh/measure/android/fakes/FakeMeasureInitializer.kt +++ /dev/null @@ -1,56 +0,0 @@ -package sh.measure.android.fakes - -import sh.measure.android.MeasureInitializer -import sh.measure.android.SessionManager -import sh.measure.android.anr.AnrCollector -import sh.measure.android.appexit.AppExitCollector -import sh.measure.android.applaunch.AppLaunchCollector -import sh.measure.android.attributes.UserAttributeProcessor -import sh.measure.android.attributes.UserDefinedAttribute -import sh.measure.android.config.ConfigProvider -import sh.measure.android.events.EventProcessor -import sh.measure.android.events.UserTriggeredEventCollector -import sh.measure.android.exceptions.UnhandledExceptionCollector -import sh.measure.android.exporter.NetworkClient -import sh.measure.android.exporter.PeriodicEventExporter -import sh.measure.android.gestures.GestureCollector -import sh.measure.android.lifecycle.LifecycleCollector -import sh.measure.android.logger.Logger -import sh.measure.android.networkchange.NetworkChangesCollector -import sh.measure.android.okhttp.OkHttpEventCollector -import sh.measure.android.performance.ComponentCallbacksCollector -import sh.measure.android.performance.CpuUsageCollector -import sh.measure.android.performance.MemoryUsageCollector -import sh.measure.android.screenshot.ScreenshotCollector -import sh.measure.android.storage.DataCleanupService -import sh.measure.android.utils.ManifestReader -import sh.measure.android.utils.ResumedActivityProvider -import sh.measure.android.utils.TimeProvider - -internal class FakeMeasureInitializer : MeasureInitializer { - override lateinit var logger: Logger - override lateinit var timeProvider: TimeProvider - override lateinit var networkClient: NetworkClient - override lateinit var configProvider: ConfigProvider - override lateinit var manifestReader: ManifestReader - override lateinit var resumedActivityProvider: ResumedActivityProvider - override lateinit var eventProcessor: EventProcessor - override lateinit var userTriggeredEventCollector: UserTriggeredEventCollector - override lateinit var okHttpEventCollector: OkHttpEventCollector - override lateinit var sessionManager: SessionManager - override lateinit var unhandledExceptionCollector: UnhandledExceptionCollector - override lateinit var anrCollector: AnrCollector - override lateinit var appExitCollector: AppExitCollector - override lateinit var cpuUsageCollector: CpuUsageCollector - override lateinit var memoryUsageCollector: MemoryUsageCollector - override lateinit var componentCallbacksCollector: ComponentCallbacksCollector - override lateinit var lifecycleCollector: LifecycleCollector - override lateinit var gestureCollector: GestureCollector - override lateinit var appLaunchCollector: AppLaunchCollector - override lateinit var networkChangesCollector: NetworkChangesCollector - override lateinit var periodicEventExporter: PeriodicEventExporter - override lateinit var userAttributeProcessor: UserAttributeProcessor - override lateinit var userDefinedAttribute: UserDefinedAttribute - override lateinit var screenshotCollector: ScreenshotCollector - override lateinit var dataCleanupService: DataCleanupService -} diff --git a/android/measure/src/androidTest/java/sh/measure/android/fakes/FakeTimeProvider.kt b/android/measure/src/androidTest/java/sh/measure/android/fakes/FakeTimeProvider.kt deleted file mode 100644 index bf8db78c3..000000000 --- a/android/measure/src/androidTest/java/sh/measure/android/fakes/FakeTimeProvider.kt +++ /dev/null @@ -1,14 +0,0 @@ -package sh.measure.android.fakes - -import sh.measure.android.utils.TimeProvider - -internal class FakeTimeProvider(private val date: Long = 0) : TimeProvider { - override val currentTimeSinceEpochInMillis: Long - get() = date - override val currentTimeSinceEpochInNanos: Long - get() = date - override val uptimeInMillis: Long - get() = date - override val elapsedRealtime: Long - get() = date -} diff --git a/android/measure/src/androidTest/java/sh/measure/android/fakes/NoopConfigLoader.kt b/android/measure/src/androidTest/java/sh/measure/android/fakes/NoopConfigLoader.kt deleted file mode 100644 index fc92dd3d0..000000000 --- a/android/measure/src/androidTest/java/sh/measure/android/fakes/NoopConfigLoader.kt +++ /dev/null @@ -1,13 +0,0 @@ -package sh.measure.android.fakes - -import sh.measure.android.config.Config -import sh.measure.android.config.ConfigLoader - -internal class NoopConfigLoader : ConfigLoader { - override fun getCachedConfig(): Config? { - return null - } - - override fun getNetworkConfig(onSuccess: (Config) -> Unit) { - } -} diff --git a/android/measure/src/androidTest/java/sh/measure/android/fakes/NoopLogger.kt b/android/measure/src/androidTest/java/sh/measure/android/fakes/NoopLogger.kt deleted file mode 100644 index ee4c15f54..000000000 --- a/android/measure/src/androidTest/java/sh/measure/android/fakes/NoopLogger.kt +++ /dev/null @@ -1,11 +0,0 @@ -package sh.measure.android.fakes - -import sh.measure.android.logger.LogLevel -import sh.measure.android.logger.Logger - -internal class NoopLogger : Logger { - override var enabled: Boolean = false - override fun log(level: LogLevel, message: String, throwable: Throwable?) { - // No-op - } -} diff --git a/android/measure/src/androidTest/java/sh/measure/android/gestures/ComposeGestureCollectorTest.kt b/android/measure/src/androidTest/java/sh/measure/android/gestures/ComposeGestureCollectorTest.kt deleted file mode 100644 index b19c30885..000000000 --- a/android/measure/src/androidTest/java/sh/measure/android/gestures/ComposeGestureCollectorTest.kt +++ /dev/null @@ -1,94 +0,0 @@ -package sh.measure.android.gestures - -import androidx.test.core.app.ActivityScenario -import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.action.ViewActions.click -import androidx.test.espresso.action.ViewActions.swipeUp -import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.ext.junit.runners.AndroidJUnit4 -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull -import org.junit.Assert.assertTrue -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import sh.measure.android.events.EventType -import sh.measure.android.fakes.FakeEventProcessor -import sh.measure.android.fakes.FakeTimeProvider -import sh.measure.android.fakes.NoopLogger -import sh.measure.android.test.R - -@RunWith(AndroidJUnit4::class) -class ComposeGestureCollectorTest { - private val logger = NoopLogger() - private val timeProvider = FakeTimeProvider() - private lateinit var tracker: FakeEventProcessor - - @Before - fun setup() { - tracker = FakeEventProcessor() - GestureCollector(logger, tracker, timeProvider).register() - } - - @Test - fun tracks_clicks_on_clickable_views() { - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.clickable_compose_view)).perform(click()) - assertEquals(1, tracker.getTrackedEventsByType(EventType.CLICK).size) - } - - @Test - fun tracks_clicked_view_properties() { - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.clickable_compose_view)).perform(click()) - - val event = tracker.getTrackedEventsByType(EventType.CLICK)[0] - event.data as ClickData - assertEquals("androidx.compose.ui.platform.AndroidComposeView", event.data.target) - assertEquals("compose_clickable", event.data.target_id) - assertTrue(event.data.touch_down_time > 0) - assertTrue(event.data.touch_up_time > 0) - assertTrue(event.data.x > 0) - assertTrue(event.data.y > 0) - - // we currently don't have ability to track compose view bounds: - assertNull(event.data.width) - assertNull(event.data.height) - } - - @Test - fun ignores_clicks_on_non_clickable_views() { - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.non_clickable_compose_view)).perform(click()) - assertEquals(0, tracker.getTrackedEventsByType(EventType.CLICK).size) - } - - @Test - fun tracks_scrolls_on_scrollable_views() { - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.scrollable_compose_view)).perform(swipeUp()) - assertEquals(1, tracker.getTrackedEventsByType(EventType.SCROLL).size) - } - - @Test - fun tracks_scrollable_view_properties() { - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.scrollable_compose_view)).perform(swipeUp()) - - val event = tracker.getTrackedEventsByType(EventType.SCROLL)[0] - event.data as ScrollData - assertEquals("androidx.compose.ui.platform.AndroidComposeView", event.data.target) - assertEquals("compose_scrollable", event.data.target_id) - assertTrue(event.data.touch_down_time > 0) - assertTrue(event.data.touch_up_time > 0) - assertTrue(event.data.x > 0) - assertTrue(event.data.y > 0) - } - - @Test - fun ignores_scrolls_on_non_scrollable_views() { - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.clickable_compose_view)).perform(swipeUp()) - assertEquals(0, tracker.getTrackedEventsByType(EventType.SCROLL).size) - } -} diff --git a/android/measure/src/androidTest/java/sh/measure/android/gestures/GestureCollectorTest.kt b/android/measure/src/androidTest/java/sh/measure/android/gestures/GestureCollectorTest.kt deleted file mode 100644 index 7a06088d8..000000000 --- a/android/measure/src/androidTest/java/sh/measure/android/gestures/GestureCollectorTest.kt +++ /dev/null @@ -1,144 +0,0 @@ -package sh.measure.android.gestures - -import androidx.test.core.app.ActivityScenario -import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.action.ViewActions.click -import androidx.test.espresso.action.ViewActions.longClick -import androidx.test.espresso.action.ViewActions.swipeUp -import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.LargeTest -import org.junit.Assert -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import sh.measure.android.events.EventType -import sh.measure.android.fakes.FakeEventProcessor -import sh.measure.android.fakes.FakeTimeProvider -import sh.measure.android.fakes.NoopLogger -import sh.measure.android.test.R - -@RunWith(AndroidJUnit4::class) -@LargeTest -internal class GestureCollectorTest { - private val logger = NoopLogger() - private val timeProvider = FakeTimeProvider() - private lateinit var tracker: FakeEventProcessor - - @Before - fun setup() { - tracker = FakeEventProcessor() - } - - @Test - fun tracks_clicks_on_clickable_views() { - GestureCollector(logger, tracker, timeProvider).register() - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.button)).perform(click()) - Assert.assertEquals(1, tracker.getTrackedEventsByType(EventType.CLICK).size) - } - - @Test - fun tracks_clicked_view_properties() { - GestureCollector(logger, tracker, timeProvider).register() - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.button)).perform(click()) - - val event = tracker.getTrackedEventsByType(EventType.CLICK)[0] - event.data as ClickData - Assert.assertEquals("android.widget.Button", event.data.target) - Assert.assertEquals("button", event.data.target_id) - Assert.assertTrue(event.data.touch_down_time > 0) - Assert.assertTrue(event.data.touch_up_time > 0) - Assert.assertTrue(event.data.x > 0) - Assert.assertTrue(event.data.y > 0) - event.data.width.let { - Assert.assertNotNull(it) - Assert.assertTrue(it!! > 0) - } - event.data.height.let { - Assert.assertNotNull(it) - Assert.assertTrue(it!! > 0) - } - } - - @Test - fun ignores_clicks_on_non_clickable_views() { - GestureCollector(logger, tracker, timeProvider).register() - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.text)).perform(click()) - Assert.assertEquals(0, tracker.getTrackedEventsByType(EventType.CLICK).size) - } - - @Test - fun tracks_long_clicks_on_clickable_views() { - GestureCollector(logger, tracker, timeProvider).register() - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.button)).perform(longClick()) - Assert.assertEquals(1, tracker.getTrackedEventsByType(EventType.LONG_CLICK).size) - } - - @Test - fun tracks_long_clicked_view_properties() { - GestureCollector(logger, tracker, timeProvider).register() - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.button)).perform(longClick()) - - val event = tracker.getTrackedEventsByType(EventType.LONG_CLICK)[0] - event.data as LongClickData - Assert.assertEquals("android.widget.Button", event.data.target) - Assert.assertEquals("button", event.data.target_id) - Assert.assertTrue(event.data.touch_down_time > 0) - Assert.assertTrue(event.data.touch_up_time > 0) - Assert.assertTrue(event.data.x > 0) - Assert.assertTrue(event.data.y > 0) - event.data.width.let { - Assert.assertNotNull(it) - Assert.assertTrue(it!! > 0) - } - event.data.height.let { - Assert.assertNotNull(it) - Assert.assertTrue(it!! > 0) - } - } - - @Test - fun ignores_long_clicks_on_non_clickable_views() { - GestureCollector(logger, tracker, timeProvider).register() - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.text)).perform(longClick()) - Assert.assertEquals(0, tracker.getTrackedEventsByType(EventType.LONG_CLICK).size) - } - - @Test - fun tracks_scroll_on_scrollable_views() { - GestureCollector(logger, tracker, timeProvider).register() - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.scroll_view)).perform(swipeUp()) - Assert.assertEquals(1, tracker.getTrackedEventsByType(EventType.SCROLL).size) - } - - @Test - fun tracks_scrollable_view_properties() { - GestureCollector(logger, tracker, timeProvider).register() - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.scroll_view)).perform(swipeUp()) - - val event = tracker.getTrackedEventsByType(EventType.SCROLL)[0] - event.data as ScrollData - Assert.assertEquals("android.widget.ScrollView", event.data.target) - Assert.assertEquals("scroll_view", event.data.target_id) - Assert.assertTrue(event.data.touch_down_time > 0) - Assert.assertTrue(event.data.touch_up_time > 0) - Assert.assertTrue(event.data.x > 0) - Assert.assertTrue(event.data.y > 0) - } - - @Test - fun ignores_scrolls_on_non_scrollable_views() { - GestureCollector(logger, tracker, timeProvider).register() - ActivityScenario.launch(GestureTestActivity::class.java) - onView(withId(R.id.text)).perform(swipeUp()) - Assert.assertEquals(0, tracker.getTrackedEventsByType(EventType.SCROLL).size) - } -} diff --git a/android/measure/src/androidTest/java/sh/measure/android/gestures/GestureTestActivity.kt b/android/measure/src/androidTest/java/sh/measure/android/gestures/GestureTestActivity.kt deleted file mode 100644 index f1d599972..000000000 --- a/android/measure/src/androidTest/java/sh/measure/android/gestures/GestureTestActivity.kt +++ /dev/null @@ -1,68 +0,0 @@ -package sh.measure.android.gestures - -import android.os.Bundle -import android.widget.Button -import androidx.activity.ComponentActivity -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material3.Text -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.compose.ui.platform.testTag -import sh.measure.android.test.R - -class GestureTestActivity : ComponentActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.test_gesture_collector) - findViewById