#!/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: # # # # 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 #" "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. sleep 2 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 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 sleep 2 # 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