mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-05-02 07:24:26 +02:00
Drive app migration tests through instrumentation
Make tests less flaky
This commit is contained in:
parent
08ea937f7c
commit
9e2b59060d
@ -2,13 +2,22 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||||
|
tools:ignore="QueryAllPackagesPermission" />
|
||||||
|
|
||||||
|
<queries tools:node="removeAll" />
|
||||||
|
|
||||||
<application tools:node="replace">
|
<application tools:node="replace">
|
||||||
<uses-library android:name="android.test.runner" />
|
<uses-library android:name="android.test.runner" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
<instrumentation
|
||||||
|
android:name="com.topjohnwu.magisk.test.AppTestRunner"
|
||||||
|
android:targetPackage="com.topjohnwu.magisk" />
|
||||||
|
|
||||||
<instrumentation
|
<instrumentation
|
||||||
android:name="com.topjohnwu.magisk.test.TestRunner"
|
android:name="com.topjohnwu.magisk.test.TestRunner"
|
||||||
android:targetPackage="com.topjohnwu.magisk"
|
android:targetPackage="com.topjohnwu.magisk.test" />
|
||||||
android:label="Tests for Magisk" />
|
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
package com.topjohnwu.magisk.test
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.os.ParcelFileDescriptor.AutoCloseInputStream
|
||||||
|
import androidx.annotation.Keep
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class AppMigrationTest {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val APP_PKG = "com.topjohnwu.magisk"
|
||||||
|
private const val STUB_PKG = "repackaged.$APP_PKG"
|
||||||
|
private const val RECEIVER_TIMEOUT = 20L
|
||||||
|
}
|
||||||
|
|
||||||
|
private val instrumentation get() = InstrumentationRegistry.getInstrumentation()
|
||||||
|
private val context get() = instrumentation.context
|
||||||
|
private val uiAutomation get() = instrumentation.uiAutomation
|
||||||
|
private val registeredReceivers = mutableListOf<BroadcastReceiver>()
|
||||||
|
|
||||||
|
class PackageRemoveMonitor(
|
||||||
|
context: Context,
|
||||||
|
private val packageName: String
|
||||||
|
) : BroadcastReceiver() {
|
||||||
|
|
||||||
|
val latch = CountDownLatch(1)
|
||||||
|
|
||||||
|
init {
|
||||||
|
val filter = IntentFilter(Intent.ACTION_PACKAGE_REMOVED)
|
||||||
|
filter.addDataScheme("package")
|
||||||
|
context.registerReceiver(this, filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (intent.action != Intent.ACTION_PACKAGE_REMOVED)
|
||||||
|
return
|
||||||
|
val data = intent.data ?: return
|
||||||
|
val pkg = data.schemeSpecificPart
|
||||||
|
if (pkg == packageName) latch.countDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
registeredReceivers.forEach(context::unregisterReceiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun testAppMigration(pkg: String, method: String) {
|
||||||
|
val receiver = PackageRemoveMonitor(context, pkg)
|
||||||
|
registeredReceivers.add(receiver)
|
||||||
|
|
||||||
|
// Trigger the test to run migration
|
||||||
|
val pfd = uiAutomation.executeShellCommand(
|
||||||
|
"am instrument -w --user 0 -e class .Environment#$method " +
|
||||||
|
"$pkg.test/${AppTestRunner::class.java.name}"
|
||||||
|
)
|
||||||
|
val output = AutoCloseInputStream(pfd).reader().use { it.readText() }
|
||||||
|
assertTrue("$method failed, inst out: $output", output.contains("OK ("))
|
||||||
|
|
||||||
|
// Wait for migration to complete
|
||||||
|
assertTrue(
|
||||||
|
"$pkg uninstallation failed",
|
||||||
|
receiver.latch.await(RECEIVER_TIMEOUT, TimeUnit.SECONDS)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAppHide() {
|
||||||
|
testAppMigration(APP_PKG, "setupAppHide")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAppRestore() {
|
||||||
|
testAppMigration(STUB_PKG, "setupAppRestore")
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@ import android.os.Bundle
|
|||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.runner.AndroidJUnitRunner
|
import androidx.test.runner.AndroidJUnitRunner
|
||||||
|
|
||||||
class TestRunner : AndroidJUnitRunner() {
|
open class TestRunner : AndroidJUnitRunner() {
|
||||||
override fun onCreate(arguments: Bundle) {
|
override fun onCreate(arguments: Bundle) {
|
||||||
// Support short-hand ".ClassName"
|
// Support short-hand ".ClassName"
|
||||||
arguments.getString("class")?.let {
|
arguments.getString("class")?.let {
|
||||||
@ -17,6 +17,12 @@ class TestRunner : AndroidJUnitRunner() {
|
|||||||
}
|
}
|
||||||
arguments.putString("class", classArg)
|
arguments.putString("class", classArg)
|
||||||
}
|
}
|
||||||
|
super.onCreate(arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppTestRunner : TestRunner() {
|
||||||
|
override fun onCreate(arguments: Bundle) {
|
||||||
// Force using the target context's classloader to run tests
|
// Force using the target context's classloader to run tests
|
||||||
arguments.putString("classLoader", TestClassLoader::class.java.name)
|
arguments.putString("classLoader", TestClassLoader::class.java.name)
|
||||||
super.onCreate(arguments)
|
super.onCreate(arguments)
|
@ -28,16 +28,9 @@ print_error() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# $1 = TestClass#method
|
# $1 = TestClass#method
|
||||||
# $2: boolean = isRepackaged
|
# $2 = component
|
||||||
am_instrument() {
|
am_instrument() {
|
||||||
local test_pkg
|
local out=$(adb shell am instrument -w --user 0 -e class "$1" "$2")
|
||||||
if [ -n "$2" -a "$2" ]; then
|
|
||||||
test_pkg="repackaged.com.topjohnwu.magisk.test"
|
|
||||||
else
|
|
||||||
test_pkg=com.topjohnwu.magisk.test
|
|
||||||
fi
|
|
||||||
local out=$(adb shell am instrument -w --user 0 -e class "$1" \
|
|
||||||
"$test_pkg/com.topjohnwu.magisk.test.TestRunner")
|
|
||||||
grep -q 'OK (' <<< "$out"
|
grep -q 'OK (' <<< "$out"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,27 +50,31 @@ run_setup() {
|
|||||||
# Install the test app
|
# Install the test app
|
||||||
adb install -r -g out/test.apk
|
adb install -r -g out/test.apk
|
||||||
|
|
||||||
|
local app='com.topjohnwu.magisk.test/com.topjohnwu.magisk.test.AppTestRunner'
|
||||||
|
|
||||||
# Run setup through the test app
|
# Run setup through the test app
|
||||||
am_instrument '.Environment#setupMagisk'
|
am_instrument '.Environment#setupMagisk' $app
|
||||||
# Install LSPosed
|
# Install LSPosed
|
||||||
am_instrument '.Environment#setupLsposed'
|
am_instrument '.Environment#setupLsposed' $app
|
||||||
}
|
}
|
||||||
|
|
||||||
run_tests() {
|
run_tests() {
|
||||||
|
local self='com.topjohnwu.magisk.test/com.topjohnwu.magisk.test.TestRunner'
|
||||||
|
local app='com.topjohnwu.magisk.test/com.topjohnwu.magisk.test.AppTestRunner'
|
||||||
|
local stub='repackaged.com.topjohnwu.magisk.test/com.topjohnwu.magisk.test.AppTestRunner'
|
||||||
|
|
||||||
# Run app tests
|
# Run app tests
|
||||||
am_instrument '.MagiskAppTest,.AdditionalTest'
|
am_instrument '.MagiskAppTest,.AdditionalTest' $app
|
||||||
|
|
||||||
# Test app hiding
|
# Test app hiding
|
||||||
am_instrument '.Environment#setupAppHide'
|
am_instrument '.AppMigrationTest#testAppHide' $self
|
||||||
wait_for_pm com.topjohnwu.magisk
|
|
||||||
|
|
||||||
# Make sure it still works
|
# Make sure it still works
|
||||||
am_instrument '.MagiskAppTest' true
|
am_instrument '.MagiskAppTest' $stub
|
||||||
|
|
||||||
# Test app restore
|
# Test app restore
|
||||||
am_instrument '.Environment#setupAppRestore' true
|
am_instrument '.AppMigrationTest#testAppRestore' $self
|
||||||
wait_for_pm repackaged.com.topjohnwu.magisk
|
|
||||||
|
|
||||||
# Make sure it still works
|
# Make sure it still works
|
||||||
am_instrument '.MagiskAppTest'
|
am_instrument '.MagiskAppTest' $app
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user