/* * 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.TestResult; import com.android.tradefed.testtype.IDeviceTest; import com.android.tradefed.testtype.IRemoteTest; import junit.framework.Assert; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * 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"; @Override public void run(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 CollectingTestListener(); mTestDevice.runInstrumentationTests(runner, collectingListener, listener); // Retrieve bugreport BugreportParser parser = new BugreportParser(); BugreportItem bugreport = null; InputStreamSource bugSource = mTestDevice.getBugreport(); try { listener.testLog(BUGREPORT_LOG_NAME, LogDataType.TEXT, bugSource); bugreport = parser.parse(new BufferedReader(new InputStreamReader( bugSource.createInputStream()))); } catch (IOException e) { Assert.fail(String.format("Failed to fetch and parse bugreport for device %s: %s", mTestDevice.getSerialNumber(), e)); } finally { bugSource.cancel(); } Map<String, String> stressTestMetrics = new HashMap<String, String>(); Integer numIterations = 0; Integer numSuccessfulIterations = 0; LogcatItem systemLog = bugreport.getSystemLog(); Integer numAnrs = systemLog.getAnrs().size(); Integer numJavaCrashes = systemLog.getJavaCrashes().size(); Integer numNativeCrashes = systemLog.getNativeCrashes().size(); // Fetch the last iteration count from the InstrumentationTestResult. We only expect to have // one test, and we take the result from the first test result. Collection<TestResult> testResults = collectingListener.getCurrentRunResults().getTestResults().values(); if (testResults != null && testResults.iterator().hasNext()) { Map<String, String> testMetrics = testResults.iterator().next().getMetrics(); if (testMetrics != null) { CLog.d(testMetrics.toString()); // We want to report all test metrics as well. for (String metric : testMetrics.keySet()) { if (metric.equalsIgnoreCase(CURRENT_ITERATION_LABEL)) { String test_iterations = testMetrics.get(metric); numIterations = Integer.parseInt(test_iterations); } else { stressTestMetrics.put(metric, testMetrics.get(metric)); } } } } // Calculate the number of successful iterations. numSuccessfulIterations = numIterations - numAnrs - numJavaCrashes - numNativeCrashes; // Report other metrics from bugreport. stressTestMetrics.put("anrs", numAnrs.toString()); stressTestMetrics.put("java_crashes", numJavaCrashes.toString()); stressTestMetrics.put("native_crashes", numNativeCrashes.toString()); stressTestMetrics.put("iterations", numSuccessfulIterations.toString()); // Post everything to the dashboard. reportMetrics(listener, mDashboardTestLabel, stressTestMetrics); } /** * 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", metrics); listener.testRunStarted(runName, 0); listener.testRunEnded(0, metrics); } @Override public void setDevice(ITestDevice device) { mTestDevice = device; } @Override public ITestDevice getDevice() { return mTestDevice; } }