blob: e987db36dac3a6c189adde11186175a5e261fb4f [file] [log] [blame]
/*
* Copyright (C) 2011 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.framework.tests;
import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.loganalysis.item.BugreportItem;
import com.android.loganalysis.item.LogcatItem;
import com.android.loganalysis.parser.BugreportParser;
import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.CollectingTestListener;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.InputStreamSource;
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.result.TestDescription;
import com.android.tradefed.result.TestResult;
import com.android.tradefed.testtype.IDeviceTest;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.util.proto.TfMetricProtoUtil;
import org.junit.Assert;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Map.Entry;
/**
* Test that instruments a stress test package, gathers iterations metrics, and posts the results.
*/
public class FrameworkStressTest implements IDeviceTest, IRemoteTest {
public static final String BUGREPORT_LOG_NAME = "bugreport_stress.txt";
ITestDevice mTestDevice = null;
@Option(name = "test-package-name", description = "Android test package name.")
private String mTestPackageName;
@Option(name = "test-class-name", description = "Test class name.")
private String mTestClassName;
@Option(name = "dashboard-test-label",
description = "Test label to use when posting to dashboard.")
private String mDashboardTestLabel;
@Option(name = "setup-shell-command",
description = "Setup shell command to run before the test, if any.")
private String mSetupShellCommand;
private static final String CURRENT_ITERATION_LABEL= "currentiterations";
private static final String ANR_COUNT_LABEL = "anrs";
private static final String JAVA_CRASH_COUNT_LABEL = "java_crashes";
private static final String NATIVE_CRASH_COUNT_LABEL = "native_crashes";
private static final String ITERATION_COUNT_LABEL = "iterations";
private int mNumAnrsTotal = 0;
private int mNumJavaCrashesTotal = 0;
private int mNumNativeCrashesTotal = 0;
@Override
public void run(final ITestInvocationListener listener) throws DeviceNotAvailableException {
Assert.assertNotNull(mTestDevice);
if (mSetupShellCommand != null) {
mTestDevice.executeShellCommand(mSetupShellCommand);
}
IRemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mTestPackageName,
mTestDevice.getIDevice());
runner.setClassName(mTestClassName);
CollectingTestListener collectingListener = new CollectingMetricsTestListener(listener);
mTestDevice.runInstrumentationTests(runner, collectingListener, listener);
Map<TestDescription, TestResult> testResults =
collectingListener.getCurrentRunResults().getTestResults();
if (testResults != null) {
for (Entry<TestDescription, TestResult> e : testResults.entrySet()) {
TestResult res = e.getValue();
Map<String, String> testMetrics = res.getMetrics();
if (testMetrics != null) {
CLog.d(testMetrics.toString());
// Post everything to the dashboard.
String label = String.format("%s#%s", mDashboardTestLabel,
e.getKey().getTestName());
reportMetrics(listener, label, testMetrics);
}
}
}
}
/**
* Report run metrics by creating an empty test run to stick them in.
*
* @param listener the {@link ITestInvocationListener} of test results
* @param runName the test name
* @param metrics the {@link Map} that contains metrics for the given test
*/
void reportMetrics(ITestInvocationListener listener, String runName,
Map<String, String> metrics) {
// Create an empty testRun to report the parsed runMetrics
CLog.d("About to report metrics: %s with label: %s", metrics, runName);
listener.testRunStarted(runName, 0);
listener.testRunEnded(0, TfMetricProtoUtil.upgradeConvert(metrics));
}
@Override
public void setDevice(ITestDevice device) {
mTestDevice = device;
}
@Override
public ITestDevice getDevice() {
return mTestDevice;
}
/**
* Helper class to collect the Framework metrics at the end of each test.
*/
private class CollectingMetricsTestListener extends CollectingTestListener {
private ITestInvocationListener mListener;
public CollectingMetricsTestListener(ITestInvocationListener listener) {
mListener = listener;
}
@Override
public void testEnded(TestDescription test, Map<String, String> testMetrics) {
// Retrieve bugreport
BugreportParser parser = new BugreportParser();
BugreportItem bugreport = null;
try (InputStreamSource bugSource = mTestDevice.getBugreport()) {
mListener.testLog(BUGREPORT_LOG_NAME, LogDataType.BUGREPORT, bugSource);
bugreport = parser.parse(new BufferedReader(new InputStreamReader(
bugSource.createInputStream())));
Assert.assertNotNull(bugreport);
Assert.assertNotNull(bugreport.getSystemLog());
} catch (IOException e) {
Assert.fail(String.format("Failed to fetch and parse bugreport for device %s: "
+ "%s", mTestDevice.getSerialNumber(), e));
}
LogcatItem systemLog = bugreport.getSystemLog();
// We only add errors found since last test run.
Integer numArns = systemLog.getAnrs().size() - mNumAnrsTotal;
mNumAnrsTotal = systemLog.getAnrs().size();
testMetrics.put(ANR_COUNT_LABEL, numArns.toString());
Integer numJavaCrashes = systemLog.getJavaCrashes().size() - mNumJavaCrashesTotal;
mNumJavaCrashesTotal = systemLog.getJavaCrashes().size();
testMetrics.put(JAVA_CRASH_COUNT_LABEL, numJavaCrashes.toString());
Integer numNativeCrashes = systemLog.getNativeCrashes().size() - mNumNativeCrashesTotal;
mNumNativeCrashesTotal = systemLog.getNativeCrashes().size();
testMetrics.put(NATIVE_CRASH_COUNT_LABEL, numNativeCrashes.toString());
Integer numSuccessfulIterations =
Integer.parseInt(testMetrics.get(CURRENT_ITERATION_LABEL))
- numArns - numJavaCrashes - numNativeCrashes;
testMetrics.put(ITERATION_COUNT_LABEL, numSuccessfulIterations.toString());
super.testEnded(test, testMetrics);
}
}
}