/*
* 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.wireless.tests;
import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
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.BugreportCollector;
import com.android.tradefed.result.CollectingTestListener;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.testtype.IDeviceTest;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.StreamUtil;
import junit.framework.Assert;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Run radio outgoing call stress test. The test stresses the voice connection when making
* outgoing calls, number of failures will be collected and reported.
*/
public class TelephonyTest implements IRemoteTest, IDeviceTest {
private ITestDevice mTestDevice = null;
private static String mTestName = "TelephonyTest";
private static final String mOutputFile = "/data/data/com.android.phone/files/phoneResults.txt";
private static final int TEST_TIMER = 15 * 60 * 60 * 1000; // 15 hours
// Define metrics for result report
private static final String mMetricsName = "PhoneVoiceConnectionStress";
private final String[] keys = {"CallActiveFailure", "CallDisconnectionFailure", "HangupFailure",
"ServiceStateChange", "SuccessfulCall"};
private int[] callStatus = new int[5];
private RadioHelper mRadioHelper;
// Define instrumentation test package and runner.
private static final String TEST_PACKAGE_NAME = "com.android.phonetests";
private static final String TEST_RUNNER_NAME = ".PhoneInstrumentationStressTestRunner";
private static final String TEST_CLASS_NAME =
"com.android.phonetests.stress.telephony.TelephonyStress";
public static final String TEST_METHOD = "testRadioOnOutgoingCalls";
@Option(name="call-duration",
description="The time of a call to be held in the test (in seconds)")
private String mCallDuration = "5";
@Option(name="pause-time",
description="The idle time between two calls (in seconds)")
private String mPauseTime = "2";
@Option(name="phone-number",
description="The phone number used for outgoing call test")
private String mPhoneNumber = null;
@Option(name="repeat-count",
description="The number of calls to make during the test")
private String mRepeatCount = "1000";
/**
* Run the telephony outgoing call stress test
* Collect results and post results to dash board
*/
@Override
public void run(ITestInvocationListener listener)
throws DeviceNotAvailableException {
CLog.d("input options: mCallDuration(%s),mPauseTime(%s), mPhoneNumber(%s),"
+ "mRepeatCount(%s)", mCallDuration, mPauseTime, mPhoneNumber, mRepeatCount);
Assert.assertNotNull(mTestDevice);
Assert.assertNotNull(mPhoneNumber);
mRadioHelper = new RadioHelper(mTestDevice);
// wait for data connection
if (!mRadioHelper.radioActivation() || !mRadioHelper.waitForDataSetup()) {
mRadioHelper.getBugreport(listener);
return;
}
IRemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(TEST_PACKAGE_NAME,
TEST_RUNNER_NAME, mTestDevice.getIDevice());
runner.setClassName(TEST_CLASS_NAME);
runner.setMethodName(TEST_CLASS_NAME, TEST_METHOD);
runner.addInstrumentationArg("callduration", mCallDuration);
runner.addInstrumentationArg("pausetime", mPauseTime);
runner.addInstrumentationArg("phonenumber", mPhoneNumber);
runner.setMaxtimeToOutputResponse(TEST_TIMER);
// Add bugreport listener for failed test
BugreportCollector bugListener = new
BugreportCollector(listener, mTestDevice);
bugListener.addPredicate(BugreportCollector.AFTER_FAILED_TESTCASES);
bugListener.setDescriptiveName(mTestName);
// Device may reboot during the test, to capture a bugreport after that,
// wait for 30 seconds for device to be online, otherwise, bugreport will be empty
bugListener.setDeviceWaitTime(30);
CollectingTestListener collectListener = new CollectingTestListener();
int remainingCalls = Integer.parseInt(mRepeatCount);
while (remainingCalls > 0) {
CLog.d("remaining calls: %s", remainingCalls);
runner.addInstrumentationArg("repeatcount", String.valueOf(remainingCalls));
mTestDevice.runInstrumentationTests(runner, bugListener, collectListener);
if (collectListener.hasFailedTests()) {
// the test failed
int numCalls = logOutputFile(bugListener);
remainingCalls -= numCalls;
cleanOutputFiles();
} else {
// the test passed
remainingCalls = 0;
}
}
reportMetrics(mMetricsName, bugListener);
}
/**
* Collect number of successful calls and failure reason
*
* @param listener
*/
private int logOutputFile(ITestInvocationListener listener) throws DeviceNotAvailableException {
File resFile = null;
int calls = 0;
resFile = mTestDevice.pullFile(mOutputFile);
BufferedReader br = null;
try {
if (resFile == null) {
// test failed without writing any results
// either system crash, or other fails, treat as one failed iteration
return 1;
}
br = new BufferedReader(new FileReader(resFile));
String line = br.readLine();
// The output file should only include one line
if (line == null) {
return 0;
}
// Get number of calls and failure reason;
String[] res = line.split(" ");
calls = Integer.parseInt(res[0]);
int reason = Integer.parseInt(res[1]);
callStatus[reason]++;
} catch (IOException e) {
CLog.e("IOException while reading outputfile %s", resFile.getAbsolutePath());
} finally {
FileUtil.deleteFile(resFile);
StreamUtil.close(br);
}
return calls;
}
/**
* Report run metrics by creating an empty test run to stick them in
* <p />
* Exposed for unit testing
*/
private void reportMetrics(String metricsName, ITestInvocationListener listener) {
Map<String, String> metrics = new HashMap<String, String>();
for (int i = 0; i < (keys.length - 1); i++) {
callStatus[keys.length - 1] = Integer.parseInt(mRepeatCount) - callStatus[i];
metrics.put(keys[i], Integer.toString(callStatus[i]));
}
metrics.put(keys[keys.length - 1], Integer.toString(callStatus[keys.length - 1]));
// Create an empty testRun to report the parsed runMetrics
CLog.d("About to report metrics to %s: %s", metricsName, metrics);
listener.testRunStarted(metricsName, 0);
listener.testRunEnded(0, metrics);
}
/**
* Clean up output files from the last test run
*/
private void cleanOutputFiles() throws DeviceNotAvailableException {
CLog.d("Remove output file: %s", mOutputFile);
mTestDevice.executeShellCommand(String.format("rm %s", mOutputFile));
}
@Override
public void setDevice(ITestDevice testDevice) {
mTestDevice = testDevice;
}
@Override
public ITestDevice getDevice() {
return mTestDevice;
}
}