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.platform.test.annotations.Presubmit
22 import android.tools.Scenario
23 import android.tools.device.apphelpers.MessagingAppHelper
24 import android.tools.flicker.annotation.FlickerServiceCompatible
25 import android.tools.flicker.junit.FlickerBuilderProvider
26 import android.tools.flicker.junit.FlickerParametersRunnerFactory
27 import android.tools.flicker.legacy.FlickerBuilder
28 import android.tools.flicker.legacy.LegacyFlickerTest
29 import android.tools.flicker.legacy.LegacyFlickerTestFactory
30 import android.tools.flicker.subject.FlickerSubject
31 import android.tools.flicker.subject.layers.LayersTraceSubject
32 import android.tools.flicker.subject.region.RegionSubject
33 import android.tools.flicker.subject.wm.WindowManagerTraceSubject
34 import android.tools.io.RunStatus
35 import android.tools.traces.parsers.WindowManagerStateHelper
36 import androidx.test.platform.app.InstrumentationRegistry
37 import com.android.launcher3.tapl.LauncherInstrumentation
38 import com.google.common.truth.Truth
39 import org.junit.Test
40 import org.junit.runner.RunWith
41 import org.junit.runners.Parameterized
42 
43 @FlickerServiceCompatible(expectedCujs = ["ENTIRE_TRACE"])
44 @RunWith(Parameterized::class)
45 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
46 class FullLegacyTestRun(private val flicker: LegacyFlickerTest) {
47     private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
48     private val testApp = MessagingAppHelper(instrumentation)
49     private val tapl: LauncherInstrumentation = LauncherInstrumentation()
50 
51     init {
52         flicker.scenario.setIsTablet(
53             WindowManagerStateHelper(instrumentation, clearCacheAfterParsing = false)
54                 .currentState
55                 .wmState
56                 .isTablet
57         )
58         tapl.setExpectedRotationCheckEnabled(true)
59     }
60 
61     /**
62      * Entry point for the test runner. It will use this method to initialize and cache flicker
63      * executions
64      */
65     @FlickerBuilderProvider
buildFlickernull66     fun buildFlicker(): FlickerBuilder {
67         return FlickerBuilder(instrumentation).apply {
68             setup { flicker.scenario.setIsTablet(wmHelper.currentState.wmState.isTablet) }
69             teardown { testApp.exit(wmHelper) }
70             transitions { testApp.launchViaIntent(wmHelper) }
71         }
72     }
73 
74     /**
75      * This is a shel test from the flicker infra to ensure the WM tracing pipeline executed
76      * entirely executed correctly
77      */
78     @Presubmit
79     @Test
internalWmChecknull80     fun internalWmCheck() {
81         var trace: WindowManagerTraceSubject? = null
82         var executionCount = 0
83         flicker.assertWm {
84             executionCount++
85             trace = this
86             this.isNotEmpty()
87         }
88         flicker.assertWm {
89             executionCount++
90             val failure: Result<Any> = runCatching { this.isEmpty() }
91             if (failure.isSuccess) {
92                 error("Should have thrown failure")
93             }
94         }
95         flicker.assertWmStart {
96             executionCount++
97             validateState(this, trace?.first())
98             validateVisibleRegion(this.visibleRegion(), trace?.first()?.visibleRegion())
99         }
100         flicker.assertWmEnd {
101             executionCount++
102             validateState(this, trace?.last())
103             validateVisibleRegion(this.visibleRegion(), trace?.last()?.visibleRegion())
104         }
105         Truth.assertWithMessage("Execution count").that(executionCount).isEqualTo(4)
106     }
107 
108     /**
109      * This is a shel test from the flicker infra to ensure the Layers tracing pipeline executed
110      * entirely executed correctly
111      */
112     @Presubmit
113     @Test
internalLayersChecknull114     fun internalLayersCheck() {
115         var trace: LayersTraceSubject? = null
116         var executionCount = 0
117         flicker.assertLayers {
118             executionCount++
119             trace = this
120             this.isNotEmpty()
121         }
122         flicker.assertLayers {
123             executionCount++
124             val failure: Result<Any> = runCatching { this.isEmpty() }
125             if (failure.isSuccess) {
126                 error("Should have thrown failure")
127             }
128         }
129         flicker.assertLayersStart {
130             executionCount++
131             validateState(this, trace?.first())
132             validateVisibleRegion(this.visibleRegion(), trace?.first()?.visibleRegion())
133         }
134         flicker.assertLayersEnd {
135             executionCount++
136             validateState(this, trace?.last())
137             validateVisibleRegion(this.visibleRegion(), trace?.last()?.visibleRegion())
138         }
139         Truth.assertWithMessage("Execution count").that(executionCount).isEqualTo(4)
140     }
141 
142     @Presubmit
143     @Test
exceptionMessageChecknull144     fun exceptionMessageCheck() {
145         val failure: Result<Any> = runCatching { flicker.assertLayers { this.isEmpty() } }
146         val exception = failure.exceptionOrNull() ?: error("Should have thrown failure")
147         Truth.assertWithMessage("Artifact path on exception")
148             .that(exception)
149             .hasMessageThat()
150             .contains(RunStatus.ASSERTION_FAILED.prefix)
151     }
152 
validateStatenull153     private fun validateState(actual: FlickerSubject?, expected: FlickerSubject?) {
154         Truth.assertWithMessage("Actual state").that(actual).isNotNull()
155         Truth.assertWithMessage("Expected state").that(expected).isNotNull()
156     }
157 
validateVisibleRegionnull158     private fun validateVisibleRegion(
159         actual: RegionSubject?,
160         expected: RegionSubject?,
161     ) {
162         Truth.assertWithMessage("Actual visible region").that(actual).isNotNull()
163         Truth.assertWithMessage("Expected visible region").that(expected).isNotNull()
164         actual?.coversExactly(expected?.region ?: Region())
165 
166         val failure: Result<Any?> = runCatching { actual?.isHigher(expected?.region ?: Region()) }
167         if (failure.isSuccess) {
168             error("Should have thrown failure")
169         }
170     }
171 
172     companion object {
173         /**
174          * Creates the test configurations.
175          *
176          * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
177          * navigation modes.
178          */
179         @Parameterized.Parameters(name = "{0}")
180         @JvmStatic
getParamsnull181         fun getParams() =
182             LegacyFlickerTestFactory.nonRotationTests(
183                 extraArgs = mapOf(Scenario.FAAS_BLOCKING to true)
184             )
185     }
186 }
187