[#278] Fix Firebase Test Lab configuration

This commit is contained in:
Carter Jernigan 2022-03-16 15:26:39 -04:00 committed by Carter Jernigan
parent 5b8aaaaed9
commit fb5fc153a5
6 changed files with 138 additions and 16 deletions

View File

@ -121,7 +121,7 @@ jobs:
run: |
mkdir ${ARTIFACTS_DIR_PATH}
zip -r ${REPORTS_ZIP_PATH} . -i build/reports/ktlint/*
zip -r ${REPORTS_ZIP_PATH} . -i build/reports/ktlint/\*
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
@ -151,6 +151,7 @@ jobs:
run: |
./gradlew :app:lintZcashmainnetRelease
- name: Collect Artifacts
if: ${{ always() }}
timeout-minutes: 1
env:
ARTIFACTS_DIR_PATH: ${{ format('{0}/artifacts', env.home) }}
@ -159,6 +160,7 @@ jobs:
mkdir ${ARTIFACTS_DIR_PATH}
zip -r ${LINT_ZIP_PATH} . -i *build/reports/*
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
timeout-minutes: 1
with:
@ -184,6 +186,7 @@ jobs:
# Note that we explicitly check just the Kotlin modules, to avoid compiling the Android modules here
./gradlew :preference-api-lib:check
- name: Collect Artifacts
if: ${{ always() }}
timeout-minutes: 1
env:
ARTIFACTS_DIR_PATH: ${{ format('{0}/artifacts', env.home) }}
@ -192,6 +195,7 @@ jobs:
mkdir ${ARTIFACTS_DIR_PATH}
zip -r ${RESULTS_ZIP_PATH} . -i *build/reports/*
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
timeout-minutes: 1
with:
@ -232,10 +236,12 @@ jobs:
# This first environment variable is used by Flank, since the temporary token is missing the project name
GOOGLE_CLOUD_PROJECT: ${{ secrets.FIREBASE_TEST_LAB_PROJECT }}
ORG_GRADLE_PROJECT_ZCASH_FIREBASE_TEST_LAB_API_KEY_PATH: ${{ steps.auth_test_lab.outputs.credentials_file_path }}
# Because Fulladle doesn't allow Test Orchestrator to be enabled/disabled for a specific submodule, it must be enabled for all modules
ORG_GRADLE_PROJECT_IS_USE_TEST_ORCHESTRATOR: true
run: |
# NEED Firebase Test Lab API key
# ./gradlew runFlank --parallel
./gradlew runFlank --parallel
- name: Collect Artifacts
if: ${{ always() }}
timeout-minutes: 1
env:
ARTIFACTS_DIR_PATH: ${{ format('{0}/artifacts', env.home) }}
@ -243,8 +249,9 @@ jobs:
run: |
mkdir ${ARTIFACTS_DIR_PATH}
zip -r ${TEST_RESULTS_ZIP_PATH} . -i *build/outputs/androidTest-results/*
zip -r ${TEST_RESULTS_ZIP_PATH} . -i build/fladle/\* \*/build/outputs/androidTest-results/\*
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
timeout-minutes: 1
with:

View File

@ -4,6 +4,7 @@ plugins {
id("kotlin-parcelize")
id("zcash.android-build-conventions")
id("com.github.triplet.play")
id("com.osacky.fladle")
}
val packageName = "co.electriccoin.zcash"
@ -146,6 +147,7 @@ dependencies {
androidTestImplementation(libs.androidx.uiAutomator)
androidTestImplementation(libs.bundles.androidx.test)
androidTestImplementation(projects.sdkExtLib)
androidTestImplementation(projects.spackleLib)
if (isOrchestratorEnabled) {
androidTestUtil(libs.androidx.test.orchestrator) {
@ -222,3 +224,48 @@ tasks.whenTaskAdded {
finalizedBy(fetchScreenshotsTask)
}
}
// Firebase Test Lab has min and max values that might differ from our project's
// These are determined by `gcloud firebase test android models list`
@Suppress("MagicNumber", "PropertyName", "VariableNaming")
val FIREBASE_TEST_LAB_MIN_API = 23
@Suppress("MagicNumber", "PropertyName", "VariableNaming")
val FIREBASE_TEST_LAB_MAX_API = 30
val firebaseTestLabKeyPath = project.properties["ZCASH_FIREBASE_TEST_LAB_API_KEY_PATH"].toString()
if (firebaseTestLabKeyPath.isNotBlank()) {
val minSdkVersion = run {
val buildMinSdk =
project.properties["ANDROID_MIN_SDK_VERSION"].toString().toInt()
buildMinSdk.coerceAtLeast(FIREBASE_TEST_LAB_MIN_API).toString()
}
val targetSdkVersion = run {
val buildTargetSdk =
project.properties["ANDROID_TARGET_SDK_VERSION"].toString().toInt()
buildTargetSdk.coerceAtMost(FIREBASE_TEST_LAB_MAX_API).toString()
}
fladle {
serviceAccountCredentials.set(File(firebaseTestLabKeyPath))
configs {
create("sanityConfig") {
clearPropertiesForSanityRobo()
debugApk.set(
project.provider {
"${buildDir}/outputs/apk/zcashmainnet/release/app-zcashmainnet-release.apk"
}
)
testTimeout.set("5m")
devices.addAll(
mapOf("model" to "Nexus6", "version" to minSdkVersion),
mapOf("model" to "Pixel2", "version" to targetSdkVersion)
)
}
}
}
}

View File

@ -16,7 +16,9 @@ import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
@ -26,6 +28,7 @@ import cash.z.ecc.sdk.fixture.WalletAddressFixture
import cash.z.ecc.sdk.model.MonetarySeparators
import co.electriccoin.zcash.app.test.EccScreenCaptureProcessor
import co.electriccoin.zcash.app.test.getStringResource
import co.electriccoin.zcash.spackle.FirebaseTestLabUtil
import co.electriccoin.zcash.ui.MainActivity
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.screen.backup.BackupTag
@ -39,6 +42,8 @@ import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
// TODO [#285]: Screenshot tests fail on older devices due to issue granting external storage permission
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
class ScreenshotTest {
companion object {
@ -80,6 +85,11 @@ class ScreenshotTest {
@Test
@SmallTest
fun take_screenshots_for_restore_wallet() {
// TODO [#286]: Screenshot tests fail on Firebase Test Lab
if (FirebaseTestLabUtil.isFirebaseTestLab(ApplicationProvider.getApplicationContext())) {
return
}
composeTestRule.waitUntil { composeTestRule.activity.walletViewModel.secretState.value is SecretState.None }
composeTestRule.onNodeWithText(getStringResource(R.string.onboarding_1_header)).also {
@ -124,6 +134,11 @@ class ScreenshotTest {
@Test
@SmallTest
fun take_screenshots_for_new_wallet_and_rest_of_app() {
// TODO [#286]: Screenshot tests fail on Firebase Test Lab
if (FirebaseTestLabUtil.isFirebaseTestLab(ApplicationProvider.getApplicationContext())) {
return
}
onboardingScreenshots(composeTestRule)
backupScreenshots(composeTestRule)
homeScreenshots(composeTestRule)

View File

@ -69,13 +69,21 @@ if (firebaseTestLabKeyPath.isNotBlank()) {
}
fladle {
serviceAccountCredentials.set(File(firebaseTestLabKeyPath))
// TODO [#282]: Replace this with NexusLowRes once tests pass on larger screen sizes
devices.addAll(
mapOf("model" to "NexusLowRes", "version" to minSdkVersion),
mapOf("model" to "NexusLowRes", "version" to targetSdkVersion)
mapOf("model" to "Nexus6", "version" to minSdkVersion),
mapOf("model" to "Pixel2", "version" to targetSdkVersion)
)
@Suppress("MagicNumber")
flakyTestAttempts.set(2)
if (project.properties["IS_USE_TEST_ORCHESTRATOR"].toString().toBoolean()) {
useOrchestrator.set(true)
environmentVariables.set(mapOf("clearPackageData" to "true"))
} else {
useOrchestrator.set(false)
}
}
}

View File

@ -5,6 +5,10 @@ plugins {
id("zcash.android-build-conventions")
}
// Force orchestrator to be used for this module, because we need the preference files
// to be purged between tests
val isOrchestratorEnabled = true
android {
// TODO [#6]: Figure out how to move this into the build-conventions
kotlinOptions {
@ -13,14 +17,15 @@ android {
freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn"
}
// Force orchestrator to be used for this module, because we need the preference files
// to be purged between tests
defaultConfig {
testInstrumentationRunnerArguments["clearPackageData"] = "true"
}
testOptions {
execution = "ANDROIDX_TEST_ORCHESTRATOR"
if (isOrchestratorEnabled) {
defaultConfig {
testInstrumentationRunnerArguments["clearPackageData"] = "true"
}
testOptions {
execution = "ANDROIDX_TEST_ORCHESTRATOR"
}
}
}
@ -34,9 +39,11 @@ dependencies {
androidTestImplementation(libs.bundles.androidx.test)
androidTestImplementation(libs.kotlinx.coroutines.test)
androidTestUtil(libs.androidx.test.orchestrator) {
artifact {
type = "apk"
if (isOrchestratorEnabled) {
androidTestUtil(libs.androidx.test.orchestrator) {
artifact {
type = "apk"
}
}
}
}

View File

@ -0,0 +1,38 @@
package co.electriccoin.zcash.spackle
import android.content.Context
import android.provider.Settings
/*
* This is not under a test module, because there are some code paths that we might want to alter
* during Google Play Prelaunch reports.
*/
object FirebaseTestLabUtil {
private const val FIREBASE_TEST_LAB_SETTING = "firebase.test.lab" // $NON-NLS
private const val SETTING_TRUE = "true" // $NON-NLS
private val isFirebaseTestLabCached = LazyWithArgument<Context, Boolean> {
isFirebaseTestLabImpl(it)
}
/**
* @return True if the environment is Firebase Test Lab.
*/
fun isFirebaseTestLab(context: Context) = isFirebaseTestLabCached.getInstance(context)
private fun isFirebaseTestLabImpl(context: Context): Boolean {
/*
* Per the documentation at https://firebase.google.com/docs/test-lab/android-studio
*/
// Tested with the benchmark library, this is very fast. There shouldn't be a need to make
// this a suspend function. That said, we'll still cache the result as a just-in-case
// since IPC may be involved.
return runCatching {
SETTING_TRUE == Settings.System.getString(context.contentResolver, FIREBASE_TEST_LAB_SETTING)
}.recover {
// Fail-safe in case an error occurs
// 99.9% of the time, it won't be Firebase Test Lab
false
}.getOrThrow()
}
}