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