1 /* 2 * Copyright (C) 2016 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.result; 17 18 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 19 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.LogAnnotation; 20 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.MetricAnnotation; 21 import com.android.tradefed.testtype.MetricTestCase.LogHolder; 22 import com.android.tradefed.util.StreamUtil; 23 24 import org.junit.AssumptionViolatedException; 25 import org.junit.runner.Description; 26 import org.junit.runner.notification.Failure; 27 import org.junit.runner.notification.RunListener; 28 import org.junit.runners.model.MultipleFailureException; 29 30 import java.lang.annotation.Annotation; 31 import java.util.ArrayList; 32 import java.util.HashMap; 33 import java.util.List; 34 35 /** 36 * Result forwarder from JUnit4 Runner. 37 */ 38 public class JUnit4ResultForwarder extends RunListener { 39 40 private ITestInvocationListener mListener; 41 private List<Throwable> mTestCaseFailures; 42 JUnit4ResultForwarder(ITestInvocationListener listener)43 public JUnit4ResultForwarder(ITestInvocationListener listener) { 44 mListener = listener; 45 mTestCaseFailures = new ArrayList<>(); 46 } 47 48 @Override testFailure(Failure failure)49 public void testFailure(Failure failure) throws Exception { 50 Description description = failure.getDescription(); 51 if (description.getMethodName() == null) { 52 // In case of exception in @BeforeClass, the method name will be null 53 mListener.testRunFailed(String.format("Failed with trace: %s", failure.getTrace())); 54 return; 55 } 56 mTestCaseFailures.add(failure.getException()); 57 } 58 59 @Override testAssumptionFailure(Failure failure)60 public void testAssumptionFailure(Failure failure) { 61 mTestCaseFailures.add(failure.getException()); 62 } 63 64 @Override testStarted(Description description)65 public void testStarted(Description description) { 66 mTestCaseFailures.clear(); 67 TestDescription testid = 68 new TestDescription( 69 description.getClassName(), 70 description.getMethodName(), 71 description.getAnnotations()); 72 mListener.testStarted(testid); 73 } 74 75 @Override testFinished(Description description)76 public void testFinished(Description description) { 77 TestDescription testid = 78 new TestDescription( 79 description.getClassName(), 80 description.getMethodName(), 81 description.getAnnotations()); 82 handleFailures(testid); 83 // Explore the Description to see if we find any Annotation metrics carrier 84 HashMap<String, Metric> metrics = new HashMap<>(); 85 for (Description child : description.getChildren()) { 86 for (Annotation a : child.getAnnotations()) { 87 if (a instanceof MetricAnnotation) { 88 metrics.putAll(((MetricAnnotation) a).mMetrics); 89 } 90 if (a instanceof LogAnnotation) { 91 // Log all the logs found. 92 for (LogHolder log : ((LogAnnotation) a).mLogs) { 93 mListener.testLog(log.mDataName, log.mDataType, log.mDataStream); 94 StreamUtil.cancel(log.mDataStream); 95 } 96 ((LogAnnotation) a).mLogs.clear(); 97 } 98 } 99 } 100 //description. 101 mListener.testEnded(testid, metrics); 102 } 103 104 @Override testIgnored(Description description)105 public void testIgnored(Description description) throws Exception { 106 TestDescription testid = 107 new TestDescription( 108 description.getClassName(), 109 description.getMethodName(), 110 description.getAnnotations()); 111 // We complete the event life cycle since JUnit4 fireIgnored is not within fireTestStarted 112 // and fireTestEnded. 113 mListener.testStarted(testid); 114 mListener.testIgnored(testid); 115 mListener.testEnded(testid, new HashMap<String, Metric>()); 116 } 117 118 /** 119 * Handle all the failure received from the JUnit4 tests, if a single 120 * AssumptionViolatedException is received then treat the test as assumption failure. Otherwise 121 * treat everything else as failure. 122 */ handleFailures(TestDescription testid)123 private void handleFailures(TestDescription testid) { 124 if (mTestCaseFailures.isEmpty()) { 125 return; 126 } 127 if (mTestCaseFailures.size() == 1) { 128 Throwable t = mTestCaseFailures.get(0); 129 if (t instanceof AssumptionViolatedException) { 130 mListener.testAssumptionFailure(testid, StreamUtil.getStackTrace(t)); 131 } else { 132 mListener.testFailed(testid, StreamUtil.getStackTrace(t)); 133 } 134 } else { 135 MultipleFailureException multiException = 136 new MultipleFailureException(mTestCaseFailures); 137 mListener.testFailed(testid, StreamUtil.getStackTrace(multiException)); 138 } 139 } 140 } 141