Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add end-to-end emulator test running on CI #553

Merged
merged 5 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
container:
image: ghcr.io/cirruslabs/android-sdk:33
kvm: true
cpu: 8
memory: 16G

instrumentation_tests_task:
name: "Cirrus CI Instrumentation Tests"
skip: "!changesInclude('.cirrus.yml', '*.gradle', '*.gradle.kts', '**/*.gradle', '**/*.gradle.kts', '*.properties', '**/*.properties', '**/*.kt', '**/*.xml')"
start_avd_background_script:
sdkmanager --install "system-images;android-33;google_apis;x86_64";
echo no | avdmanager create avd -n seedvault -k "system-images;android-33;google_apis;x86_64";
$ANDROID_HOME/emulator/emulator
-avd seedvault
-no-audio
-no-boot-anim
-gpu swiftshader_indirect
-no-snapshot
-no-window
-writable-system;
provision_avd_background_script:
wget https://github.com/seedvault-app/seedvault-test-data/releases/download/1/backup.tar.gz;

adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;';
adb root;
sleep 5;
adb remount;
adb reboot;
adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;';
adb root;
sleep 5;
adb remount;
sleep 5;
assemble_script:
./gradlew :app:assembleRelease :app:assembleAndroidTest
install_app_script:
timeout 180s bash -c 'while [[ -z $(adb shell mount | grep "/system " | grep "(rw,") ]]; do sleep 1; done;';
adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;';

adb shell mkdir -p /sdcard/seedvault_baseline;
adb push backup.tar.gz /sdcard/seedvault_baseline/backup.tar.gz;
adb shell tar xzf /sdcard/seedvault_baseline/backup.tar.gz --directory=/sdcard/seedvault_baseline;

adb shell mkdir -p /system/priv-app/Seedvault;
adb push app/build/outputs/apk/release/app-release.apk /system/priv-app/Seedvault/Seedvault.apk;
adb push permissions_com.stevesoltys.seedvault.xml /system/etc/permissions/privapp-permissions-seedvault.xml;
adb push allowlist_com.stevesoltys.seedvault.xml /system/etc/sysconfig/allowlist-seedvault.xml;
adb shell bmgr enable true;
adb shell bmgr transport com.stevesoltys.seedvault.transport.ConfigurableBackupTransport;
adb reboot;
adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;';
run_large_tests_script: ./gradlew -Pinstrumented_test_size=large :app:connectedAndroidTest
run_medium_tests_script: ./gradlew -Pinstrumented_test_size=medium :app:connectedAndroidTest
always:
pull_screenshots_script:
adb pull /sdcard/seedvault_test_videos
screenshots_artifacts:
path: "seedvault_test_videos/**/*.mp4"
6 changes: 3 additions & 3 deletions .idea/runConfigurations/app_emulator.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 24 additions & 4 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ android {
minSdk 32 // leave at 32 for robolectric tests
targetSdk rootProject.ext.targetSdk
versionNameSuffix "-$gitDescribe"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "com.stevesoltys.seedvault.KoinInstrumentationTestRunner"
grote marked this conversation as resolved.
Show resolved Hide resolved
testInstrumentationRunnerArguments disableAnalytics: 'true'

if (project.hasProperty('instrumented_test_size')) {
final testSize = project.getProperty('instrumented_test_size')
println("Instrumented test size: $testSize")

testInstrumentationRunnerArguments size: testSize
}
}

buildTypes {
Expand Down Expand Up @@ -150,10 +157,12 @@ dependencies {
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit5_version"
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:$junit5_version"

androidTestImplementation rootProject.ext.aosp_libs
stevesoltys marked this conversation as resolved.
Show resolved Hide resolved
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test:rules:1.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation "io.mockk:mockk-android:$mockk_version"
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
}

apply from: "${rootProject.rootDir}/gradle/ktlint.gradle"
Expand Down Expand Up @@ -182,7 +191,7 @@ tasks.register('provisionEmulator', Exec) {
"seedvault",
"system-images;android-33;google_apis;x86_64"

environment "ANDROID_SDK_HOME", android.sdkDirectory.absolutePath
environment "ANDROID_HOME", android.sdkDirectory.absolutePath
environment "JAVA_HOME", System.properties['java.home']
}
}
Expand All @@ -193,7 +202,7 @@ tasks.register('startEmulator', Exec) {
doFirst {
commandLine "${project.projectDir}/development/scripts/start_emulator.sh", "seedvault"

environment "ANDROID_SDK_HOME", android.sdkDirectory.absolutePath
environment "ANDROID_HOME", android.sdkDirectory.absolutePath
environment "JAVA_HOME", System.properties['java.home']
}
}
Expand All @@ -206,7 +215,18 @@ tasks.register('installEmulatorRelease', Exec) {
doFirst {
commandLine "${project.projectDir}/development/scripts/install_app.sh"

environment "ANDROID_SDK_HOME", android.sdkDirectory.absolutePath
environment "ANDROID_HOME", android.sdkDirectory.absolutePath
environment "JAVA_HOME", System.properties['java.home']
}
}

tasks.register('clearEmulatorAppData', Exec) {
group("emulator")

doFirst {
commandLine "${project.projectDir}/development/scripts/clear_app_data.sh"

environment "ANDROID_HOME", android.sdkDirectory.absolutePath
environment "JAVA_HOME", System.properties['java.home']
}
}
22 changes: 22 additions & 0 deletions app/development/scripts/clear_app_data.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash

# assert ANDROID_HOME is set
if [ -z "$ANDROID_HOME" ]; then
echo "ANDROID_HOME is not set"
exit 1
fi

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
DEVELOPMENT_DIR=$SCRIPT_DIR/..
ROOT_PROJECT_DIR=$SCRIPT_DIR/../../..

EMULATOR_DEVICE_NAME=$($ANDROID_HOME/platform-tools/adb devices | grep emulator | cut -f1)

if [ -z "$EMULATOR_DEVICE_NAME" ]; then
echo "Emulator device name not found"
exit 1
fi

ADB="$ANDROID_HOME/platform-tools/adb -s $EMULATOR_DEVICE_NAME"

$ADB shell pm clear com.stevesoltys.seedvault
8 changes: 4 additions & 4 deletions app/development/scripts/install_app.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
#!/usr/bin/env bash

# assert ANDROID_HOME is set
if [ -z "$ANDROID_SDK_HOME" ]; then
echo "ANDROID_SDK_HOME is not set"
if [ -z "$ANDROID_HOME" ]; then
echo "ANDROID_HOME is not set"
exit 1
fi

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
DEVELOPMENT_DIR=$SCRIPT_DIR/..
ROOT_PROJECT_DIR=$SCRIPT_DIR/../../..

EMULATOR_DEVICE_NAME=$($ANDROID_SDK_HOME/platform-tools/adb devices | grep emulator | cut -f1)
EMULATOR_DEVICE_NAME=$($ANDROID_HOME/platform-tools/adb devices | grep emulator | cut -f1)

if [ -z "$EMULATOR_DEVICE_NAME" ]; then
echo "Emulator device name not found"
exit 1
fi

ADB="$ANDROID_SDK_HOME/platform-tools/adb -s $EMULATOR_DEVICE_NAME"
ADB="$ANDROID_HOME/platform-tools/adb -s $EMULATOR_DEVICE_NAME"

$ADB root
sleep 3 # wait for adb to restart
Expand Down
24 changes: 16 additions & 8 deletions app/development/scripts/provision_emulator.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/usr/bin/env bash

# assert ANDROID_HOME is set
if [ -z "$ANDROID_SDK_HOME" ]; then
echo "ANDROID_SDK_HOME is not set"
if [ -z "$ANDROID_HOME" ]; then
echo "ANDROID_HOME is not set"
exit 1
fi

Expand All @@ -20,30 +20,29 @@ DEVELOPMENT_DIR=$SCRIPT_DIR/..
ROOT_PROJECT_DIR=$SCRIPT_DIR/../../..

echo "Downloading system image..."
$ANDROID_SDK_HOME/cmdline-tools/latest/bin/sdkmanager --install "$SYSTEM_IMAGE"
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --install "$SYSTEM_IMAGE"

# create AVD if it doesn't exist
if $ANDROID_SDK_HOME/cmdline-tools/latest/bin/avdmanager list avd | grep -q "$EMULATOR_NAME"; then
if $ANDROID_HOME/cmdline-tools/latest/bin/avdmanager list avd | grep -q "$EMULATOR_NAME"; then
echo "AVD already exists. Skipping creation."
else
echo "Creating AVD..."
echo 'no' | $ANDROID_SDK_HOME/cmdline-tools/latest/bin/avdmanager create avd -n "$EMULATOR_NAME" -k "$SYSTEM_IMAGE"
echo 'no' | $ANDROID_HOME/cmdline-tools/latest/bin/avdmanager create avd -n "$EMULATOR_NAME" -k "$SYSTEM_IMAGE"
sleep 1
fi

echo "Starting emulator..."
$SCRIPT_DIR/start_emulator.sh "$EMULATOR_NAME"
sleep 3

# get emulator device name from ADB
EMULATOR_DEVICE_NAME=$($ANDROID_SDK_HOME/platform-tools/adb devices | grep emulator | cut -f1)
EMULATOR_DEVICE_NAME=$($ANDROID_HOME/platform-tools/adb devices | grep emulator | cut -f1)

if [ -z "$EMULATOR_DEVICE_NAME" ]; then
echo "Emulator device name not found"
exit 1
fi

ADB="$ANDROID_SDK_HOME/platform-tools/adb -s $EMULATOR_DEVICE_NAME"
ADB="$ANDROID_HOME/platform-tools/adb -s $EMULATOR_DEVICE_NAME"

echo "Waiting for emulator to boot..."
$ADB wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;'
Expand All @@ -68,4 +67,13 @@ echo "Rebooting emulator..."
$ADB reboot
$ADB wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;'

echo "Downloading and extracting test backup to '/sdcard/seedvault'..."
wget https://github.com/seedvault-app/seedvault-test-data/releases/download/1/backup.tar.gz
$ADB push backup.tar.gz /sdcard/
rm backup.tar.gz

$ADB shell mkdir -p /sdcard/seedvault_baseline
$ADB shell tar xzf /sdcard/backup.tar.gz --directory=/sdcard/seedvault_baseline
$ADB shell rm /sdcard/backup.tar.gz

echo "Emulator '$EMULATOR_NAME' has been provisioned with Seedvault!"
6 changes: 3 additions & 3 deletions app/development/scripts/start_emulator.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/usr/bin/env bash

# assert ANDROID_HOME is set
if [ -z "$ANDROID_SDK_HOME" ]; then
echo "ANDROID_SDK_HOME is not set"
if [ -z "$ANDROID_HOME" ]; then
echo "ANDROID_HOME is not set"
exit 1
fi

Expand All @@ -19,4 +19,4 @@ DEVELOPMENT_DIR=$SCRIPT_DIR/..
ROOT_PROJECT_DIR=$SCRIPT_DIR/../../..

echo "Starting emulator..."
nohup $ANDROID_SDK_HOME/emulator/emulator -avd "$EMULATOR_NAME" -gpu swiftshader_indirect -writable-system -no-snapshot-load >/dev/null 2>&1 &
nohup $ANDROID_HOME/emulator/emulator -avd "$EMULATOR_NAME" -gpu swiftshader_indirect -writable-system -no-snapshot-load >/dev/null 2>&1 &
1 change: 0 additions & 1 deletion app/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application android:extractNativeLibs="true" />
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.stevesoltys.seedvault

import com.stevesoltys.seedvault.restore.RestoreViewModel
import com.stevesoltys.seedvault.transport.backup.FullBackup
import com.stevesoltys.seedvault.transport.backup.InputFactory
import com.stevesoltys.seedvault.transport.backup.KVBackup
import com.stevesoltys.seedvault.transport.restore.FullRestore
import com.stevesoltys.seedvault.transport.restore.KVRestore
import com.stevesoltys.seedvault.transport.restore.OutputFactory
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import io.mockk.spyk
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.core.module.Module
import org.koin.dsl.module

internal var currentRestoreViewModel: RestoreViewModel? = null

class KoinInstrumentationTestApp : App() {

override fun appModules(): List<Module> {
val testModule = module {
val context = this@KoinInstrumentationTestApp

single { spyk(BackupNotificationManager(context)) }
single { spyk(FullBackup(get(), get(), get(), get())) }
single { spyk(KVBackup(get(), get(), get(), get(), get())) }
single { spyk(InputFactory()) }

single { spyk(FullRestore(get(), get(), get(), get(), get())) }
single { spyk(KVRestore(get(), get(), get(), get(), get(), get())) }
single { spyk(OutputFactory()) }

viewModel {
currentRestoreViewModel =
spyk(RestoreViewModel(context, get(), get(), get(), get(), get(), get()))
currentRestoreViewModel!!
}
}

return super.appModules().plus(testModule)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.stevesoltys.seedvault

import android.app.Application
import android.content.Context
import androidx.test.runner.AndroidJUnitRunner

class KoinInstrumentationTestRunner : AndroidJUnitRunner() {

override fun newApplication(
classLoader: ClassLoader?,
className: String?,
context: Context?,
): Application {
return super.newApplication(
classLoader,
KoinInstrumentationTestApp::class.java.name,
context
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.stevesoltys.seedvault

import androidx.test.core.content.pm.PackageInfoBuilder
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.test.platform.app.InstrumentationRegistry
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
Expand All @@ -28,6 +29,7 @@ import org.koin.core.component.inject

@RunWith(AndroidJUnit4::class)
@Suppress("BlockingMethodInNonBlockingContext")
@MediumTest
class PluginTest : KoinComponent {

private val context = InstrumentationRegistry.getInstrumentation().targetContext
Expand Down
Loading