1 /*
2  * Copyright (C) 2011 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 com.android.tradefed.testtype;
17 
18 import com.android.tradefed.device.DeviceNotAvailableException;
19 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
20 import com.android.tradefed.result.JUnitToInvocationResultForwarder;
21 import com.android.tradefed.testtype.MetricTestCase.LogHolder;
22 import com.android.tradefed.util.StreamUtil;
23 
24 import junit.framework.AssertionFailedError;
25 import junit.framework.Protectable;
26 import junit.framework.Test;
27 import junit.framework.TestCase;
28 import junit.framework.TestListener;
29 import junit.framework.TestResult;
30 
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
34 
35 /**
36  * An specialization of {@link junit.framework.TestResult} that will abort when a
37  * {@link DeviceNotAvailableException} occurs
38  */
39 public class DeviceTestResult extends TestResult {
40 
41     @SuppressWarnings("serial")
42     public class RuntimeDeviceNotAvailableException extends RuntimeException {
43         private DeviceNotAvailableException mException;
44 
RuntimeDeviceNotAvailableException(DeviceNotAvailableException e)45         RuntimeDeviceNotAvailableException(DeviceNotAvailableException e) {
46             super(e.getMessage());
47             mException = e;
48         }
49 
getDeviceException()50         DeviceNotAvailableException getDeviceException() {
51             return mException;
52         }
53     }
54 
55     /**
56      * Runs a TestCase.
57      *
58      * @throws RuntimeDeviceNotAvailableException if a DeviceNotAvailableException occurs
59      */
60     @Override
runProtected(final Test test, Protectable p)61     public void runProtected(final Test test, Protectable p) {
62         // this is a copy of the superclass runProtected code, with the extra clause
63         // for DeviceNotAvailableException
64         try {
65             p.protect();
66         }
67         catch (AssertionFailedError e) {
68             addFailure(test, e);
69         }
70         catch (ThreadDeath e) { // don't catch ThreadDeath by accident
71             throw e;
72         }
73         catch (DeviceNotAvailableException e) {
74             addError(test, e);
75             throw new RuntimeDeviceNotAvailableException(e);
76         }
77         catch (Throwable e) {
78             addError(test, e);
79         }
80     }
81 
82     @Override
run(final TestCase test)83     protected void run(final TestCase test) {
84         // this is a copy of the superclass run code, with the extra finally clause
85         // to ensure endTest is called when RuntimeDeviceNotAvailableException occurs
86         startTest(test);
87         Protectable p = new Protectable() {
88             @Override
89             public void protect() throws Throwable {
90                 test.runBare();
91             }
92         };
93         try {
94             runProtected(test, p);
95         } finally {
96             endTest(test);
97         }
98     }
99 
100     /** {@inheritDoc} */
101     @Override
endTest(Test test)102     public void endTest(Test test) {
103         HashMap<String, Metric> metrics = new HashMap<>();
104         if (test instanceof MetricTestCase) {
105             MetricTestCase metricTest = (MetricTestCase) test;
106             metrics.putAll(metricTest.mMetrics);
107             // reset the metric for next test.
108             metricTest.mMetrics = new HashMap<String, Metric>();
109 
110             // testLog the log files
111             for (TestListener each : cloneListeners()) {
112                 for (LogHolder log : metricTest.mLogs) {
113                     if (each instanceof JUnitToInvocationResultForwarder) {
114                         ((JUnitToInvocationResultForwarder) each)
115                                 .testLog(log.mDataName, log.mDataType, log.mDataStream);
116                     }
117                     StreamUtil.cancel(log.mDataStream);
118                 }
119             }
120             metricTest.mLogs.clear();
121         }
122 
123         for (TestListener each : cloneListeners()) {
124             // when possible pass the metrics collected from the tests to our reporters.
125             if (!metrics.isEmpty() && each instanceof JUnitToInvocationResultForwarder) {
126                 ((JUnitToInvocationResultForwarder) each).endTest(test, metrics);
127             } else {
128                 each.endTest(test);
129             }
130         }
131     }
132 
133     /**
134      * Returns a copy of the listeners. Copied from {@link TestResult} to enable overriding {@link
135      * #endTest(Test)} in a similar way. This allows to override {@link #endTest(Test)} and report
136      * our metrics.
137      */
cloneListeners()138     private synchronized List<TestListener> cloneListeners() {
139         List<TestListener> result = new ArrayList<TestListener>();
140         result.addAll(fListeners);
141         return result;
142     }
143 }
144