blob: 6af0bc16372e5cc1f9ce82d6de0831aaf7a0e026 [file] [log] [blame]
Brett Chabotb1052c22011-01-12 19:44:23 -08001/*
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 */
16package com.android.tradefed.invoker;
17
jdesprez5c272662017-11-28 02:42:27 -080018import com.android.tradefed.build.IBuildInfo;
jdesprezc9f81492017-05-30 15:59:05 -070019import com.android.tradefed.log.LogUtil.CLog;
Jed Estep86fc0472016-03-02 15:45:57 -080020import com.android.tradefed.result.ILogSaver;
jdesprez2ffb1bd2018-03-19 10:37:23 -070021import com.android.tradefed.result.ILogSaverListener;
Brett Chabotb1052c22011-01-12 19:44:23 -080022import com.android.tradefed.result.ITestInvocationListener;
jdesprez2ffb1bd2018-03-19 10:37:23 -070023import com.android.tradefed.result.InputStreamSource;
24import com.android.tradefed.result.LogDataType;
25import com.android.tradefed.result.LogFile;
Brett Chabotb1052c22011-01-12 19:44:23 -080026import com.android.tradefed.result.ResultForwarder;
jdesprezc9f81492017-05-30 15:59:05 -070027import com.android.tradefed.util.TimeUtil;
Brett Chabotb1052c22011-01-12 19:44:23 -080028
jdesprez5c272662017-11-28 02:42:27 -080029import java.util.ArrayList;
Brett Chabotb1052c22011-01-12 19:44:23 -080030import java.util.List;
jdesprez5c272662017-11-28 02:42:27 -080031import java.util.Map.Entry;
Brett Chabotb1052c22011-01-12 19:44:23 -080032
33/**
34 * A {@link ResultForwarder} that combines the results of a sharded test invocations. It only
35 * reports completion of the invocation to the listeners once all sharded invocations are complete.
jdesprezbf750e12017-04-03 12:18:47 -070036 *
37 * <p>This class is not thread safe. It is expected that clients will lock on this class when
38 * sending test results, to prevent invocation callbacks from being called out of order.
Brett Chabotb1052c22011-01-12 19:44:23 -080039 */
jdesprez2ffb1bd2018-03-19 10:37:23 -070040public class ShardMasterResultForwarder extends ResultForwarder implements ILogSaverListener {
Brett Chabotb1052c22011-01-12 19:44:23 -080041
jdesprezc9f81492017-05-30 15:59:05 -070042 private final int mInitCount;
Brett Chabotb1052c22011-01-12 19:44:23 -080043 private int mShardsRemaining;
jdesprez671d0d22018-01-29 16:04:15 -080044 private long mTotalElapsed = 0L;
Brett Chabotb1052c22011-01-12 19:44:23 -080045 private boolean mStartReported = false;
46
jdesprez671d0d22018-01-29 16:04:15 -080047 private long mFirstShardEndTime = 0L;
jdesprez57f2df42017-10-31 11:58:23 -070048 private IInvocationContext mOriginalContext;
jdesprez5c272662017-11-28 02:42:27 -080049 private List<IInvocationContext> mShardContextList;
jdesprez57f2df42017-10-31 11:58:23 -070050 private int shardIndex = 0;
jdesprezc9f81492017-05-30 15:59:05 -070051
Brett Chabotb1052c22011-01-12 19:44:23 -080052 /**
53 * Create a {@link ShardMasterResultForwarder}.
54 *
55 * @param listeners the list of {@link ITestInvocationListener} to forward results to when all
jdesprez2ffb1bd2018-03-19 10:37:23 -070056 * shards are completed
Brett Chabotb1052c22011-01-12 19:44:23 -080057 * @param expectedShards the number of shards
58 */
jdesprez2ffb1bd2018-03-19 10:37:23 -070059 public ShardMasterResultForwarder(List<ITestInvocationListener> listeners, int expectedShards) {
60 super(listeners);
Brett Chabotb1052c22011-01-12 19:44:23 -080061 mShardsRemaining = expectedShards;
jdesprezc9f81492017-05-30 15:59:05 -070062 mInitCount = expectedShards;
jdesprez5c272662017-11-28 02:42:27 -080063 mShardContextList = new ArrayList<>();
Brett Chabotb1052c22011-01-12 19:44:23 -080064 }
65
Julien Desprezd0c379a2016-11-04 11:00:54 +000066 /**
67 * {@inheritDoc}
Julien Desprezd0c379a2016-11-04 11:00:54 +000068 */
Julien Desprez53353e62016-08-12 15:24:33 +010069 @Override
70 public void invocationStarted(IInvocationContext context) {
71 if (!mStartReported) {
jdesprez57f2df42017-10-31 11:58:23 -070072 mOriginalContext = context;
Julien Desprez53353e62016-08-12 15:24:33 +010073 super.invocationStarted(context);
74 mStartReported = true;
jdesprez57f2df42017-10-31 11:58:23 -070075 } else {
76 // Track serials used in each shard.
77 mOriginalContext.addSerialsFromShard(shardIndex, context.getSerials());
jdesprez5c272662017-11-28 02:42:27 -080078 mShardContextList.add(context);
jdesprez57f2df42017-10-31 11:58:23 -070079 shardIndex++;
Julien Desprez53353e62016-08-12 15:24:33 +010080 }
81 }
82
Brett Chabotb1052c22011-01-12 19:44:23 -080083 /**
84 * {@inheritDoc}
85 */
86 @Override
87 public void invocationFailed(Throwable cause) {
88 // one of the shards failed. Fail the whole invocation
89 // TODO: does any extra logging need to be done ?
90 super.invocationFailed(cause);
91 }
92
Julien Desprezd0c379a2016-11-04 11:00:54 +000093 /**
94 * {@inheritDoc}
95 */
Brett Chabotb1052c22011-01-12 19:44:23 -080096 @Override
97 public void invocationEnded(long elapsedTime) {
98 mTotalElapsed += elapsedTime;
jdesprezc9f81492017-05-30 15:59:05 -070099 if (mInitCount == mShardsRemaining) {
100 mFirstShardEndTime = System.currentTimeMillis();
101 }
Brett Chabotb1052c22011-01-12 19:44:23 -0800102 mShardsRemaining--;
103 if (mShardsRemaining <= 0) {
jdesprezc9f81492017-05-30 15:59:05 -0700104 // TODO: consider logging all shard final times.
105 CLog.i(
106 "There was %s between the first and last shard ended.",
107 TimeUtil.formatElapsedTime(System.currentTimeMillis() - mFirstShardEndTime));
jdesprez5c272662017-11-28 02:42:27 -0800108 copyShardBuildInfoToMain(mOriginalContext, mShardContextList);
Brett Chabotb1052c22011-01-12 19:44:23 -0800109 super.invocationEnded(mTotalElapsed);
110 }
111 }
jdesprez5c272662017-11-28 02:42:27 -0800112
jdesprez2ffb1bd2018-03-19 10:37:23 -0700113 /** {@inheritDoc} */
114 @Override
115 public void testLogSaved(
116 String dataName, LogDataType dataType, InputStreamSource dataStream, LogFile logFile) {
117 for (ITestInvocationListener listener : getListeners()) {
118 try {
119 // Forward the testLogSaved event to ILogSaverListener
120 if (listener instanceof ILogSaverListener) {
121 ((ILogSaverListener) listener)
122 .testLogSaved(dataName, dataType, dataStream, logFile);
123 }
124 } catch (Exception e) {
125 CLog.e("Exception while invoking %s#testLogSaved", listener.getClass().getName());
126 CLog.e(e);
127 }
128 }
129 }
130
131 @Override
132 public void setLogSaver(ILogSaver logSaver) {
133 // Shard master does not need log saver.
134 }
135
jdesprez5c272662017-11-28 02:42:27 -0800136 /**
137 * Copy the build info from the shard builds to the main build in the original invocation
138 * context.
139 *
140 * @param main the original {@link IInvocationContext} from the main invocation.
141 * @param shardContexts the list of {@link IInvocationContext}s, one for each shard invocation.
142 */
143 private void copyShardBuildInfoToMain(
144 IInvocationContext main, List<IInvocationContext> shardContexts) {
145 for (IInvocationContext shard : shardContexts) {
146 for (String deviceName : shard.getDeviceConfigNames()) {
147 IBuildInfo shardBuild = shard.getBuildInfo(deviceName);
148 IBuildInfo mainBuild = main.getBuildInfo(deviceName);
149 if (mainBuild != null) {
150 for (Entry<String, String> entry : shardBuild.getBuildAttributes().entrySet()) {
151 mainBuild.addBuildAttribute(entry.getKey(), entry.getValue());
152 }
153 } else {
154 // Should not happen
155 CLog.e(
156 "Found a device '%s' in shard configuration but not in parent configuration.",
157 deviceName);
158 }
159 }
160 }
161 }
Brett Chabotb1052c22011-01-12 19:44:23 -0800162}