1 /* 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 */ 16 package com.android.wireless.tests; 17 18 import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner; 19 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; 20 import com.android.tradefed.config.Option; 21 import com.android.tradefed.device.DeviceNotAvailableException; 22 import com.android.tradefed.device.ITestDevice; 23 import com.android.tradefed.log.LogUtil.CLog; 24 import com.android.tradefed.result.ITestInvocationListener; 25 import com.android.tradefed.result.InputStreamSource; 26 import com.android.tradefed.result.LogDataType; 27 import com.android.tradefed.testtype.IDeviceTest; 28 import com.android.tradefed.testtype.IRemoteTest; 29 import com.android.tradefed.util.FileUtil; 30 import com.android.tradefed.util.StreamUtil; 31 32 import org.junit.Assert; 33 34 import java.io.BufferedReader; 35 import java.io.File; 36 import java.io.FileReader; 37 import java.io.IOException; 38 import java.util.HashMap; 39 import java.util.Map; 40 import java.util.concurrent.TimeUnit; 41 import java.util.regex.Matcher; 42 import java.util.regex.Pattern; 43 44 /** 45 * Run radio outgoing call stress test. The test stresses the voice connection when making 46 * outgoing calls, number of failures will be collected and reported. 47 */ 48 public class TelephonyTest implements IRemoteTest, IDeviceTest { 49 private static final int TEST_TIMEOUT = 8 * 60 * 60 * 1000; // 8 hours 50 51 private static final String OUTPUT_FILE = "output.txt"; 52 // Output file in format: iteration [failure_reason] 53 private static final Pattern OUTPUT_LINE_REGEX = Pattern.compile("(\\d+)( (\\d+))?"); 54 55 // Define metrics for result report 56 private static final String METRICS_NAME = "PhoneVoiceConnectionStress"; 57 private static final String SUCCESS_KEY = "SuccessfulCall"; 58 private static final String TEST_FAILURE_KEY = "TestFailure"; 59 private static final String[] FAILURE_KEYS = {"CallActiveFailure", "CallDisconnectionFailure", 60 "HangupFailure", "ServiceStateChange", TEST_FAILURE_KEY}; 61 62 // Define instrumentation test package and runner. 63 private static final String TEST_PACKAGE_NAME = "com.android.phonetests"; 64 private static final String TEST_RUNNER_NAME = ".PhoneInstrumentationStressTestRunner"; 65 private static final String TEST_CLASS_NAME = 66 "com.android.phonetests.stress.telephony.TelephonyStress2"; 67 public static final String TEST_METHOD = "testOutgoingCalls"; 68 69 @Option(name="phone-number", 70 description="The phone number used for outgoing call test") 71 private String mPhoneNumber = null; 72 73 @Option(name="iterations", 74 description="The number of calls to make during the test") 75 private int mIterations = 1000; 76 77 @Option(name="call-duration", 78 description="The time of a call to be held in the test (in seconds)") 79 private long mCallDurationSec = 5; 80 81 @Option(name="start-pause-duration", 82 description="The time to wait before starting tests (in seconds)") 83 private long mStartPauseDurationSec = 2; 84 85 private ITestDevice mTestDevice = null; 86 87 /** 88 * Run the telephony outgoing call stress test 89 * Collect results and post results to dash board 90 */ 91 @Override 92 public void run(ITestInvocationListener listener) 93 throws DeviceNotAvailableException { 94 Assert.assertNotNull(mTestDevice); 95 Assert.assertNotNull(mPhoneNumber); 96 97 final RadioHelper radioHelper = new RadioHelper(mTestDevice); 98 Assert.assertTrue("Radio activation failed", radioHelper.radioActivation()); 99 Assert.assertTrue("Data setup failed", radioHelper.waitForDataSetup()); 100 101 IRemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(TEST_PACKAGE_NAME, 102 TEST_RUNNER_NAME, mTestDevice.getIDevice()); 103 runner.setClassName(TEST_CLASS_NAME); 104 runner.setMethodName(TEST_CLASS_NAME, TEST_METHOD); 105 106 runner.addInstrumentationArg("phone-number", mPhoneNumber); 107 runner.addInstrumentationArg("iterations", Integer.toString(mIterations)); 108 runner.addInstrumentationArg("current-iteration", Integer.toString(0)); 109 runner.addInstrumentationArg("call-duration", Long.toString(mCallDurationSec)); 110 runner.addInstrumentationArg("start-pause-duration", Long.toString(mStartPauseDurationSec)); 111 runner.setMaxTimeToOutputResponse(TEST_TIMEOUT, TimeUnit.MILLISECONDS); 112 113 mTestDevice.runInstrumentationTests(runner, listener); 114 115 Map<String, Integer> metrics = new HashMap<String, Integer>(4); 116 for (String key : FAILURE_KEYS) { 117 metrics.put(key, 0); 118 } 119 int successfulIterations = processOutputFile(metrics); 120 metrics.put(SUCCESS_KEY, successfulIterations); 121 122 if (successfulIterations < mIterations) { 123 mTestDevice.waitForDeviceOnline(30 * 1000); 124 InputStreamSource bugreport = mTestDevice.getBugreport(); 125 InputStreamSource screenshot = mTestDevice.getScreenshot(); 126 try { 127 listener.testLog(String.format("bugreport_%s", successfulIterations), 128 LogDataType.BUGREPORT, bugreport); 129 listener.testLog(String.format("screenshot_%s", successfulIterations), 130 LogDataType.PNG, screenshot); 131 } finally { 132 StreamUtil.cancel(bugreport); 133 StreamUtil.cancel(screenshot); 134 } 135 } 136 137 reportMetrics(listener, metrics); 138 } 139 140 /** 141 * Process the output file, add the failure reason to the file, and return the number of 142 * successful iterations. 143 */ 144 private int processOutputFile(Map<String, Integer> failures) 145 throws DeviceNotAvailableException { 146 final File resFile = mTestDevice.pullFileFromExternal(OUTPUT_FILE); 147 BufferedReader reader = null; 148 try { 149 if (resFile == null) { 150 CLog.w("Output file did not exist"); 151 failures.put(TEST_FAILURE_KEY, failures.get(TEST_FAILURE_KEY) + 1); 152 return 0; 153 } 154 reader = new BufferedReader(new FileReader(resFile)); 155 String line = getLastLine(reader); 156 157 if (line == null) { 158 CLog.w("Output file was emtpy"); 159 failures.put(TEST_FAILURE_KEY, failures.get(TEST_FAILURE_KEY) + 1); 160 return 0; 161 } 162 163 Matcher m = OUTPUT_LINE_REGEX.matcher(line); 164 if (!m.matches()) { 165 CLog.w("Output did not match the expected pattern. Line was \"%s\"", line); 166 failures.put(TEST_FAILURE_KEY, failures.get(TEST_FAILURE_KEY) + 1); 167 return 0; 168 } 169 170 final int recordedIteration = Integer.parseInt(m.group(1)); 171 if (m.group(3) != null) { 172 final int failureCode = Integer.parseInt(m.group(3)); 173 final String key = FAILURE_KEYS[failureCode]; 174 failures.put(key, 1); 175 return recordedIteration; 176 } 177 178 return recordedIteration + 1; 179 } catch (IOException e) { 180 CLog.e("IOException while reading outputfile %s", resFile.getAbsolutePath()); 181 failures.put(TEST_FAILURE_KEY, failures.get(TEST_FAILURE_KEY) + 1); 182 return 0; 183 } finally { 184 FileUtil.deleteFile(resFile); 185 StreamUtil.close(reader); 186 mTestDevice.executeShellCommand(String.format("rm ${EXTERNAL_STORAGE}/%s", 187 OUTPUT_FILE)); 188 } 189 } 190 191 /** 192 * Get the last line from a buffered reader. 193 */ 194 private String getLastLine(BufferedReader reader) throws IOException { 195 String lastLine = null; 196 String currentLine; 197 while ((currentLine = reader.readLine()) != null) { 198 lastLine = currentLine; 199 } 200 return lastLine; 201 } 202 203 /** 204 * Report run metrics by creating an empty test run to stick them in 205 */ 206 private void reportMetrics(ITestInvocationListener listener, Map<String, Integer> metrics) { 207 Map<String, String> reportedMetrics = new HashMap<String, String>(); 208 for (Map.Entry<String, Integer> entry : metrics.entrySet()) { 209 reportedMetrics.put(entry.getKey(), Integer.toString(entry.getValue())); 210 } 211 212 // Create an empty testRun to report the parsed runMetrics 213 CLog.d("About to report metrics to %s: %s", METRICS_NAME, reportedMetrics); 214 listener.testRunStarted(METRICS_NAME, 0); 215 listener.testRunEnded(0, reportedMetrics); 216 } 217 218 @Override 219 public void setDevice(ITestDevice testDevice) { 220 mTestDevice = testDevice; 221 } 222 223 @Override 224 public ITestDevice getDevice() { 225 return mTestDevice; 226 } 227 } 228