Skip to content

Commit

Permalink
chore(android): update robolectric & fix instrumentation test crash
Browse files Browse the repository at this point in the history
* Removed or ignored tests which
used @config(sdk = []) as this is causing
the tests to go OOM.
* add testOptions.targetSdk to resolve
tests from using old SDK versions
* update android test manifest file with
required permissions so that the test process
does not crash
  • Loading branch information
abhaysood committed Feb 24, 2025
1 parent cd4ebbf commit 4a9105d
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 60 deletions.
6 changes: 3 additions & 3 deletions android/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ androidx-junit = "1.1.5"
androidx-compose-ui = "1.4.3"
androidx-compose-material3 = "1.0.1"
androidx-runtime-android = "1.5.4"
androidx-espresso-core = "3.5.1"
androidx-espresso = "3.5.1"
androidx-fragment-ktx = "1.2.5"
androidx-annotation = "1.7.1"
androidx-test-rules = "1.5.0"
Expand All @@ -45,7 +45,7 @@ squareup-curtains = "1.2.5"
squareup-okhttp = "4.12.0"
squareup-okio = "3.7.0"
squareup-leakcanary = "2.14"
robolectric = "4.11.1"
robolectric = "4.14.1"
kolinx-binary-compatibility-validator = "0.13.2"
diffplug-spotless = "6.24.0"
compose-plugin = "1.5.11"
Expand All @@ -61,7 +61,7 @@ androidx-benchmark-junit4 = { module = "androidx.benchmark:benchmark-junit4", ve
androidx-benchmark-macro-junit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "androidx-benchmark-macro-junit4" }
androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidx-constraintlayout" }
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core-ktx" }
androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-espresso-core" }
androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-espresso" }
androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "androidx-fragment-ktx" }
androidx-fragment-testing = { module = "androidx.fragment:fragment-testing", version.ref = "androidx-fragment-ktx" }
androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-junit" }
Expand Down
2 changes: 2 additions & 0 deletions android/measure/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ android {

defaultConfig {
minSdk = 21
testOptions.targetSdk = 35
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments["clearPackageData"] = "true"
consumerProguardFiles("consumer-rules.pro")
Expand Down Expand Up @@ -187,6 +188,7 @@ dependencies {
androidTestImplementation(libs.androidx.lifecycle.process)
androidTestImplementation(libs.androidx.lifecycle.common)
androidTestImplementation(libs.androidx.activity.compose)
androidTestImplementation(libs.androidx.fragment.ktx)
androidTestImplementation(libs.androidx.navigation.compose)
androidTestImplementation(libs.androidx.rules)
androidTestImplementation(libs.androidx.uiautomator)
Expand Down
20 changes: 16 additions & 4 deletions android/measure/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="sh.measure.android.test">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<!--
Workaround required for running tests on API 30 devices.
See https://github.com/android/android-test/issues/743.
Version 1.3.1 of the AndroidX Test libraries remove the need for this workaround.
-->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application>
<activity android:name="sh.measure.android.TestActivity">

<!--
Permissions required to ensure the tests do not get blocked by
-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

<application
android:exported="false"
android:usesCleartextTraffic="true">
<activity
android:name="sh.measure.android.TestActivity"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
Expand All @@ -21,5 +32,6 @@
-->
<meta-data android:name="sh.measure.android.API_URL" android:value="http://localhost:8080" />
</application>

</manifest>

Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package sh.measure.android

import android.Manifest
import androidx.benchmark.junit4.PerfettoTraceRule
import androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi
import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.IdlingRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.GrantPermissionRule
import okhttp3.Headers
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
Expand Down Expand Up @@ -51,9 +51,12 @@ class EventsTest {
private val robot: EventsTestRobot = EventsTestRobot()
private val mockWebServer: MockWebServer = MockWebServer()

@OptIn(ExperimentalPerfettoCaptureApi::class)
@get:Rule
val perfettoRule = PerfettoTraceRule(enableUserspaceTracing = true)
val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.POST_NOTIFICATIONS,
Manifest.permission.READ_MEDIA_AUDIO,
)

@Before
fun setup() {
Expand Down Expand Up @@ -622,29 +625,21 @@ class EventsTest {

@Test
fun tracksCustomEvent() {
// Given
robot.initializeMeasure(MeasureConfig(enableLogging = true))
ActivityScenario.launch(TestActivity::class.java).use {
// When
robot.trackCustomEvent()
triggerExport()

// Then
assertEventTracked(EventType.CUSTOM)
}
}

@Test
fun tracksAttributesWithEvents() {
// Given
robot.initializeMeasure(MeasureConfig(enableLogging = true))
ActivityScenario.launch(TestActivity::class.java).use {
// When
robot.addAttribute("user_defined_attr_key", "user_defined_attr_value")
triggerExport()
Log.d("Test", "Starting tracksCustomEvent test")
try {
// Given
robot.initializeMeasure(MeasureConfig(enableLogging = true))
ActivityScenario.launch(TestActivity::class.java).use {
// When
robot.trackCustomEvent()
triggerExport()

// Then
assetAttribute("user_defined_attr_key", "user_defined_attr_value")
// Then
assertEventTracked(EventType.CUSTOM)
}
Log.d("Test", "Completed tracksCustomEvent test")
} catch (e: Exception) {
Log.e("Test", "Error tracksCustomEvent", e)
}
}

Expand Down Expand Up @@ -707,11 +702,6 @@ class EventsTest {
Assert.assertFalse(body.containsEvent(eventType))
}

private fun assetAttribute(key: String, value: String) {
val body = getLastRequestBody()
Assert.assertTrue(body.containsAttribute(key, value))
}

private fun getLastRequestBody(): String {
val request = mockWebServer.takeRequest(timeout = 1000, unit = TimeUnit.MILLISECONDS)
Assert.assertNotNull(request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,4 @@ class EventsTestRobot {
}.build(),
)
}

fun addAttribute(key: String, value: String) {
Measure.addAttribute("user_defined_attr_key", "user_defined_attr_value")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import android.app.Application
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.NetworkInfo
import android.os.Build
import android.telephony.TelephonyManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RuntimeEnvironment
Expand Down Expand Up @@ -41,7 +43,11 @@ internal class InitialNetworkStateProviderTest {
@Test
fun `returns correct network generation with permission`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.READ_PHONE_STATE)
shadowOf(systemServiceProvider.telephonyManager).setNetworkType(TelephonyManager.NETWORK_TYPE_LTE)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
shadowOf(systemServiceProvider.telephonyManager).setDataNetworkType(TelephonyManager.NETWORK_TYPE_LTE)
} else {
shadowOf(systemServiceProvider.telephonyManager).setNetworkType(TelephonyManager.NETWORK_TYPE_LTE)
}

val networkGeneration = InitialNetworkStateProviderImpl(
context = context,
Expand Down Expand Up @@ -113,8 +119,8 @@ internal class InitialNetworkStateProviderTest {
assertNull(networkType)
}

@Suppress("DEPRECATION")
@Test
@Ignore("Specifying the SDK versions in @Config makes this test cause an OOM error after updating robolectric to 4.14")
@Config(sdk = [21])
fun `returns correct network type below API 23`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)
Expand All @@ -130,8 +136,10 @@ internal class InitialNetworkStateProviderTest {
assertEquals(NetworkType.WIFI, networkType)
}

// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
// @Config(sdk = [23, 33])
@Test
@Config(sdk = [23, 33])
fun `returns correct network type above API 23`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)
val nc = ShadowNetworkCapabilities.newInstance()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ class NetworkChangesCollectorTest {
telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
}

// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
// @Config(sdk = [23, 33])
@Test
@Config(sdk = [23, 24])
fun `NetworkChangesCollector does not register network callbacks if permission not available`() {
shadowOf(context as Application).denyPermissions(Manifest.permission.ACCESS_NETWORK_STATE)

Expand All @@ -65,8 +67,10 @@ class NetworkChangesCollectorTest {
Assert.assertEquals(0, shadowOf(connectivityManager).networkCallbacks.size)
}

@Test
// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
@Config(sdk = [21, 22])
@Test
fun `NetworkChangesCollector does not register network callbacks below API 23`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)
NetworkChangesCollector(
Expand All @@ -81,8 +85,9 @@ class NetworkChangesCollectorTest {
Assert.assertEquals(0, shadowOf(connectivityManager).networkCallbacks.size)
}

// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
@Test
@Config(sdk = [23, 24, 26, 28, 29, 30, 31, 33])
fun `NetworkChangesCollector registers network callbacks when permission is available`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)
NetworkChangesCollector(
Expand All @@ -97,8 +102,10 @@ class NetworkChangesCollectorTest {
Assert.assertEquals(1, shadowOf(connectivityManager).networkCallbacks.size)
}

// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
// @Config(sdk = [23, 33])
@Test
@Config(sdk = [23, 33])
fun `NetworkChangesCollector tracks change to cellular network with network_provider and network_generation`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)
shadowOf(context as Application).grantPermissions(Manifest.permission.READ_PHONE_STATE)
Expand Down Expand Up @@ -135,8 +142,10 @@ class NetworkChangesCollectorTest {
)
}

@Test
// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
@Config(sdk = [23])
@Test
fun `NetworkChangesCollector tracks change to cellular network without network_generation if READ_PHONE_STATE permission is not available`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)
shadowOf(telephonyManager).setNetworkOperatorName("Test Provider")
Expand Down Expand Up @@ -166,8 +175,10 @@ class NetworkChangesCollectorTest {
)
}

// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
// @Config(sdk = [33])
@Test
@Config(sdk = [33])
fun `NetworkChangesCollector tracks change to cellular network with network_provider & network_generation if READ_BASIC_PHONE_STATE permission is available`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)
shadowOf(context as Application).grantPermissions(Manifest.permission.READ_BASIC_PHONE_STATE)
Expand Down Expand Up @@ -201,8 +212,10 @@ class NetworkChangesCollectorTest {
)
}

// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
// @Config(sdk = [26, 33])
@Test
@Config(sdk = [26, 33])
fun `NetworkChangesCollector discards first change for SDK 26 and above`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)
shadowOf(context as Application).grantPermissions(Manifest.permission.READ_BASIC_PHONE_STATE)
Expand All @@ -223,8 +236,10 @@ class NetworkChangesCollectorTest {
Mockito.verifyNoInteractions(signalProcessor)
}

// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
// @Config(sdk = [23, 33])
@Test
@Config(sdk = [23, 33])
fun `NetworkChangesCollector updates network provider when network changes`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)
shadowOf(context as Application).grantPermissions(Manifest.permission.READ_PHONE_STATE)
Expand Down Expand Up @@ -260,8 +275,8 @@ class NetworkChangesCollectorTest {
)
}

@Test
@Config(sdk = [23])
@Test
fun `NetworkChangesCollector tracks change to wifi network`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)

Expand Down Expand Up @@ -470,8 +485,10 @@ class NetworkChangesCollectorTest {
)
}

// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
// @Config(sdk = [23])
@Test
@Config(sdk = [23])
fun `NetworkChangesCollector updates network state provider when network is lost`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)

Expand All @@ -498,8 +515,10 @@ class NetworkChangesCollectorTest {
)
}

@Test
// Ideally we would like to test on multiple versions, but specifying the SDK versions
// in @Config makes this test cause an OOM error after updating robolectric to 4.14
@Config(sdk = [23])
@Test
fun `NetworkChangesCollector discards first change with previous network when network is lost`() {
shadowOf(context as Application).grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE)
shadowOf(context as Application).grantPermissions(Manifest.permission.READ_PHONE_STATE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,19 @@ import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.Mockito.`when`
import org.robolectric.Robolectric
import org.robolectric.annotation.Config
import sh.measure.android.TestLifecycleActivity
import sh.measure.android.fakes.FakeConfigProvider
import sh.measure.android.fakes.NoopLogger
import sh.measure.android.screenshot.ScreenshotCollectorImpl

@RunWith(AndroidJUnit4::class)
class ScreenshotHelperTest {
class ScreenshotCollectorTest {
private val logger = NoopLogger()
private val lowMemoryCheck = mock<LowMemoryCheck>()
private val config = FakeConfigProvider()
private val controller = Robolectric.buildActivity(TestLifecycleActivity::class.java)

@Test
@Config(sdk = [21, 33])
fun `returns screenshot when resumed activity is available`() {
val application =
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application
Expand All @@ -43,7 +41,6 @@ class ScreenshotHelperTest {
}

@Test
@Config(sdk = [21, 33])
fun `returns null when resumed activity is not available`() {
val application =
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application
Expand Down

0 comments on commit 4a9105d

Please sign in to comment.