xref: /aosp_15_r20/platform_testing/libraries/flicker/src/android/tools/flicker/legacy/FlickerBuilder.kt (revision dd0948b35e70be4c0246aabd6c72554a5eb8b22a)
1 /*
2  * Copyright (C) 2024 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.flicker.legacy
18 
19 import android.app.Instrumentation
20 import android.tools.flicker.Utils.ALL_MONITORS
21 import android.tools.io.TraceType
22 import android.tools.traces.getDefaultFlickerOutputDir
23 import android.tools.traces.monitors.ITransitionMonitor
24 import android.tools.traces.monitors.NoTraceMonitor
25 import android.tools.traces.monitors.ScreenRecorder
26 import android.tools.traces.parsers.WindowManagerStateHelper
27 import androidx.test.uiautomator.UiDevice
28 import java.io.File
29 import org.junit.rules.TestRule
30 
31 /** Build Flicker tests using Flicker DSL */
32 @FlickerDslMarker
33 class FlickerBuilder(
34     private val instrumentation: Instrumentation,
35     private val outputDir: File = getDefaultFlickerOutputDir(),
36     private val wmHelper: WindowManagerStateHelper =
37         WindowManagerStateHelper(instrumentation, clearCacheAfterParsing = false),
38     private val setupCommands: MutableList<FlickerTestData.() -> Any> = mutableListOf(),
39     private val transitionCommands: MutableList<FlickerTestData.() -> Any> = mutableListOf(),
40     private val teardownCommands: MutableList<FlickerTestData.() -> Any> = mutableListOf(),
41     val device: UiDevice = UiDevice.getInstance(instrumentation),
42     private val rules: MutableList<TestRule> = mutableListOf(),
43     private val traceMonitors: MutableList<ITransitionMonitor> = ALL_MONITORS.toMutableList(),
44 ) {
45     private var usingExistingTraces = false
46 
47     /**
48      * Configure a [ScreenRecorder].
49      *
50      * By default, the tracing is always active. To disable tracing return null
51      */
<lambda>null52     fun withScreenRecorder(screenRecorder: () -> ScreenRecorder?): FlickerBuilder = apply {
53         traceMonitors.removeIf { it is ScreenRecorder }
54         addMonitor(screenRecorder())
55     }
56 
<lambda>null57     fun withoutScreenRecorder(): FlickerBuilder = apply {
58         traceMonitors.removeIf { it is ScreenRecorder }
59     }
60 
61     /** Defines the setup commands executed before the [transitions] to test */
<lambda>null62     fun setup(commands: FlickerTestData.() -> Unit): FlickerBuilder = apply {
63         setupCommands.add(commands)
64     }
65 
66     /** Defines the teardown commands executed after the [transitions] to test */
<lambda>null67     fun teardown(commands: FlickerTestData.() -> Unit): FlickerBuilder = apply {
68         teardownCommands.add(commands)
69     }
70 
71     /** Defines the commands that trigger the behavior to test */
<lambda>null72     fun transitions(command: FlickerTestData.() -> Unit): FlickerBuilder = apply {
73         require(!usingExistingTraces) {
74             "Can't update transition after calling usingExistingTraces"
75         }
76         transitionCommands.add(command)
77     }
78 
79     /** Adds JUnit rules to be executed with the provided transitions. */
withRulesnull80     fun withRules(vararg rules: TestRule) {
81         this.rules.addAll(rules)
82     }
83 
84     data class TraceFiles(
85         val wmTrace: File,
86         val perfetto: File,
87         val wmTransitions: File,
88         val shellTransitions: File,
89         val eventLog: File,
90     )
91 
92     /** Use pre-executed results instead of running transitions to get the traces */
<lambda>null93     fun usingExistingTraces(_traceFiles: () -> TraceFiles): FlickerBuilder = apply {
94         val traceFiles = _traceFiles()
95         // Remove all trace monitor and use only monitor that read from existing trace file
96         this.traceMonitors.clear()
97         addMonitor(NoTraceMonitor { it.addTraceResult(TraceType.WM, traceFiles.wmTrace) })
98         addMonitor(NoTraceMonitor { it.addTraceResult(TraceType.SF, traceFiles.perfetto) })
99         addMonitor(NoTraceMonitor { it.addTraceResult(TraceType.TRANSACTION, traceFiles.perfetto) })
100         addMonitor(
101             NoTraceMonitor {
102                 it.addTraceResult(TraceType.LEGACY_WM_TRANSITION, traceFiles.wmTransitions)
103             }
104         )
105         addMonitor(
106             NoTraceMonitor {
107                 it.addTraceResult(TraceType.LEGACY_SHELL_TRANSITION, traceFiles.shellTransitions)
108             }
109         )
110         addMonitor(NoTraceMonitor { it.addTraceResult(TraceType.EVENT_LOG, traceFiles.eventLog) })
111 
112         // Remove all transitions execution
113         this.transitionCommands.clear()
114         this.usingExistingTraces = true
115     }
116 
117     /** Creates a new Flicker runner based on the current builder configuration */
buildnull118     fun build(): FlickerTestData {
119         return FlickerTestDataImpl(
120             instrumentation,
121             device,
122             outputDir,
123             traceMonitors,
124             setupCommands,
125             transitionCommands,
126             teardownCommands,
127             rules,
128             wmHelper,
129         )
130     }
131 
132     /** Returns a copy of the current builder with the changes of [block] applied */
copynull133     fun copy(block: FlickerBuilder.() -> Unit) =
134         FlickerBuilder(
135                 instrumentation,
136                 outputDir.absoluteFile,
137                 wmHelper,
138                 setupCommands.toMutableList(),
139                 transitionCommands.toMutableList(),
140                 teardownCommands.toMutableList(),
141                 device,
142                 rules.toMutableList(),
143                 traceMonitors.toMutableList(),
144             )
145             .apply(block)
146 
147     private fun addMonitor(newMonitor: ITransitionMonitor?) {
148         require(!usingExistingTraces) { "Can't add monitors after calling usingExistingTraces" }
149 
150         if (newMonitor != null) {
151             traceMonitors.add(newMonitor)
152         }
153     }
154 }
155