| #!/bin/bash |
| # |
| # Copyright (C) 2008 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. |
| |
| # Options and default values |
| # TODO: other options ideas: |
| # pass options to am (then remove some of the more specific options) |
| # TODO capture more non-error output when not -v |
| # TODO read configs from vendor/*, not just from vendor/google |
| |
| optListTests=0 |
| optSkipBuild=0 |
| optPreview=0 |
| optRawmode=0 |
| optSuiteAssignmentMode=0 |
| optAdbTarget="" |
| optVerbose=0 |
| optWaitForDebugger=0 |
| optTestClass="" |
| optTestMethod="" |
| optUserTests=${HOME}/.android/runtest.rc |
| |
| # |
| # process command-line options. You must pass them into this function. |
| # TODO error messages on once-only or mutually-exclusive options |
| # |
| function processOptions() { |
| while getopts "l b n a r d e s: v w c:t:u:" opt ; do |
| case ${opt} in |
| l ) optListTests=1 ;; |
| b ) optSkipBuild=1 ;; |
| n ) optPreview=1 ;; |
| r ) optRawMode=1 ;; |
| a ) optSuiteAssignmentMode=1 ;; |
| d ) optAdbTarget="-d" ;; |
| e ) optAdbTarget="-e" ;; |
| s ) optAdbTarget="-s ${OPTARG}" ;; |
| v ) optVerbose=1 ;; |
| w ) optWaitForDebugger=1 ;; |
| c ) optTestClass=${OPTARG} ;; |
| t ) optTestMethod=${OPTARG} ;; |
| u ) optUserTests=${OPTARG} ;; |
| esac |
| done |
| } |
| |
| # |
| # Show the command usage and options |
| # |
| function showUsage() { |
| echo "usage: The $progName script works in two ways. You can query it for a list" >&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: |
| # <short-name> <build-path> <test-package> <test-class> |
| # <testrunner-package> <testrunner-component> |
| # |
| # These map to the following commands: |
| # (if test-class = "#") |
| # adb shell am instrument -w \ |
| # <testrunner-package>/<testrunner-component> |
| # (else) |
| # adb shell am instrument -w \ |
| # -e class <test-package>.<test-class> \ |
| # <testrunner-package>/<testrunner-component> |
| # |
| # In order to define the most common cases simply, "#" can be used for some of |
| # the fields, with the following default values: |
| # <build-path> = "#": skip build/sync step |
| # <test-package> = "#": test class is fully qualified with package |
| # <test-class> = "#": omit "-e class" section |
| # <testrunner-package> = "#": use same value as test-package |
| # <testrunner-component> = "#": 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 <test-package> <test-class> <testrunner-package> <testrunner-component> |
| |
| # 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 |
| |