Home | History | Annotate | Download | only in tests
      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