1 /*
2  * Copyright (C) 2018 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 package android.platform.test.rule;
17 
18 import android.content.Context;
19 import android.os.Bundle;
20 import android.os.Trace;
21 import android.util.Log;
22 
23 import androidx.test.InstrumentationRegistry;
24 import androidx.test.uiautomator.UiDevice;
25 
26 import java.io.IOException;
27 import java.lang.Class;
28 
29 import org.junit.AssumptionViolatedException;
30 import org.junit.rules.TestRule;
31 import org.junit.runner.Description;
32 import org.junit.runners.model.Statement;
33 
34 /**
35  * Similar to {@link org.junit.rules.TestWatcher}, but does not perform operations quietly, i.e. by
36  * delaying failures and running the underlying base {@link Statement} under all circumstances. It
37  * also has additional common support for platform testing.
38  */
39 public class TestWatcher implements TestRule {
40     private static final String LOG_TAG = TestWatcher.class.getSimpleName();
41 
42     private UiDevice mDevice;
43 
44     private Class clz = this.getClass();
45 
apply(final Statement base, final Description description)46     public Statement apply(final Statement base, final Description description) {
47         return new Statement() {
48             @Override
49             public void evaluate() throws Throwable {
50                 try {
51                     Trace.beginSection(clz.getSimpleName() + ":starting");
52                     starting(description);
53                     Trace.endSection();
54                     base.evaluate();
55                     Trace.beginSection(clz.getSimpleName() + ":succeeded");
56                     succeeded(description);
57                     Trace.endSection();
58                 } catch (AssumptionViolatedException e) {
59                     Trace.beginSection(clz.getSimpleName() + ":skipped");
60                     skipped(e, description);
61                     Trace.endSection();
62                     throw e;
63                 } catch (Throwable e) {
64                     Trace.beginSection(clz.getSimpleName() + ":failed");
65                     failed(e, description);
66                     Trace.endSection();
67                     throw e;
68                 } finally {
69                     Trace.beginSection(clz.getSimpleName() + ":finished");
70                     finished(description);
71                     Trace.endSection();
72                 }
73             }
74         };
75     }
76 
77     /** Invoked when a test is about to start. */
78     protected void starting(Description description) {}
79 
80     /** Invoked when a test succeeds. */
81     protected void succeeded(Description description) {}
82 
83     /** Invoked when a test is skipped due to a failed assumption. */
84     protected void skipped(AssumptionViolatedException e, Description description) {}
85 
86     /** Invoked when a test fails. */
87     protected void failed(Throwable e, Description description) {}
88 
89     /** Invoked when a test method finishes (whether passing or failing). */
90     protected void finished(Description description) {}
91 
92     /**
93      * Returns the active {@link UiDevice} to interact with.
94      *
95      * <p>Override this for unit testing device calls.
96      */
97     protected UiDevice getUiDevice() {
98         if (mDevice == null) {
99             mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
100         }
101         return mDevice;
102     }
103 
104     /**
105      * Runs a shell command, {@code cmd}, and returns the output.
106      *
107      * <p>Override this for unit testing shell commands.
108      */
109     protected String executeShellCommand(String cmd) {
110         try {
111             Log.v(LOG_TAG, String.format("Executing command from %s: %s", this.getClass(), cmd));
112             return getUiDevice().executeShellCommand(cmd);
113         } catch (IOException e) {
114             throw new RuntimeException(e);
115         }
116     }
117 
118     /**
119      * Returns the {@link Bundle} containing registered arguments.
120      *
121      * <p>Override this for unit testing device calls.
122      */
123     protected Bundle getArguments() {
124         return InstrumentationRegistry.getArguments();
125     }
126 
127     /** Returns the {@link Context} for this application. */
128     protected Context getContext() {
129         return InstrumentationRegistry.getContext();
130     }
131 }
132