aboutsummaryrefslogtreecommitdiff
path: root/src/com/android
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2017-10-18 16:51:51 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2017-10-18 16:51:51 +0000
commit1b8312235f3b947d3f49ab35ec2e249b11c2673b (patch)
tree988e80c2146ebbaba9566333815755e9d3b5a057 /src/com/android
parent55396cb7426bf8a74dd41c0ebb1d63893221400e (diff)
parent4cbf9cb7fdd2af9333b8256b19d77296273c685e (diff)
downloadtradefederation-1b8312235f3b947d3f49ab35ec2e249b11c2673b.tar.gz
Snap for 4402310 from 4cbf9cb7fdd2af9333b8256b19d77296273c685e to oc-m2-release
Change-Id: I806922dc8762c1ea708988c5ff060b09794205f8
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/tradefed/config/Configuration.java18
-rw-r--r--src/com/android/tradefed/config/IConfiguration.java7
-rw-r--r--src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java155
-rw-r--r--src/com/android/tradefed/device/metric/DeviceMetricData.java46
-rw-r--r--src/com/android/tradefed/device/metric/IMetricCollector.java64
-rw-r--r--src/com/android/tradefed/device/metric/ScheduledDeviceMetricCollector.java106
-rw-r--r--src/com/android/tradefed/invoker/TestInvocation.java12
-rw-r--r--src/com/android/tradefed/testtype/StubTest.java3
8 files changed, 408 insertions, 3 deletions
diff --git a/src/com/android/tradefed/config/Configuration.java b/src/com/android/tradefed/config/Configuration.java
index 60aa5e790..9e6b05f47 100644
--- a/src/com/android/tradefed/config/Configuration.java
+++ b/src/com/android/tradefed/config/Configuration.java
@@ -24,6 +24,7 @@ import com.android.tradefed.config.OptionSetter.FieldDef;
import com.android.tradefed.device.IDeviceRecovery;
import com.android.tradefed.device.IDeviceSelection;
import com.android.tradefed.device.TestDeviceOptions;
+import com.android.tradefed.device.metric.IMetricCollector;
import com.android.tradefed.log.ILeveledLogOutput;
import com.android.tradefed.log.StdoutLogger;
import com.android.tradefed.profiler.ITestProfiler;
@@ -87,6 +88,7 @@ public class Configuration implements IConfiguration {
public static final String CONFIGURATION_DESCRIPTION_TYPE_NAME = "config_desc";
public static final String DEVICE_NAME = "device";
public static final String TEST_PROFILER_TYPE_NAME = "test_profiler";
+ public static final String DEVICE_METRICS_COLLECTOR_TYPE_NAME = "metrics_collector";
public static final String SANDBOX_TYPE_NAME = "sandbox";
private static Map<String, ObjTypeInfo> sObjTypeMap = null;
@@ -161,6 +163,9 @@ public class Configuration implements IConfiguration {
CONFIGURATION_DESCRIPTION_TYPE_NAME,
new ObjTypeInfo(ConfigurationDescriptor.class, false));
sObjTypeMap.put(TEST_PROFILER_TYPE_NAME, new ObjTypeInfo(ITestProfiler.class, false));
+ sObjTypeMap.put(
+ DEVICE_METRICS_COLLECTOR_TYPE_NAME,
+ new ObjTypeInfo(IMetricCollector.class, true));
}
return sObjTypeMap;
}
@@ -211,6 +216,7 @@ public class Configuration implements IConfiguration {
setSystemStatusCheckers(new ArrayList<ISystemStatusChecker>());
setConfigurationDescriptor(new ConfigurationDescriptor());
setProfiler(new StubTestProfiler());
+ setDeviceMetricCollectors(new ArrayList<>());
}
/**
@@ -349,6 +355,13 @@ public class Configuration implements IConfiguration {
RESULT_REPORTER_TYPE_NAME);
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public List<IMetricCollector> getMetricCollectors() {
+ return (List<IMetricCollector>)
+ getConfigurationObjectList(DEVICE_METRICS_COLLECTOR_TYPE_NAME);
+ }
+
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
@@ -642,6 +655,11 @@ public class Configuration implements IConfiguration {
setConfigurationObjectListNoThrow(RESULT_REPORTER_TYPE_NAME, listeners);
}
+ @Override
+ public void setDeviceMetricCollectors(List<IMetricCollector> collectors) {
+ setConfigurationObjectListNoThrow(DEVICE_METRICS_COLLECTOR_TYPE_NAME, collectors);
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/com/android/tradefed/config/IConfiguration.java b/src/com/android/tradefed/config/IConfiguration.java
index 88e2b43c5..4270b4abc 100644
--- a/src/com/android/tradefed/config/IConfiguration.java
+++ b/src/com/android/tradefed/config/IConfiguration.java
@@ -22,6 +22,7 @@ import com.android.tradefed.config.ConfigurationDef.OptionDef;
import com.android.tradefed.device.IDeviceRecovery;
import com.android.tradefed.device.IDeviceSelection;
import com.android.tradefed.device.TestDeviceOptions;
+import com.android.tradefed.device.metric.IMetricCollector;
import com.android.tradefed.log.ILeveledLogOutput;
import com.android.tradefed.profiler.ITestProfiler;
import com.android.tradefed.result.ILogSaver;
@@ -129,6 +130,9 @@ public interface IConfiguration {
*/
public ITestProfiler getProfiler();
+ /** Gets the {@link IMetricCollector}s from the configuration. */
+ public List<IMetricCollector> getMetricCollectors();
+
/**
* Gets the {@link ICommandOptions} to use from the configuration.
*
@@ -346,6 +350,9 @@ public interface IConfiguration {
*/
public void setTestInvocationListener(ITestInvocationListener listener);
+ /** Set the list of {@link IMetricCollector}s, replacing any existing values. */
+ public void setDeviceMetricCollectors(List<IMetricCollector> collectors);
+
/**
* Set the {@link ITestProfiler}, replacing any existing values
*
diff --git a/src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java b/src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java
new file mode 100644
index 000000000..9f6fbc097
--- /dev/null
+++ b/src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tradefed.device.metric;
+
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.InputStreamSource;
+import com.android.tradefed.result.LogDataType;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base implementation of {@link IMetricCollector} that allows to start and stop collection on
+ * {@link #onTestRunStart(DeviceMetricData)} and {@link #onTestRunEnd(DeviceMetricData)}.
+ */
+public class BaseDeviceMetricCollector implements IMetricCollector {
+
+ private IInvocationContext mContext;
+ private ITestInvocationListener mForwarder;
+ private DeviceMetricData mRunData;
+
+ @Override
+ public ITestInvocationListener init(
+ IInvocationContext context, ITestInvocationListener listener) {
+ mContext = context;
+ mForwarder = listener;
+ return this;
+ }
+
+ @Override
+ public List<ITestDevice> getDevices() {
+ return mContext.getDevices();
+ }
+
+ @Override
+ public List<IBuildInfo> getBuildInfos() {
+ return mContext.getBuildInfos();
+ }
+
+ @Override
+ public ITestInvocationListener getInvocationListener() {
+ return mForwarder;
+ }
+
+ @Override
+ public void onTestRunStart(DeviceMetricData runData) {
+ // Does nothing
+ }
+
+ @Override
+ public void onTestRunEnd(DeviceMetricData runData) {
+ // Does nothing
+ }
+
+ /** =================================== */
+ /** Invocation Listeners for forwarding */
+ @Override
+ public final void invocationStarted(IInvocationContext context) {
+ mForwarder.invocationStarted(context);
+ }
+
+ @Override
+ public final void invocationFailed(Throwable cause) {
+ mForwarder.invocationFailed(cause);
+ }
+
+ @Override
+ public final void invocationEnded(long elapsedTime) {
+ mForwarder.invocationEnded(elapsedTime);
+ }
+
+ @Override
+ public final void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) {
+ mForwarder.testLog(dataName, dataType, dataStream);
+ }
+
+ /** Test run callbacks */
+ @Override
+ public final void testRunStarted(String runName, int testCount) {
+ mRunData = new DeviceMetricData();
+ onTestRunStart(mRunData);
+ mForwarder.testRunStarted(runName, testCount);
+ }
+
+ @Override
+ public final void testRunFailed(String errorMessage) {
+ mForwarder.testRunFailed(errorMessage);
+ }
+
+ @Override
+ public final void testRunStopped(long elapsedTime) {
+ mForwarder.testRunStopped(elapsedTime);
+ }
+
+ @Override
+ public final void testRunEnded(long elapsedTime, Map<String, String> runMetrics) {
+ onTestRunEnd(mRunData);
+ mRunData.addToMetrics(runMetrics);
+ mForwarder.testRunEnded(elapsedTime, runMetrics);
+ }
+
+ /** Test cases callbacks */
+ @Override
+ public final void testStarted(TestIdentifier test) {
+ testStarted(test, System.currentTimeMillis());
+ }
+
+ @Override
+ public final void testStarted(TestIdentifier test, long startTime) {
+ mForwarder.testStarted(test, startTime);
+ }
+
+ @Override
+ public final void testFailed(TestIdentifier test, String trace) {
+ mForwarder.testFailed(test, trace);
+ }
+
+ @Override
+ public final void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
+ testEnded(test, System.currentTimeMillis(), testMetrics);
+ }
+
+ @Override
+ public final void testEnded(
+ TestIdentifier test, long endTime, Map<String, String> testMetrics) {
+ mForwarder.testEnded(test, endTime, testMetrics);
+ }
+
+ @Override
+ public final void testAssumptionFailure(TestIdentifier test, String trace) {
+ mForwarder.testAssumptionFailure(test, trace);
+ }
+
+ @Override
+ public final void testIgnored(TestIdentifier test) {
+ mForwarder.testIgnored(test);
+ }
+}
diff --git a/src/com/android/tradefed/device/metric/DeviceMetricData.java b/src/com/android/tradefed/device/metric/DeviceMetricData.java
new file mode 100644
index 000000000..d31324d43
--- /dev/null
+++ b/src/com/android/tradefed/device/metric/DeviceMetricData.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tradefed.device.metric;
+
+import java.io.Serializable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Object to hold all the data collected by metric collectors. TODO: Add the data holding and
+ * receiving of data methods.
+ */
+public class DeviceMetricData implements Serializable {
+ private static final long serialVersionUID = 1;
+
+ // TODO: expend type supports to more complex type: Object, File, etc.
+ private LinkedHashMap<String, String> mCurrentStringMetrics = new LinkedHashMap<>();
+
+ public void addStringMetric(String key, String value) {
+ mCurrentStringMetrics.put(key, value);
+ }
+
+ /**
+ * Push all the data received so far to the map of metrics that will be reported. This should
+ * also clean up the resources after pushing them.
+ *
+ * @param metrics The metrics currently available.
+ */
+ public void addToMetrics(Map<String, String> metrics) {
+ // TODO: dump all the metrics collected to the map of metrics to be reported.
+ metrics.putAll(mCurrentStringMetrics);
+ }
+}
diff --git a/src/com/android/tradefed/device/metric/IMetricCollector.java b/src/com/android/tradefed/device/metric/IMetricCollector.java
new file mode 100644
index 000000000..b6d0ef77b
--- /dev/null
+++ b/src/com/android/tradefed/device/metric/IMetricCollector.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tradefed.device.metric;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.result.ITestInvocationListener;
+
+import java.util.List;
+
+/**
+ * This interface will be added as a decorator when reporting tests results in order to collect
+ * matching metrics.
+ */
+public interface IMetricCollector extends ITestInvocationListener {
+
+ /**
+ * Initialization of the collector with the current context and where to forward results.
+ *
+ * @param context the {@link IInvocationContext} for the invocation in progress.
+ * @param listener the {@link ITestInvocationListener} where to put results.
+ * @return the new listener wrapping the original one.
+ */
+ public ITestInvocationListener init(
+ IInvocationContext context, ITestInvocationListener listener);
+
+ /** Returns the list of devices available in the invocation. */
+ public List<ITestDevice> getDevices();
+
+ /** Returns the list of build information available in the invocation. */
+ public List<IBuildInfo> getBuildInfos();
+
+ /** Returns the original {@link ITestInvocationListener} where we are forwarding the results. */
+ public ITestInvocationListener getInvocationListener();
+
+ /**
+ * Callback when a test run is started.
+ *
+ * @param runData the {@link DeviceMetricData} holding the data for the run.
+ */
+ public void onTestRunStart(DeviceMetricData runData);
+
+ /**
+ * Callback when a test run is ended. This should be the time for clean up.
+ *
+ * @param runData the {@link DeviceMetricData} holding the data for the run. Will be the same
+ * object as during {@link #onTestRunStart(DeviceMetricData)}.
+ */
+ public void onTestRunEnd(DeviceMetricData runData);
+}
diff --git a/src/com/android/tradefed/device/metric/ScheduledDeviceMetricCollector.java b/src/com/android/tradefed/device/metric/ScheduledDeviceMetricCollector.java
new file mode 100644
index 000000000..7c1f9a71f
--- /dev/null
+++ b/src/com/android/tradefed/device/metric/ScheduledDeviceMetricCollector.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tradefed.device.metric;
+
+import com.android.tradefed.config.Option;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * A {@link IMetricCollector} that allows to run a collection task periodically at a set interval.
+ */
+public abstract class ScheduledDeviceMetricCollector extends BaseDeviceMetricCollector {
+
+ @Option(
+ name = "fixed-schedule-rate",
+ description = "Schedule the timetask as a fixed schedule rate"
+ )
+ private boolean mFixedScheduleRate = false;
+
+ @Option(
+ name = "interval",
+ description = "the interval between two tasks being scheduled",
+ isTimeVal = true
+ )
+ private long mIntervalMs = 60 * 1000l;
+
+ private Timer timer;
+
+ @Override
+ public final void onTestRunStart(DeviceMetricData runData) {
+ CLog.d("starting");
+ onStart(runData);
+ timer = new Timer();
+ TimerTask timerTask =
+ new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ collect(runData);
+ } catch (InterruptedException e) {
+ timer.cancel();
+ Thread.currentThread().interrupt();
+ CLog.e("Interrupted exception thrown from task:");
+ CLog.e(e);
+ }
+ }
+ };
+
+ if (mFixedScheduleRate) {
+ timer.scheduleAtFixedRate(timerTask, 0, mIntervalMs);
+ } else {
+ timer.schedule(timerTask, 0, mIntervalMs);
+ }
+ }
+
+ @Override
+ public final void onTestRunEnd(DeviceMetricData runData) {
+ if (timer != null) {
+ timer.cancel();
+ timer.purge();
+ }
+ onEnd(runData);
+ CLog.d("finished");
+ }
+
+ /**
+ * Task periodically & asynchronously run during the test running.
+ *
+ * @param runData the {@link DeviceMetricData} where to put metrics.
+ * @throws InterruptedException
+ */
+ abstract void collect(DeviceMetricData runData) throws InterruptedException;
+
+ /**
+ * Executed when entering this collector.
+ *
+ * @param runData the {@link DeviceMetricData} where to put metrics.
+ */
+ void onStart(DeviceMetricData runData) {
+ // Does nothing.
+ }
+
+ /**
+ * Executed when finishing this collector.
+ *
+ * @param runData the {@link DeviceMetricData} where to put metrics.
+ */
+ void onEnd(DeviceMetricData runData) {
+ // Does nothing.
+ }
+}
diff --git a/src/com/android/tradefed/invoker/TestInvocation.java b/src/com/android/tradefed/invoker/TestInvocation.java
index dd9a4fb3c..13cdae075 100644
--- a/src/com/android/tradefed/invoker/TestInvocation.java
+++ b/src/com/android/tradefed/invoker/TestInvocation.java
@@ -32,6 +32,7 @@ import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.ITestDevice.RecoveryMode;
import com.android.tradefed.device.StubDevice;
import com.android.tradefed.device.TestDeviceState;
+import com.android.tradefed.device.metric.IMetricCollector;
import com.android.tradefed.invoker.shard.IShardHelper;
import com.android.tradefed.invoker.shard.ShardBuildCloner;
import com.android.tradefed.log.ILeveledLogOutput;
@@ -762,8 +763,15 @@ public class TestInvocation implements ITestInvocation {
* @param listener the {@link ITestInvocationListener} of test results
* @throws DeviceNotAvailableException
*/
- private void runTests(IInvocationContext context, IConfiguration config,
- ITestInvocationListener listener) throws DeviceNotAvailableException {
+ @VisibleForTesting
+ void runTests(
+ IInvocationContext context, IConfiguration config, ITestInvocationListener listener)
+ throws DeviceNotAvailableException {
+ // Wrap collectors in each other and collection will be sequential
+ for (IMetricCollector collector : config.getMetricCollectors()) {
+ listener = collector.init(context, listener);
+ }
+
for (IRemoteTest test : config.getTests()) {
// For compatibility of those receivers, they are assumed to be single device alloc.
if (test instanceof IDeviceTest) {
diff --git a/src/com/android/tradefed/testtype/StubTest.java b/src/com/android/tradefed/testtype/StubTest.java
index 0809e4145..d0d7ff8d7 100644
--- a/src/com/android/tradefed/testtype/StubTest.java
+++ b/src/com/android/tradefed/testtype/StubTest.java
@@ -27,6 +27,7 @@ import com.android.tradefed.result.ITestInvocationListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
/**
@@ -91,7 +92,7 @@ public class StubTest implements IShardableTest {
TestIdentifier testId = new TestIdentifier("StubTest", "StubMethod");
listener.testStarted(testId);
listener.testEnded(testId, Collections.emptyMap());
- listener.testRunEnded(500, Collections.emptyMap());
+ listener.testRunEnded(500, new LinkedHashMap<>());
}
}