1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.tools.integration 18 19 import android.app.Instrumentation 20 import android.graphics.Region 21 import android.tools.Timestamps 22 import android.tools.device.apphelpers.MessagingAppHelper 23 import android.tools.flicker.AssertionInvocationGroup 24 import android.tools.flicker.FlickerConfig 25 import android.tools.flicker.ScenarioInstance 26 import android.tools.flicker.annotation.ExpectedScenarios 27 import android.tools.flicker.annotation.FlickerConfigProvider 28 import android.tools.flicker.assertions.FlickerTest 29 import android.tools.flicker.assertors.AssertionTemplate 30 import android.tools.flicker.config.FlickerConfig 31 import android.tools.flicker.config.FlickerConfigEntry 32 import android.tools.flicker.config.FlickerServiceConfig 33 import android.tools.flicker.config.ScenarioId 34 import android.tools.flicker.extractors.ScenarioExtractor 35 import android.tools.flicker.extractors.TraceSlice 36 import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner 37 import android.tools.flicker.subject.FlickerSubject 38 import android.tools.flicker.subject.layers.LayersTraceSubject 39 import android.tools.flicker.subject.region.RegionSubject 40 import android.tools.flicker.subject.wm.WindowManagerTraceSubject 41 import android.tools.io.Reader 42 import android.tools.traces.parsers.WindowManagerStateHelper 43 import androidx.test.platform.app.InstrumentationRegistry 44 import com.google.common.truth.Truth 45 import org.junit.After 46 import org.junit.Before 47 import org.junit.Test 48 import org.junit.runner.RunWith 49 50 /** 51 * Contains an integration test running a flicker service test using 52 * [FlickerServiceJUnit4ClassRunner]. 53 * 54 * To run this test: `atest FlickerLibTestE2e:FullServiceRunTest` 55 */ 56 @RunWith(FlickerServiceJUnit4ClassRunner::class) 57 class FullServiceRunTest { 58 private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() 59 private val wmHelper = WindowManagerStateHelper(instrumentation) 60 private val testApp = MessagingAppHelper(instrumentation) 61 62 @Before setupnull63 fun setup() { 64 // Nothing to do 65 } 66 67 @ExpectedScenarios(["ENTIRE_TRACE"]) 68 @Test openAppnull69 fun openApp() { 70 testApp.launchViaIntent(wmHelper) 71 } 72 73 @After teardownnull74 fun teardown() { 75 testApp.exit(wmHelper) 76 } 77 78 companion object { 79 @JvmStatic 80 @FlickerConfigProvider flickerConfigProvidernull81 fun flickerConfigProvider(): FlickerConfig = 82 FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(CUSTOM_CONFIG) 83 84 val CUSTOM_CONFIG = 85 FlickerConfigEntry( 86 scenarioId = ScenarioId("MY_CUSTOM_SCENARIO"), 87 extractor = 88 object : ScenarioExtractor { 89 override fun extract(reader: Reader): List<TraceSlice> { 90 return listOf(TraceSlice(Timestamps.min(), Timestamps.max())) 91 } 92 }, 93 assertions = 94 mapOf( 95 object : AssertionTemplate("internalWmCheck") { doEvaluatenull96 override fun doEvaluate( 97 scenarioInstance: ScenarioInstance, 98 flicker: FlickerTest, 99 ) { 100 var trace: WindowManagerTraceSubject? = null 101 var executionCount = 0 102 flicker.assertWm { 103 executionCount++ 104 trace = this 105 this.isNotEmpty() 106 107 Truth.assertWithMessage("Execution count") 108 .that(executionCount) 109 .isEqualTo(1) 110 } 111 flicker.assertWm { 112 executionCount++ 113 val failure: Result<Any> = runCatching { this.isEmpty() } 114 if (failure.isSuccess) { 115 error("Should have thrown failure") 116 } 117 118 Truth.assertWithMessage("Execution count") 119 .that(executionCount) 120 .isEqualTo(2) 121 } 122 flicker.assertWmStart { 123 executionCount++ 124 validateState(this, trace?.first()) 125 validateVisibleRegion( 126 this.visibleRegion(), 127 trace?.first()?.visibleRegion(), 128 ) 129 130 Truth.assertWithMessage("Execution count") 131 .that(executionCount) 132 .isEqualTo(3) 133 } 134 flicker.assertWmEnd { 135 executionCount++ 136 validateState(this, trace?.last()) 137 validateVisibleRegion( 138 this.visibleRegion(), 139 trace?.last()?.visibleRegion(), 140 ) 141 142 Truth.assertWithMessage("Execution count") 143 .that(executionCount) 144 .isEqualTo(4) 145 } 146 } 147 } to AssertionInvocationGroup.BLOCKING, 148 object : AssertionTemplate("internalLayersCheck") { doEvaluatenull149 override fun doEvaluate( 150 scenarioInstance: ScenarioInstance, 151 flicker: FlickerTest, 152 ) { 153 var trace: LayersTraceSubject? = null 154 var executionCount = 0 155 flicker.assertLayers { 156 executionCount++ 157 trace = this 158 this.isNotEmpty() 159 160 Truth.assertWithMessage("Execution count") 161 .that(executionCount) 162 .isEqualTo(1) 163 } 164 flicker.assertLayers { 165 executionCount++ 166 val failure: Result<Any> = runCatching { this.isEmpty() } 167 if (failure.isSuccess) { 168 error("Should have thrown failure") 169 } 170 171 Truth.assertWithMessage("Execution count") 172 .that(executionCount) 173 .isEqualTo(2) 174 } 175 flicker.assertLayersStart { 176 executionCount++ 177 validateState(this, trace?.first()) 178 validateVisibleRegion( 179 this.visibleRegion(), 180 trace?.first()?.visibleRegion(), 181 ) 182 183 Truth.assertWithMessage("Execution count") 184 .that(executionCount) 185 .isEqualTo(3) 186 } 187 flicker.assertLayersEnd { 188 executionCount++ 189 validateState(this, trace?.last()) 190 validateVisibleRegion( 191 this.visibleRegion(), 192 trace?.last()?.visibleRegion(), 193 ) 194 195 Truth.assertWithMessage("Execution count") 196 .that(executionCount) 197 .isEqualTo(4) 198 } 199 } 200 } to AssertionInvocationGroup.BLOCKING, 201 ), 202 enabled = true, 203 ) 204 validateStatenull205 private fun validateState(actual: FlickerSubject?, expected: FlickerSubject?) { 206 Truth.assertWithMessage("Actual state").that(actual).isNotNull() 207 Truth.assertWithMessage("Expected state").that(expected).isNotNull() 208 } 209 validateVisibleRegionnull210 private fun validateVisibleRegion(actual: RegionSubject?, expected: RegionSubject?) { 211 Truth.assertWithMessage("Actual visible region").that(actual).isNotNull() 212 Truth.assertWithMessage("Expected visible region").that(expected).isNotNull() 213 actual?.coversExactly(expected?.region ?: Region()) 214 215 val failure: Result<Any?> = runCatching { 216 actual?.isHigher(expected?.region ?: Region()) 217 } 218 if (failure.isSuccess) { 219 error("Should have thrown failure") 220 } 221 } 222 } 223 } 224