From 6c6c1ab5fd5b7559c271438f50b22edbea1e1f05 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Wed, 6 May 2009 11:45:33 -0700 Subject: [PATCH] Manual merge of runtest fixes in donut and new account test def add in master. commit 8a101cb057c1d1d5397b988b6a3f4c3add879008 Author: Brett Chabot Date: Tue May 5 12:56:39 2009 -0700 runtest.py bug fixes. Improved error handling, and added support for "size" and "package" arguments. Removed deprecated runtest shell script. --- testrunner/adb_interface.py | 28 ++- testrunner/errors.py | 3 + testrunner/run_command.py | 11 +- testrunner/runtest.py | 15 +- testrunner/test_defs.xml | 6 + tools/runtest | 368 ------------------------------------ 6 files changed, 38 insertions(+), 393 deletions(-) delete mode 100755 tools/runtest diff --git a/testrunner/adb_interface.py b/testrunner/adb_interface.py index ad1b2c94f..dd8d6f41a 100755 --- a/testrunner/adb_interface.py +++ b/testrunner/adb_interface.py @@ -64,7 +64,7 @@ class AdbInterface: string output of command Raises: - WaitForResponseTimedOutError if device does not respond to command + WaitForResponseTimedOutError if device does not respond to command within time """ adb_cmd = "adb %s %s" % (self._target_arg, command_string) logger.SilentLog("about to run %s" % adb_cmd) @@ -327,32 +327,30 @@ class AdbInterface: Raises: WaitForResponseTimedOutError if package manager does not respond + AbortError if unrecoverable error occurred """ - output = self.SendCommand("sync", retry_count=retry_count) + output = "" + error = None + try: + output = self.SendCommand("sync", retry_count=retry_count) + except errors.AbortError, e: + error = e + output = e.msg if "Read-only file system" in output: logger.SilentLog(output) logger.Log("Remounting read-only filesystem") self.SendCommand("remount") output = self.SendCommand("sync", retry_count=retry_count) - if "No space left on device" in output: + elif "No space left on device" in output: logger.SilentLog(output) logger.Log("Restarting device runtime") self.SendShellCommand("stop", retry_count=retry_count) output = self.SendCommand("sync", retry_count=retry_count) self.SendShellCommand("start", retry_count=retry_count) - + elif error is not None: + # exception occurred that cannot be recovered from + raise error logger.SilentLog(output) self.WaitForDevicePm() return output - - def IsDevicePresent(self): - """Check if targeted device is present. - Returns: - True if device is present, False otherwise. - """ - output = self.SendShellCommand("ls", retry_count=0) - if output.startswith("error:"): - return False - else: - return True diff --git a/testrunner/errors.py b/testrunner/errors.py index 6d606ecf5..e24089918 100755 --- a/testrunner/errors.py +++ b/testrunner/errors.py @@ -34,6 +34,9 @@ class AbortError(Exception): """Generic exception that indicates a fatal error has occurred and program execution should be aborted.""" + def __init__(self, msg="AbortError"): + self.msg = msg + class ParseError(Exception): """Raised when xml data to parse has unrecognized format.""" diff --git a/testrunner/run_command.py b/testrunner/run_command.py index 44499457c..a98a943a2 100755 --- a/testrunner/run_command.py +++ b/testrunner/run_command.py @@ -58,10 +58,11 @@ def RunOnce(cmd, timeout_time=None, return_output=True): start_time = time.time() so = [] pid = [] - global _abort_on_error + global _abort_on_error, error_occurred error_occurred = False def Run(): + global error_occurred if return_output: output_dest = subprocess.PIPE else: @@ -83,8 +84,8 @@ def RunOnce(cmd, timeout_time=None, return_output=True): logger.Log(e) so.append("ERROR") error_occurred = True - if pipe.returncode < 0: - logger.SilentLog("Error: %s was terminated by signal %d" %(cmd, + if pipe.returncode != 0: + logger.SilentLog("Error: %s returned %d error code" %(cmd, pipe.returncode)) error_occurred = True @@ -111,9 +112,9 @@ def RunOnce(cmd, timeout_time=None, return_output=True): time.sleep(0.1) t.join() - + output = "".join(so) if _abort_on_error and error_occurred: - raise errors.AbortError + raise errors.AbortError(msg=output) return "".join(so) diff --git a/testrunner/runtest.py b/testrunner/runtest.py index fe6dfad0d..fde67adf7 100755 --- a/testrunner/runtest.py +++ b/testrunner/runtest.py @@ -95,6 +95,10 @@ class TestRunner(object): help="Restrict test to a specific class") parser.add_option("-m", "--test-method", dest="test_method", help="Restrict test to a specific method") + parser.add_option("-p", "--test-package", dest="test_package", + help="Restrict test to a specific java package") + parser.add_option("-z", "--size", dest="test_size", + help="Restrict test to a specific test size") parser.add_option("-u", "--user-tests-file", dest="user_tests_file", metavar="FILE", default=user_test_default, help="Alternate source of user test definitions") @@ -252,6 +256,10 @@ class TestRunner(object): instrumentation_args = {} if test_class is not None: instrumentation_args["class"] = test_class + if self._options.test_package: + instrumentation_args["package"] = self._options.test_package + if self._options.test_size: + instrumentation_args["size"] = self._options.test_size if self._options.wait_for_debugger: instrumentation_args["debug"] = "true" if self._options.suite_assign_mode: @@ -386,10 +394,6 @@ class TestRunner(object): self._DumpTests() return - if not self._adb.IsDevicePresent(): - logger.Log("Error: specified device cannot be found") - return - if not self._options.skip_build: self._DoBuild() @@ -400,7 +404,8 @@ class TestRunner(object): self._RunTest(test_suite) except KeyboardInterrupt: logger.Log("Exiting...") - except errors.AbortError: + except errors.AbortError, e: + logger.Log(e.msg) logger.SilentLog("Exiting due to AbortError...") except errors.WaitForResponseTimedOutError: logger.Log("Timed out waiting for response") diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml index 8508b3401..156594561 100644 --- a/testrunner/test_defs.xml +++ b/testrunner/test_defs.xml @@ -100,6 +100,12 @@ Native tests: coverage_target="framework" continuous="true" /> + + &2 - echo " of tests, or you can launch a test, test case, or test suite." >&2 - echo "" >&2 - echo " $progName -l # To view the list of tests" >&2 - echo "" >&2 - echo " $progName # To launch tests" >&2 - echo " [-b] # Skip build - just launch" >&2 - echo " [-n] # Do not execute, just preview commands" >&2 - echo " [-r] # Raw mode (for output to other tools)" >&2 - echo " [-a] # Suite assignment (for details & usage" >&2 - echo " # see InstrumentationTestRunner)" >&2 - echo " [-v] # Increase verbosity of ${progName}" >&2 - echo " [-w] # Wait for debugger before launching tests" >&2 - echo " [-c test-class] # Restrict test to a specific class" >&2 - echo " [-t test-method] # Restrict test to a specific method" >&2 - echo " [-e | -d | -s ser-num] # use emulator, device, or serial number" >&2 - echo " [-u user-tests-file] # Alternate source of user definitions" >&2 - echo " short-test-name # (req'd) test configuration to launch" >&2 -} - -# The list below are built-in test definitions. You can also define your own -# tests by creating a file named "~/.android/runtest.rc" and adding them to that -# file. (No array needed, just plain lines of text). -# -# Tests are defined by entries with the following format: -# -# -# -# These map to the following commands: -# (if test-class = "#") -# adb shell am instrument -w \ -# / -# (else) -# adb shell am instrument -w \ -# -e class . \ -# / -# -# In order to define the most common cases simply, "#" can be used for some of -# the fields, with the following default values: -# = "#": skip build/sync step -# = "#": test class is fully qualified with package -# = "#": omit "-e class" section -# = "#": use same value as test-package -# = "#": use "android.test.InstrumentationTestRunner" -# -# TODO: fields may be omitted completely if the trailing values are all "#" -# TODO: this should be a here doc instead of an array - -knownTests=( - # NAME BUILD DIR - - # system-wide tests - "framework frameworks/base/tests/FrameworkTest # com.android.frameworktest.AllTests com.android.frameworktest.tests #" - "account frameworks/base/tests/AndroidTests # com.android.unit_tests.accounts.AccountManagerServiceTest com.android.unit_tests #" - "android frameworks/base/tests/AndroidTests com.android.unit_tests AndroidTests # #" - "smoke frameworks/base/tests/SmokeTest com.android.smoketest # com.android.smoketest.tests #" - "core frameworks/base/tests/CoreTests # android.core.CoreTests android.core #" - "libcore frameworks/base/tests/CoreTests # android.core.JavaTests android.core #" - "apidemos development/samples/ApiDemos com.example.android.apis # com.example.android.apis.tests #" - "launchperf development/apps/launchperf com.android.launchperf # # .SimpleActivityLaunchPerformance" - - # targeted framework tests - "heap frameworks/base/tests/AndroidTests com.android.unit_tests HeapTest # #" - "activity frameworks/base/tests/AndroidTests com.android.unit_tests activity.ActivityTests # #" - "deadlock tests/Deadlock com.android.deadlock # com.android.deadlock.tests #" - "syncadapter vendor/google/tests/AbstractGDataSyncAdapterTest # # com.google.android.providers.abstractgdatasyncadaptertests #" - "tablemerger frameworks/base/tests/FrameworkTest # android.content.AbstractTableMergerTest com.android.frameworktest.tests #" - - # selected app tests - "browser packages/apps/Browser com.android.browser # # .BrowserTestRunner" - "browserfunc packages/apps/Browser com.android.browser # # .BrowserFunctionalTestRunner" - "calendar packages/apps/Calendar/tests com.android.calendar.tests # # #" - "calprov packages/providers/CalendarProvider com.android.providers.calendar # com.android.providers.calendar.tests #" - "camera tests/Camera com.android.cameratests # # CameraInstrumentationTestRunner" - "contactsprov packages/providers/GoogleContactsProvider/tests com.android.providers.contacts # com.android.providers.contactstests #" - "email packages/apps/Email com.android.email # com.android.email.tests #" - "emailsmall packages/apps/Email com.android.email SmallTests com.android.email.tests #" - "media tests/MediaFrameworkTest com.android.mediaframeworktest # # .MediaFrameworkTestRunner" - "mediaunit tests/MediaFrameworkTest com.android.mediaframeworktest # # .MediaFrameworkUnitTestRunner" - "mediaprov tests/MediaProvider com.android.mediaprovidertests # # .MediaProviderTestsInstrumentation" - "mms packages/apps/Mms # # com.android.mms.tests com.android.mms.ui.MMSInstrumentationTestRunner" - "mmslaunch packages/apps/Mms # # com.android.mms.tests com.android.mms.SmsLaunchPerformance" - "phone tests/Phone com.android.phonetests # # .PhoneInstrumentationTestRunner" - "phonestress tests/Phone com.android.phonetests # # .PhoneInstrumentationStressTestRunner" - "ringtone tests/RingtoneSettings com.android.ringtonesettingstests # # .RingtoneSettingsInstrumentationTestRunner" -) - -# -# Searches for a runtest.rc file in a given directory and, if found, prepends it to -# the list of known tests. -# -function readConfigFile () { - rcFile=$1 - if [[ -f ${rcFile} ]] ; then - declare -a lines - exec 3<${rcFile} || exit - while read curline <&3; do - if [[ -z ${curline} || ${curline:0:1} = "#" ]]; then - continue - fi - lines=("${lines[@]}" "${curline}") - done - exec 3<&- - - # now prepend the user lines (so they can override defaults) - knownTests=("${lines[@]}" "${knownTests[@]}") - fi -} - -# -# Searches for a specific test in the knownTests array. If found, writes out -# the remaining elements in the definition line (not including the test name). -# -function findTest() { - count=${#knownTests[@]} - index=0 - while [[ ${index} -lt ${count} ]] - do - # If the first word in the entry matches the argument... - test=(${knownTests[$index]}) - if [[ ${test[0]} = $1 ]] ; then - # Print all but the first word - echo ${test[@]:1} - return - fi - let "index = $index + 1" - done -} - -# -# Generate a simple listing of available tests -# -function dumpTests() { - echo "The following tests are currently defined:" - count=${#knownTests[@]} - index=0 - while [[ ${index} -lt ${count} ]] - do - test=(${knownTests[$index]}) - echo " " ${test[0]} - let "index = $index + 1" - done -} - -# -# Writes the full pathname of the "top" of the development tree, as set by envsetup & lunch. -# (based on gettop() from envsetup.sh) -# -function gettop { - TOPFILE=build/core/envsetup.mk - if [[ -n ${TOP} && -f ${TOP}/${TOPFILE} ]] ; then - echo ${TOP} - else - if [[ -f ${TOPFILE} ]] ; then - echo ${PWD} - else - # We redirect cd to /dev/null in case it's aliased to - # a command that prints something as a side-effect - # (like pushd) - HERE=${PWD} - T= - # while [ \( ! \( -f ${TOPFILE} \) \) -a \( $PWD != "/" \) ]; do - while [[ ! -f ${TOPFILE} && ${PWD} != "/" ]] ; do - cd .. > /dev/null - T=${PWD} - done - cd ${HERE} > /dev/null - if [[ -f ${T}/${TOPFILE} ]]; then - echo ${T} - fi - fi - fi -} - -# -# Captures the "mmm" command from envsetup.sh -# -function call_mmm() { - TOP=$(gettop) - if [[ -n ${TOP} ]] ; then - . ${TOP}/build/envsetup.sh - mmm ${TOP}/$@ - fi -} - -# main script - -progName=$(basename $0) - -if [[ $# -eq 0 ]] ; then - showUsage - exit 1 -fi - -processOptions $@ -shift $((OPTIND-1)) - -readConfigFile $optUserTests -# TODO: Read from *any* vendor/*/runtest.rc -readConfigFile $(gettop)/vendor/google/runtest.rc - -# if requested, list all tests and halt -if [[ ${optListTests} -ne 0 ]] ; then - dumpTests - exit 0 -fi - -testInfo=($(findTest $1)) -if [[ ${#testInfo[@]} -eq 5 ]] ; then - # break out test definition elements - buildPath=${testInfo[0]} - testPackage=${testInfo[1]} - testClass=${testInfo[2]} - runnerPackage=${testInfo[3]} - runnerComponent=${testInfo[4]} - - # replace wildcards with default values - if [[ ${testPackage} == "#" ]] ; then - testPackage= - fi - if [[ ${runnerPackage} == "#" ]] ; then - runnerPackage=$testPackage - fi - if [[ ${runnerComponent} == "#" ]] ; then - runnerComponent="android.test.InstrumentationTestRunner" - fi - - if [[ -n ${optTestClass} ]] ; then - testClass=$optTestClass - fi - - # build & sync, if requested - if [[ ${optSkipBuild} -eq 0 ]] ; then - if [[ ${buildPath} != "#" ]] ; then - if [[ $optVerbose -ne 0 || ${optPreview} -ne 0 ]] ; then - echo mmm ${buildPath} "&&" adb ${optAdbTarget} remount "&&" adb ${optAdbTarget} sync - fi - if [[ ${optPreview} -eq 0 ]] ; then - call_mmm ${buildPath} && adb ${optAdbTarget} remount && adb ${optAdbTarget} sync - buildResult=$? - else - buildResult=0 - fi - if [[ $buildResult -ne 0 ]] ; then - exit ${buildResult} - fi - # finally, sleep a bit. this is a hack. it gives the package manager time to - # install the package(s) that were just synced. this causes a reduction in the number - # of false failures, but it's not a perfect solution. - if [ ${optPreview} -eq 0 ] ; then - echo "sleeping..." - sleep 2 - fi - fi - fi - - # setup additional clauses for the command - classOptions="" - if [[ ${testClass} != "#" ]] ; then - if [[ -z ${testPackage} ]] ; then - classOptions="-e class ${testClass}" - else - classOptions="-e class ${testPackage}.${testClass}" - fi - if [[ -n ${optTestMethod} ]] ; then - classOptions=${classOptions}#${optTestMethod} - fi - fi - debugOptions="" - if [[ ${optWaitForDebugger} -ne 0 ]] ; then - debugOptions="-e debug true" - fi - fi - if [[ ${optSuiteAssignmentMode} -ne 0 ]] ; then - debugOptions="-e suiteAssignment true "${debugOptions} - fi - if [[ ${optRawMode} -ne 0 ]] ; then - debugOptions="-r "${debugOptions} - fi - - # "prevent" a race condition where we try to run the tests before they're - # actually installed - if [ ${optPreview} -eq 0 ] ; then - echo "sleeping..." - sleep 2 - fi - - # now run the command - if [[ $optVerbose -ne 0 || ${optPreview} -ne 0 ]] ; then - echo adb ${optAdbTarget} shell am instrument -w \ - ${debugOptions} \ - ${classOptions} \ - ${runnerPackage}/${runnerComponent} - fi - if [[ ${optPreview} -eq 0 ]] ; then - adb ${optAdbTarget} shell am instrument -w \ - ${debugOptions} \ - ${classOptions} \ - ${runnerPackage}/${runnerComponent} - fi - exit 0 -else - echo "$progName: unknown test \"$1\"" >&2 - exit 1 -fi -