zcash-android-wallet-sdk/demo-app-benchmark-test/src/main/java/cash/z/ecc/android/sdk/demoapp/benchmark/SyncBlockchainBenchmark.kt

113 lines
4.9 KiB
Kotlin

package cash.z.ecc.android.sdk.demoapp.benchmark
import android.content.ComponentName
import android.content.Intent
import androidx.benchmark.macro.CompilationMode
import androidx.benchmark.macro.ExperimentalMetricApi
import androidx.benchmark.macro.MacrobenchmarkScope
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.TraceSectionMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import cash.z.ecc.android.sdk.demoapp.test.UiTestPrerequisites
import cash.z.ecc.android.sdk.demoapp.test.clickAndWaitFor
import cash.z.ecc.android.sdk.demoapp.test.waitFor
import org.junit.Rule
import org.junit.Test
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
/**
* This benchmark class provides measurements and captured custom traces for investigating SDK syncing mechanisms
* with restricted blockchain range. It always resets the SDK before the next sync iteration. It uses UIAutomator to
* navigate to the Balances screen, where the whole download -> validate -> scan -> enhance process is performed and
* thus measured by this test.
*
* Run this benchmark from Android Studio only against the Benchmark build type set in all modules.
*
* We ideally run this on a physical device with Android SDK level 29, at least, as profiling is provided by this
* version and later on.
*/
// TODO [#809]: Enable macrobenchmark on CI
// TODO [#809]: https://github.com/zcash/zcash-android-wallet-sdk/issues/809
class SyncBlockchainBenchmark : UiTestPrerequisites() {
companion object {
private const val APP_TARGET_PACKAGE_NAME = "cash.z.ecc.android.sdk.demoapp.mainnet" // NON-NLS
private const val APP_TARGET_ACTIVITY_NAME = "cash.z.ecc.android.sdk.demoapp.MainActivity" // NON-NLS
private const val BALANCE_SCREEN_SECTION = "BALANCE_SCREEN" // NON-NLS
private const val BLOCKCHAIN_SYNC_SECTION = "BLOCKCHAIN_SYNC" // NON-NLS
private const val DOWNLOAD_SECTION = "DOWNLOAD" // NON-NLS
private const val VALIDATION_SECTION = "VALIDATION" // NON-NLS
private const val SCAN_SECTION = "SCAN" // NON-NLS
}
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
/**
* Advanced trace events test, which starts the Demo-app on the Home screen and then navigates to the Get Balance
* screen. SDK sync phases with restricted blockchain range are measured during the overall sync mechanism here.
*/
@Test
@OptIn(ExperimentalMetricApi::class)
fun tracesSyncBlockchain() = benchmarkRule.measureRepeated(
packageName = APP_TARGET_PACKAGE_NAME,
metrics = listOf(
TraceSectionMetric(sectionName = BALANCE_SCREEN_SECTION, mode = TraceSectionMetric.Mode.First),
TraceSectionMetric(sectionName = BLOCKCHAIN_SYNC_SECTION, mode = TraceSectionMetric.Mode.First),
TraceSectionMetric(sectionName = DOWNLOAD_SECTION, mode = TraceSectionMetric.Mode.First),
TraceSectionMetric(sectionName = VALIDATION_SECTION, mode = TraceSectionMetric.Mode.First),
TraceSectionMetric(sectionName = SCAN_SECTION, mode = TraceSectionMetric.Mode.First)
),
compilationMode = CompilationMode.Full(),
startupMode = StartupMode.COLD,
iterations = 3,
measureBlock = {
startLegacyActivityAndWait()
resetSDK()
gotoBalanceScreen()
waitForBalanceScreen()
closeBalanceScreen()
}
)
// TODO [#808]: Add demo-ui-lib module (and reference the hardcoded texts here)
// TODO [#808]: https://github.com/zcash/zcash-android-wallet-sdk/issues/808
private fun MacrobenchmarkScope.resetSDK() {
// Open toolbar overflow menu
device.findObject(By.desc("More options")).clickAndWaitFor(Until.newWindow(), 2.seconds) // NON-NLS
// Click on the reset sdk menu item
device.findObject(By.text("Reset SDK")).clickAndWaitFor(Until.newWindow(), 2.seconds) // NON-NLS
device.waitForIdle()
}
private fun MacrobenchmarkScope.waitForBalanceScreen() {
device.waitFor(Until.hasObject(By.text("Status: SYNCED")), 5.minutes) // NON-NLS
}
private fun MacrobenchmarkScope.closeBalanceScreen() {
// To close the Balance screen and disconnect from SDK Synchronizer
device.pressBack()
}
private fun MacrobenchmarkScope.gotoBalanceScreen() {
// Open drawer menu
device.findObject(By.desc("Open navigation drawer")).clickAndWaitFor(Until.newWindow(), 2.seconds) // NON-NLS
// Navigate to Balances screen
device.findObject(By.text("Get Balance")).click() // NON-NLS
}
private fun MacrobenchmarkScope.startLegacyActivityAndWait() {
val intent = Intent(Intent.ACTION_MAIN).apply {
component = ComponentName(APP_TARGET_PACKAGE_NAME, APP_TARGET_ACTIVITY_NAME)
}
startActivityAndWait(intent)
}
}