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.runner
18 
19 import android.app.Instrumentation
20 import android.tools.FLICKER_TAG
21 import android.tools.Scenario
22 import android.tools.flicker.junit.Utils
23 import android.tools.traces.io.ResultWriter
24 import android.tools.traces.monitors.ITransitionMonitor
25 import android.tools.traces.parsers.WindowManagerStateHelper
26 import android.tools.withTracing
27 import android.util.Log
28 import org.junit.rules.TestRule
29 import org.junit.runner.Description
30 import org.junit.runners.model.Statement
31 
32 /**
33  * Test rule to start and stop trace monitors and update [resultWriter]
34  *
35  * @param traceMonitors to collect device data
36  * @param scenario to run the transition
37  * @param wmHelper to stabilize the UI before/after transitions
38  * @param resultWriter to write
39  * @param instrumentation to interact with the device
40  */
41 class TraceMonitorRule(
42     private val traceMonitors: List<ITransitionMonitor>,
43     private val scenario: Scenario,
44     private val wmHelper: WindowManagerStateHelper,
45     private val resultWriter: ResultWriter,
46     private val instrumentation: Instrumentation
47 ) : TestRule {
applynull48     override fun apply(base: Statement?, description: Description?): Statement {
49         return object : Statement() {
50             override fun evaluate() {
51                 try {
52                     doStartMonitors(description)
53                 } catch (e: Throwable) {
54                     Log.e(
55                         FLICKER_TAG,
56                         "Failed to start trace monitors" +
57                             " - stopping all trace monitors to recover a clean state"
58                     )
59                     runCatching { doStopMonitors(description) }
60                     throw e
61                 }
62 
63                 try {
64                     base?.evaluate()
65                 } finally {
66                     doStopMonitors(description)
67                 }
68             }
69         }
70     }
71 
doStartMonitorsnull72     private fun doStartMonitors(description: Description?) {
73         withTracing("doStartMonitors") {
74             Utils.notifyRunnerProgress(scenario, "Starting traces for $description")
75             traceMonitors.forEach {
76                 try {
77                     it.start()
78                 } catch (e: Throwable) {
79                     Log.e(FLICKER_TAG, "Unable to start $it", e)
80                     throw e
81                 }
82             }
83         }
84     }
85 
doStopMonitorsnull86     private fun doStopMonitors(description: Description?) {
87         withTracing("doStopMonitors") {
88             Utils.notifyRunnerProgress(scenario, "Stopping traces for $description")
89             val errors =
90                 traceMonitors.map {
91                     runCatching {
92                         try {
93                             it.stop(resultWriter)
94                         } catch (e: Throwable) {
95                             Log.e(FLICKER_TAG, "Unable to stop $it", e)
96                             throw e
97                         }
98                     }
99                 }
100             errors.firstOrNull { it.isFailure }?.exceptionOrNull()?.let { throw it }
101         }
102     }
103 }
104