• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.device.flicker.legacy
18 
19 import android.app.Instrumentation
20 import android.tools.common.io.TraceType
21 import android.tools.common.traces.surfaceflinger.LayerTraceEntry
22 import android.tools.common.traces.surfaceflinger.LayersTrace
23 import android.tools.common.traces.surfaceflinger.TransactionsTrace
24 import android.tools.common.traces.wm.TransitionsTrace
25 import android.tools.common.traces.wm.WindowManagerState
26 import android.tools.common.traces.wm.WindowManagerTrace
27 import android.tools.device.traces.getDefaultFlickerOutputDir
28 import android.tools.device.traces.monitors.ITransitionMonitor
29 import android.tools.device.traces.monitors.NoTraceMonitor
30 import android.tools.device.traces.monitors.ScreenRecorder
31 import android.tools.device.traces.monitors.events.EventLogMonitor
32 import android.tools.device.traces.monitors.surfaceflinger.LayersTraceMonitor
33 import android.tools.device.traces.monitors.surfaceflinger.TransactionsTraceMonitor
34 import android.tools.device.traces.monitors.wm.ShellTransitionTraceMonitor
35 import android.tools.device.traces.monitors.wm.WindowManagerTraceMonitor
36 import android.tools.device.traces.monitors.wm.WmTransitionTraceMonitor
37 import android.tools.device.traces.parsers.WindowManagerStateHelper
38 import androidx.test.uiautomator.UiDevice
39 import java.io.File
40 
41 /** Build Flicker tests using Flicker DSL */
42 @FlickerDslMarker
43 class FlickerBuilder(
44     private val instrumentation: Instrumentation,
45     private val outputDir: File = getDefaultFlickerOutputDir(),
46     private val wmHelper: WindowManagerStateHelper =
47         WindowManagerStateHelper(instrumentation, clearCacheAfterParsing = false),
48     private val setupCommands: MutableList<FlickerTestData.() -> Any> = mutableListOf(),
49     private val transitionCommands: MutableList<FlickerTestData.() -> Any> = mutableListOf(),
50     private val teardownCommands: MutableList<FlickerTestData.() -> Any> = mutableListOf(),
51     val device: UiDevice = UiDevice.getInstance(instrumentation),
52     private val traceMonitors: MutableList<ITransitionMonitor> =
<lambda>null53         mutableListOf<ITransitionMonitor>().also {
54             it.add(WindowManagerTraceMonitor())
55             it.add(LayersTraceMonitor())
56             it.add(WmTransitionTraceMonitor())
57             it.add(ShellTransitionTraceMonitor())
58             it.add(TransactionsTraceMonitor())
59             it.add(ScreenRecorder(instrumentation.targetContext))
60             it.add(EventLogMonitor())
61         }
62 ) {
63     private var usingExistingTraces = false
64 
65     /** Disable [WindowManagerTraceMonitor]. */
<lambda>null66     fun withoutWindowManagerTracing(): FlickerBuilder = apply { withWindowManagerTracing { null } }
67 
68     /**
69      * Configure a [WindowManagerTraceMonitor] to obtain [WindowManagerTrace]
70      *
71      * By default, the tracing is always active. To disable tracing return null
72      *
73      * If this tracing is disabled, the assertions for [WindowManagerTrace] and [WindowManagerState]
74      * will not be executed
75      */
withWindowManagerTracingnull76     fun withWindowManagerTracing(traceMonitor: () -> WindowManagerTraceMonitor?): FlickerBuilder =
77         apply {
78             traceMonitors.removeIf { it is WindowManagerTraceMonitor }
79             addMonitor(traceMonitor())
80         }
81 
82     /** Disable [LayersTraceMonitor]. */
<lambda>null83     fun withoutLayerTracing(): FlickerBuilder = apply { withLayerTracing { null } }
84 
85     /**
86      * Configure a [LayersTraceMonitor] to obtain [LayersTrace].
87      *
88      * By default the tracing is always active. To disable tracing return null
89      *
90      * If this tracing is disabled, the assertions for [LayersTrace] and [LayerTraceEntry] will not
91      * be executed
92      */
<lambda>null93     fun withLayerTracing(traceMonitor: () -> LayersTraceMonitor?): FlickerBuilder = apply {
94         traceMonitors.removeIf { it is LayersTraceMonitor }
95         addMonitor(traceMonitor())
96     }
97 
98     /** Disable [WmTransitionTraceMonitor]. */
<lambda>null99     fun withoutTransitionTracing(): FlickerBuilder = apply { withTransitionTracing { null } }
100 
101     /**
102      * Configure a [WmTransitionTraceMonitor] to obtain [TransitionsTrace].
103      *
104      * By default, shell transition tracing is disabled.
105      */
withTransitionTracingnull106     fun withTransitionTracing(traceMonitor: () -> WmTransitionTraceMonitor?): FlickerBuilder =
107         apply {
108             traceMonitors.removeIf { it is WmTransitionTraceMonitor }
109             addMonitor(traceMonitor())
110         }
111 
112     /** Disable [TransactionsTraceMonitor]. */
<lambda>null113     fun withoutTransactionsTracing(): FlickerBuilder = apply { withTransactionsTracing { null } }
114 
115     /**
116      * Configure a [TransactionsTraceMonitor] to obtain [TransactionsTrace].
117      *
118      * By default, shell transition tracing is disabled.
119      */
withTransactionsTracingnull120     fun withTransactionsTracing(traceMonitor: () -> TransactionsTraceMonitor?): FlickerBuilder =
121         apply {
122             traceMonitors.removeIf { it is TransactionsTraceMonitor }
123             addMonitor(traceMonitor())
124         }
125 
126     /**
127      * Configure a [ScreenRecorder].
128      *
129      * By default, the tracing is always active. To disable tracing return null
130      */
<lambda>null131     fun withScreenRecorder(screenRecorder: () -> ScreenRecorder?): FlickerBuilder = apply {
132         traceMonitors.removeIf { it is ScreenRecorder }
133         addMonitor(screenRecorder())
134     }
135 
<lambda>null136     fun withoutScreenRecorder(): FlickerBuilder = apply {
137         traceMonitors.removeIf { it is ScreenRecorder }
138     }
139 
140     /** Defines the setup commands executed before the [transitions] to test */
<lambda>null141     fun setup(commands: FlickerTestData.() -> Unit): FlickerBuilder = apply {
142         setupCommands.add(commands)
143     }
144 
145     /** Defines the teardown commands executed after the [transitions] to test */
<lambda>null146     fun teardown(commands: FlickerTestData.() -> Unit): FlickerBuilder = apply {
147         teardownCommands.add(commands)
148     }
149 
150     /** Defines the commands that trigger the behavior to test */
<lambda>null151     fun transitions(command: FlickerTestData.() -> Unit): FlickerBuilder = apply {
152         require(!usingExistingTraces) {
153             "Can't update transition after calling usingExistingTraces"
154         }
155         transitionCommands.add(command)
156     }
157 
158     data class TraceFiles(
159         val wmTrace: File,
160         val layersTrace: File,
161         val transactions: File,
162         val wmTransitions: File,
163         val shellTransitions: File,
164         val eventLog: File
165     )
166 
167     /** Use pre-executed results instead of running transitions to get the traces */
<lambda>null168     fun usingExistingTraces(_traceFiles: () -> TraceFiles): FlickerBuilder = apply {
169         val traceFiles = _traceFiles()
170         // Remove all trace monitor and use only monitor that read from existing trace file
171         this.traceMonitors.clear()
172         addMonitor(NoTraceMonitor { it.addTraceResult(TraceType.WM, traceFiles.wmTrace) })
173         addMonitor(NoTraceMonitor { it.addTraceResult(TraceType.SF, traceFiles.layersTrace) })
174         addMonitor(
175             NoTraceMonitor { it.addTraceResult(TraceType.TRANSACTION, traceFiles.transactions) }
176         )
177         addMonitor(
178             NoTraceMonitor { it.addTraceResult(TraceType.WM_TRANSITION, traceFiles.wmTransitions) }
179         )
180         addMonitor(
181             NoTraceMonitor {
182                 it.addTraceResult(TraceType.SHELL_TRANSITION, traceFiles.shellTransitions)
183             }
184         )
185         addMonitor(NoTraceMonitor { it.addTraceResult(TraceType.EVENT_LOG, traceFiles.eventLog) })
186 
187         // Remove all transitions execution
188         this.transitionCommands.clear()
189         this.usingExistingTraces = true
190     }
191 
192     /** Creates a new Flicker runner based on the current builder configuration */
buildnull193     fun build(): FlickerTestData {
194         return FlickerTestDataImpl(
195             instrumentation,
196             device,
197             outputDir,
198             traceMonitors,
199             setupCommands,
200             transitionCommands,
201             teardownCommands,
202             wmHelper
203         )
204     }
205 
206     /** Returns a copy of the current builder with the changes of [block] applied */
copynull207     fun copy(block: FlickerBuilder.() -> Unit) =
208         FlickerBuilder(
209                 instrumentation,
210                 outputDir.absoluteFile,
211                 wmHelper,
212                 setupCommands.toMutableList(),
213                 transitionCommands.toMutableList(),
214                 teardownCommands.toMutableList(),
215                 device,
216                 traceMonitors.toMutableList(),
217             )
218             .apply(block)
219 
220     private fun addMonitor(newMonitor: ITransitionMonitor?) {
221         require(!usingExistingTraces) { "Can't add monitors after calling usingExistingTraces" }
222 
223         if (newMonitor != null) {
224             traceMonitors.add(newMonitor)
225         }
226     }
227 }
228