1 /* 2 * Copyright (C) 2012 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 17 package com.android.browser.tests; 18 19 import com.android.ddmlib.IDevice; 20 import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner; 21 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; 22 import com.android.tradefed.config.Option; 23 import com.android.tradefed.config.Option.Importance; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.device.ITestDevice; 26 import com.android.tradefed.invoker.ITestInvocation; 27 import com.android.tradefed.log.LogUtil.CLog; 28 import com.android.tradefed.result.CollectingTestListener; 29 import com.android.tradefed.result.ITestInvocationListener; 30 import com.android.tradefed.testtype.IDeviceTest; 31 import com.android.tradefed.testtype.IRemoteTest; 32 33 import java.util.HashMap; 34 import java.util.Map; 35 import java.util.concurrent.TimeUnit; 36 37 /** 38 * Base test harness class for browser site load test. 39 * 40 * The class can be configured to run Android Browser stability test with a preconfigured list 41 * of sites pushed into ${EXTERNAL_STORAGE}/popular_urls.txt 42 * 43 */ 44 public class BrowserSiteLoadTest implements IRemoteTest, IDeviceTest { 45 46 private static final String URLS_FILE_NAME = "popular_urls.txt"; 47 private static final String STATUS_FILE_NAME = "test_status.txt"; 48 private static final String TEST_CLASS_NAME = "com.android.browser.PopularUrlsTest"; 49 private static final String TEST_METHOD_NAME = "testStability"; 50 private static final String TEST_PACKAGE_NAME = "com.android.browser.tests"; 51 private static final String TEST_RUNNER_NAME = "android.test.InstrumentationTestRunner"; 52 53 private static final int MAX_TIMEOUT_MS = 8 * 60 * 60 * 1000; // max test timeout is 8 hrs 54 55 private ITestDevice mTestDevice = null; 56 57 @Option(name = "metrics-name", description = "name used to identify the metrics for reporting", 58 importance = Importance.ALWAYS) 59 private String mMetricsName; 60 61 @Option(name = "schema-key", 62 description = "the schema key that number of successful loads should be reported under", 63 importance = Importance.ALWAYS) 64 private String mSchemaKey; 65 66 @Option(name = "test-package", 67 description = "package name of the stability test. defaults to that of AOSP Browser") 68 private String mTestPackage = TEST_PACKAGE_NAME; 69 70 @Option(name = "test-class", 71 description = "class name of the stability test. defaults to that of AOSP Browser") 72 private String mTestClass = TEST_CLASS_NAME; 73 74 @Option(name = "test-method", 75 description = "method name of the stability test. defaults to that of AOSP Browser") 76 private String mTestMethod = TEST_METHOD_NAME; 77 78 @Option(name = "total-sites", description = "expected total number of site loads") 79 private int mTotalSites = 0; 80 81 private String mUrlsFilePath; 82 private String mStatusFilePath; 83 84 /** 85 * {@inheritDoc} 86 */ 87 @Override 88 public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { 89 int failCounter = 0; 90 Map<String, String> finalMetrics = new HashMap<String, String>(); 91 92 preTestSetup(); 93 94 // Create and config runner for instrumentation test 95 IRemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mTestPackage, 96 TEST_RUNNER_NAME, mTestDevice.getIDevice()); 97 runner.setClassName(mTestClass); 98 runner.setMethodName(mTestClass, mTestMethod); 99 // max timeout is the smaller of: 8 hrs or 1 minute per site 100 runner.setMaxTimeToOutputResponse(Math.min(MAX_TIMEOUT_MS, 60 * 1000 * mTotalSites), 101 TimeUnit.MILLISECONDS); 102 103 CollectingTestListener collectingTestListener = new CollectingTestListener(); 104 failCounter = runStabilityTest(runner, collectingTestListener); 105 finalMetrics.put(mSchemaKey, Integer.toString(mTotalSites - failCounter)); 106 107 reportMetrics(listener, mMetricsName, finalMetrics); 108 } 109 110 /** 111 * {@inheritDoc} 112 */ 113 @Override 114 public ITestDevice getDevice() { 115 return mTestDevice; 116 } 117 118 /** 119 * {@inheritDoc} 120 */ 121 @Override 122 public void setDevice(ITestDevice device) { 123 mTestDevice = device; 124 } 125 126 /** 127 * Wipes the device's external memory of test collateral from prior runs. 128 * 129 * @throws DeviceNotAvailableException If the device is unavailable or 130 * something happened while deleting files 131 */ 132 private void preTestSetup() throws DeviceNotAvailableException { 133 String extStore = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); 134 mUrlsFilePath = String.format("%s/%s", extStore, URLS_FILE_NAME); 135 mStatusFilePath = String.format("%s/%s", extStore, STATUS_FILE_NAME); 136 if (!mTestDevice.doesFileExist(mUrlsFilePath)) { 137 throw new RuntimeException("missing URL list file at: " + mUrlsFilePath); 138 } 139 mTestDevice.executeShellCommand("rm " + mStatusFilePath); 140 } 141 142 /** 143 * Report run metrics by creating an empty test run to stick them in. 144 * 145 * @param listener The {@link ITestInvocation} of test results 146 * @param runName The test name 147 * @param metrics The {@link Map} that contains metrics for the given test 148 */ 149 private void reportMetrics(ITestInvocationListener listener, String runName, 150 Map<String, String> metrics) { 151 CLog.i(String.format("About to report metrics: loaded=%s", metrics.get(mSchemaKey))); 152 listener.testRunStarted(runName, 0); 153 listener.testRunEnded(0, metrics); 154 } 155 156 /** 157 * Helper method for iterating through popular_urls.txt and reporting back 158 * how many pages fail to load. 159 * 160 * @param runner The {@link IRemoteAndroidTestRunner} for instrumentation 161 * @param listener The {@link CollectingTestListener} of test results 162 * @return Number of pages that failed to load 163 */ 164 private int runStabilityTest(IRemoteAndroidTestRunner runner, CollectingTestListener listener) 165 throws DeviceNotAvailableException { 166 boolean exitConditionMet = false; 167 int failureCounter = 0; 168 while (!exitConditionMet) { 169 mTestDevice.runInstrumentationTests(runner, listener); 170 // if the status file exists, then the previous instrumentation has crashed 171 if (!mTestDevice.doesFileExist(mStatusFilePath)) { 172 exitConditionMet = true; 173 } else { 174 ++failureCounter; 175 } 176 } 177 return failureCounter; 178 } 179 } 180