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.invoker; 17 18 import com.android.ddmlib.Log.LogLevel; 19 import com.android.ddmlib.testrunner.TestIdentifier; 20 import com.android.ddmlib.testrunner.TestResult; 21 import com.android.ddmlib.testrunner.TestResult.TestStatus; 22 import com.android.ddmlib.testrunner.TestRunResult; 23 import com.android.tradefed.log.LogUtil.CLog; 24 import com.android.tradefed.result.CollectingTestListener; 25 import com.android.tradefed.result.ITestInvocationListener; 26 import com.android.tradefed.result.InputStreamSource; 27 import com.android.tradefed.result.LogDataType; 28 29 import java.util.Map; 30 31 /** 32 * A {@link ITestInvocationListener} that collects results from a invocation shard (aka an 33 * invocation split to run on multiple resources in parallel), and forwards them to another 34 * listener. 35 */ 36 public class ShardListener extends CollectingTestListener { 37 38 private ITestInvocationListener mMasterListener; 39 40 /** 41 * Create a {@link ShardListener}. 42 * 43 * @param master the {@link ITestInvocationListener} the results should be forwarded. To prevent 44 * collisions with other {@link ShardListener}s, this object will synchronize on 45 * <var>master</var> when forwarding results. And results will only be sent once the 46 * invocation shard completes. 47 */ 48 public ShardListener(ITestInvocationListener master) { 49 mMasterListener = master; 50 } 51 52 /** 53 * {@inheritDoc} 54 * @deprecated use {@link #invocationStarted(IInvocationContext)} instead. 55 */ 56 @Override 57 @Deprecated 58 public void invocationStarted(IInvocationContext context) { 59 super.invocationStarted(context); 60 synchronized (mMasterListener) { 61 mMasterListener.invocationStarted(context); 62 } 63 } 64 65 /** 66 * {@inheritDoc} 67 */ 68 @Override 69 public void invocationFailed(Throwable cause) { 70 super.invocationFailed(cause); 71 synchronized (mMasterListener) { 72 mMasterListener.invocationFailed(cause); 73 } 74 } 75 76 /** 77 * {@inheritDoc} 78 */ 79 @Override 80 public void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) { 81 // forward testLog results immediately, since they are not order dependent and there are 82 // not stored by CollectingTestListener 83 synchronized (mMasterListener) { 84 mMasterListener.testLog(dataName, dataType, dataStream); 85 } 86 } 87 88 /** 89 * {@inheritDoc} 90 */ 91 @Override 92 public void testRunEnded(long elapsedTime, Map<String, String> runMetrics) { 93 super.testRunEnded(elapsedTime, runMetrics); 94 CLog.logAndDisplay(LogLevel.INFO, "Sharded test completed: %s", 95 getCurrentRunResults().getName()); 96 } 97 98 /** 99 * {@inheritDoc} 100 */ 101 @Override 102 public void testRunFailed(String failureMessage) { 103 super.testRunFailed(failureMessage); 104 CLog.logAndDisplay(LogLevel.ERROR, "FAILED: %s failed with message: %s", 105 getCurrentRunResults().getName(), failureMessage); 106 } 107 108 /** 109 * {@inheritDoc} 110 */ 111 @Override 112 public void invocationEnded(long elapsedTime) { 113 super.invocationEnded(elapsedTime); 114 synchronized (mMasterListener) { 115 for (TestRunResult runResult : getRunResults()) { 116 mMasterListener.testRunStarted(runResult.getName(), runResult.getNumTests()); 117 forwardTestResults(runResult.getTestResults()); 118 if (runResult.isRunFailure()) { 119 mMasterListener.testRunFailed(runResult.getRunFailureMessage()); 120 } 121 mMasterListener.testRunEnded(runResult.getElapsedTime(), runResult.getRunMetrics()); 122 } 123 mMasterListener.invocationEnded(elapsedTime); 124 } 125 } 126 127 private void forwardTestResults(Map<TestIdentifier, TestResult> testResults) { 128 for (Map.Entry<TestIdentifier, TestResult> testEntry : testResults.entrySet()) { 129 mMasterListener.testStarted(testEntry.getKey(), testEntry.getValue().getStartTime()); 130 switch (testEntry.getValue().getStatus()) { 131 case FAILURE: 132 mMasterListener.testFailed(testEntry.getKey(), 133 testEntry.getValue().getStackTrace()); 134 break; 135 case ASSUMPTION_FAILURE: 136 mMasterListener.testAssumptionFailure(testEntry.getKey(), 137 testEntry.getValue().getStackTrace()); 138 break; 139 case IGNORED: 140 mMasterListener.testIgnored(testEntry.getKey()); 141 break; 142 default: 143 break; 144 } 145 if (!testEntry.getValue().getStatus().equals(TestStatus.INCOMPLETE)) { 146 mMasterListener.testEnded( 147 testEntry.getKey(), 148 testEntry.getValue().getEndTime(), 149 testEntry.getValue().getMetrics()); 150 } 151 } 152 } 153 } 154