1#!/usr/bin/env bash 2# SPDX-License-Identifier: GPL-2.0 3 4# 5# A simple script to run test with Tradefed. 6# 7 8KERNEL_TF_PREBUILT=prebuilts/tradefed/filegroups/tradefed/tradefed.sh 9PLATFORM_TF_PREBUILT=tools/tradefederation/prebuilts/filegroups/tradefed/tradefed.sh 10JDK_PATH=prebuilts/jdk/jdk11/linux-x86 11PLATFORM_JDK_PATH=prebuilts/jdk/jdk21/linux-x86 12DEFAULT_LOG_DIR=$PWD/out/test_logs/$(date +%Y%m%d_%H%M%S) 13DOWNLOAD_PATH="/tmp/downloaded_tests" 14GCOV=false 15CREATE_TRACEFILE_SCRIPT="kernel/tests/tools/create-tracefile.py" 16FETCH_SCRIPT="kernel/tests/tools/fetch_artifact.sh" 17TRADEFED= 18TRADEFED_GCOV_OPTIONS=" --coverage --coverage-toolchain GCOV_KERNEL --auto-collect GCOV_KERNEL_COVERAGE" 19TEST_ARGS=() 20TEST_DIR= 21TEST_NAMES=() 22 23BOLD="$(tput bold)" 24END="$(tput sgr0)" 25GREEN="$(tput setaf 2)" 26RED="$(tput setaf 198)" 27YELLOW="$(tput setaf 3)" 28BLUE="$(tput setaf 34)" 29 30function adb_checker() { 31 if ! which adb &> /dev/null; then 32 echo -e "\n${RED}Adb not found!${END}" 33 fi 34} 35 36function go_to_repo_root() { 37 current_dir="$1" 38 while [ ! -d ".repo" ] && [ "$current_dir" != "/" ]; do 39 current_dir=$(dirname "$current_dir") # Go up one directory 40 cd "$current_dir" 41 done 42} 43 44function print_info() { 45 local log_prompt=$MY_NAME 46 if [ ! -z "$2" ]; then 47 log_prompt+=" line $2" 48 fi 49 echo "[$log_prompt]: ${GREEN}$1${END}" 50} 51 52function print_warn() { 53 local log_prompt=$MY_NAME 54 if [ ! -z "$2" ]; then 55 log_prompt+=" line $2" 56 fi 57 echo "[$log_prompt]: ${ORANGE}$1${END}" 58} 59 60function print_error() { 61 local log_prompt=$MY_NAME 62 if [ ! -z "$2" ]; then 63 log_prompt+=" line $2" 64 fi 65 echo -e "[$log_prompt]: ${RED}$1${END}" 66 cd $OLD_PWD 67 exit 1 68} 69 70function print_help() { 71 echo "Usage: $0 [OPTIONS]" 72 echo "" 73 echo "This script will run tests on an Android device." 74 echo "" 75 echo "Available options:" 76 echo " -s <serial_number>, --serial=<serial_number>" 77 echo " The device serial number to run tests with." 78 echo " -td <test_dir>, --test-dir=<test_dir> or -tb <test_build>, --test-build=<test_build>" 79 echo " The test artifact file name or directory path." 80 echo " Can be a local file or directory or a remote file" 81 echo " as ab://<branch>/<build_target>/<build_id>/<file_name>." 82 echo " If not specified, it will use the tests in the local" 83 echo " repo." 84 echo " -tl <test_log_dir>, --test-log=<test_log_dir>" 85 echo " The test log dir. Use default out/test_logs if not specified." 86 echo " -ta <test_arg>, --test-arg=<test_arg>" 87 echo " Additional tradefed command arg. Can be repeated." 88 echo " -t <test_name>, --test=<test_name> The test name. Can be repeated." 89 echo " If test is not specified, no tests will be run." 90 echo " -tf <tradefed_binary_path>, --tradefed-bin=<tradefed_binary_path>" 91 echo " The alternative tradefed binary to run test with." 92 echo " --gcov Collect coverage data from the test result" 93 echo " -h, --help Display this help message and exit" 94 echo "" 95 echo "Examples:" 96 echo "$0 -s 127.0.0.1:33847 -t selftests" 97 echo "$0 -s 1C141FDEE003FH -t selftests:kselftest_binderfs_binderfs_test" 98 echo "$0 -s 127.0.0.1:33847 -t CtsAccessibilityTestCases -t CtsAccountManagerTestCases" 99 echo "$0 -s 127.0.0.1:33847 -t CtsAccessibilityTestCases -t CtsAccountManagerTestCases \ 100-td ab://aosp-main/test_suites_x86_64-trunk_staging/latest/android-cts.zip" 101 echo "$0 -s 1C141FDEE003FH -t CtsAccessibilityTestCases -t CtsAccountManagerTestCases \ 102-td ab://git_main/test_suites_arm64-trunk_staging/latest/android-cts.zip" 103 echo "$0 -s 1C141FDEE003FH -t CtsAccessibilityTestCases -td <your_path_to_platform_repo>" 104 echo "" 105 exit 0 106} 107 108function set_platform_repo() { 109 print_warn "Build target product '${TARGET_PRODUCT}' does not match device product '$PRODUCT'" 110 lunch_cli="source build/envsetup.sh && " 111 if [ -f "build/release/release_configs/trunk_staging.textproto" ]; then 112 lunch_cli+="lunch $PRODUCT-trunk_staging-$BUILD_TYPE" 113 else 114 lunch_cli+="lunch $PRODUCT-trunk_staging-$BUILD_TYPE" 115 fi 116 print_info "Setup build environment with: $lunch_cli" 117 eval "$lunch_cli" 118} 119 120function run_test_in_platform_repo() { 121 if [ -z "${TARGET_PRODUCT}" ]; then 122 set_platform_repo 123 elif [[ "${TARGET_PRODUCT}" != *"x86"* && "${PRODUCT}" == *"x86"* ]] || \ 124 [[ "${TARGET_PRODUCT}" == *"x86"* && "${PRODUCT}" != *"x86"* ]]; then 125 set_platform_repo 126 fi 127 atest_cli="atest ${TEST_NAMES[*]} -s $SERIAL_NUMBER --" 128 if $GCOV; then 129 atest_cli+="$TRADEFED_GCOV_OPTIONS" 130 fi 131 eval "$atest_cli" "${TEST_ARGS[*]}" 132 exit_code=$? 133 134 if $GCOV; then 135 atest_log_dir="/tmp/atest_result_$USER/LATEST" 136 create_tracefile_cli="$CREATE_TRACEFILE_SCRIPT -t $atest_log_dir/log -o $atest_log_dir/cov.info" 137 print_info "Skip creating tracefile. If you have full kernel source, run the following command:" 138 print_info "$create_tracefile_cli" 139 fi 140 cd $OLD_PWD 141 exit $exit_code 142} 143 144OLD_PWD=$PWD 145MY_NAME=$0 146 147while test $# -gt 0; do 148 case "$1" in 149 -h|--help) 150 print_help 151 ;; 152 -s) 153 shift 154 if test $# -gt 0; then 155 SERIAL_NUMBER=$1 156 else 157 print_error "device serial is not specified" 158 fi 159 shift 160 ;; 161 --serial*) 162 SERIAL_NUMBER=$(echo $1 | sed -e "s/^[^=]*=//g") 163 shift 164 ;; 165 -tl) 166 shift 167 if test $# -gt 0; then 168 LOG_DIR=$1 169 else 170 print_error "test log directory is not specified" 171 fi 172 shift 173 ;; 174 --test-log*) 175 LOG_DIR=$(echo $1 | sed -e "s/^[^=]*=//g") 176 shift 177 ;; 178 -td | -tb ) 179 shift 180 if test $# -gt 0; then 181 TEST_DIR=$1 182 else 183 print_error "test directory is not specified" 184 fi 185 shift 186 ;; 187 --test-dir* | --test-build*) 188 TEST_DIR=$(echo $1 | sed -e "s/^[^=]*=//g") 189 shift 190 ;; 191 -ta) 192 shift 193 if test $# -gt 0; then 194 TEST_ARGS+=$1 195 else 196 print_error "test arg is not specified" 197 fi 198 shift 199 ;; 200 --test-arg*) 201 TEST_ARGS+=$(echo $1 | sed -e "s/^[^=]*=//g") 202 shift 203 ;; 204 -t) 205 shift 206 if test $# -gt 0; then 207 TEST_NAMES+=$1 208 else 209 print_error "test name is not specified" 210 fi 211 shift 212 ;; 213 --test*) 214 TEST_NAMES+=$(echo $1 | sed -e "s/^[^=]*=//g") 215 shift 216 ;; 217 -tf) 218 shift 219 if test $# -gt 0; then 220 TRADEFED=$1 221 else 222 print_error "tradefed binary is not specified" 223 fi 224 shift 225 ;; 226 --tradefed-bin*) 227 TRADEFED=$(echo $1 | sed -e "s/^[^=]*=//g") 228 shift 229 ;; 230 --gcov) 231 GCOV=true 232 shift 233 ;; 234 *) 235 ;; 236 esac 237done 238 239# Ensure SERIAL_NUMBER is provided 240if [ -z "$SERIAL_NUMBER" ]; then 241 print_error "Device serial is not provided with flag -s <serial_number>." "$LINENO" 242fi 243 244# Ensure TEST_NAMES is provided 245if [ -z "$TEST_NAMES" ]; then 246 print_error "No test is specified with flag -t <test_name>." "$LINENO" 247fi 248 249FULL_COMMAND_PATH=$(dirname "$PWD/$0") 250REPO_LIST_OUT=$(repo list 2>&1) 251if [[ "$REPO_LIST_OUT" == "error"* ]]; then 252 print_warn "Current path $PWD is not in an Android repo. Change path to repo root." "$LINENO" 253 go_to_repo_root "$FULL_COMMAND_PATH" 254 print_info "Changed path to $PWD" "$LINENO" 255else 256 go_to_repo_root "$PWD" 257fi 258 259REPO_ROOT_PATH="$PWD" 260FETCH_SCRIPT="$REPO_ROOT_PATH/$FETCH_SCRIPT" 261 262adb_checker 263 264# Set default LOG_DIR if not provided 265if [ -z "$LOG_DIR" ]; then 266 LOG_DIR="$DEFAULT_LOG_DIR" 267fi 268 269BOARD=$(adb -s "$SERIAL_NUMBER" shell getprop ro.product.board) 270ABI=$(adb -s "$SERIAL_NUMBER" shell getprop ro.product.cpu.abi) 271PRODUCT=$(adb -s "$SERIAL_NUMBER" shell getprop ro.product.product.name) 272BUILD_TYPE=$(adb -s "$SERIAL_NUMBER" shell getprop ro.build.type) 273 274if [ -z "$TEST_DIR" ]; then 275 print_warn "Flag -td <test_dir> is not provided. Will use the default test directory" "$LINENO" 276 if [[ "$REPO_LIST_OUT" == *"build/make"* ]]; then 277 # In the platform repo 278 print_info "Run test with atest" "$LINENO" 279 run_test_in_platform_repo 280 return 281 elif [[ "$BOARD" == "cutf"* ]] && [[ "$REPO_LIST_OUT" == *"common-modules/virtual-device"* ]]; then 282 # In the android kernel repo 283 if [[ "$ABI" == "arm64"* ]]; then 284 TEST_DIR="$REPO_ROOT_PATH/out/virtual_device_aarch64/dist/tests.zip" 285 elif [[ "$ABI" == "x86_64"* ]]; then 286 TEST_DIR="$REPO_ROOT_PATH/out/virtual_device_x86_64/dist/tests.zip" 287 else 288 print_error "No test builds for $ABI Cuttlefish in $REPO_ROOT_PATH" "$LINENO" 289 fi 290 elif [[ "$BOARD" == "raven"* || "$BOARD" == "oriole"* ]] && [[ "$REPO_LIST_OUT" == *"private/google-modules/display"* ]]; then 291 TEST_DIR="$REPO_ROOT_PATH/out/slider/dist/tests.zip" 292 elif [[ "$ABI" == "arm64"* ]] && [[ "$REPO_LIST_OUT" == *"kernel/common"* ]]; then 293 TEST_DIR="$REPO_ROOT_PATH/out/kernel_aarch64/dist/tests.zip" 294 else 295 print_error "No test builds for $ABI $BOARD in $REPO_ROOT_PATH" "$LINENO" 296 fi 297fi 298 299TEST_FILTERS= 300for i in "$TEST_NAMES"; do 301 TEST_NAME=$(echo $i | sed "s/:/ /g") 302 TEST_FILTERS+=" --include-filter '$TEST_NAME'" 303done 304 305if [[ "$TEST_DIR" == ab://* ]]; then 306 if [ ! -d "$DOWNLOAD_PATH" ]; then 307 mkdir -p "$DOWNLOAD_PATH" || $(print_error "Fail to create directory $DOWNLOAD_PATH" "$LINENO") 308 fi 309 cd $DOWNLOAD_PATH || $(print_error "Fail to go to $DOWNLOAD_PATH" "$LINENO") 310 file_name=${TEST_DIR##*/} 311 eval "$FETCH_SCRIPT $TEST_DIR" 312 exit_code=$? 313 if [ $exit_code -eq 0 ]; then 314 print_info "$TEST_DIR is downloaded to $DOWNLOAD_PATH successfully" "$LINENO" 315 else 316 print_error "Failed to download $TEST_DIR" "$LINENO" 317 fi 318 319 file_name=$(ls $file_name) 320 # Check if the download was successful 321 if [ ! -f "${file_name}" ]; then 322 print_error "Failed to download ${file_name}" "$LINENO" 323 fi 324 TEST_DIR="$DOWNLOAD_PATH/$file_name" 325elif [ ! -z "$TEST_DIR" ]; then 326 if [ -d $TEST_DIR ]; then 327 test_file_path=$TEST_DIR 328 elif [ -f "$TEST_DIR" ]; then 329 test_file_path=$(dirname "$TEST_DIR") 330 else 331 print_error "$TEST_DIR is neither a directory or file" "$LINENO" 332 fi 333 cd "$test_file_path" || $(print_error "Failed to go to $test_file_path" "$LINENO") 334 TEST_REPO_LIST_OUT=$(repo list 2>&1) 335 if [[ "$TEST_REPO_LIST_OUT" == "error"* ]]; then 336 print_info "Test path $test_file_path is not in an Android repo. Will use $TEST_DIR directly." "$LINENO" 337 elif [[ "$TEST_REPO_LIST_OUT" == *"build/make"* ]]; then 338 # Test_dir is from the platform repo 339 print_info "Test_dir $TEST_DIR is from Android platform repo. Run test with atest" "$LINENO" 340 go_to_repo_root "$PWD" 341 run_test_in_platform_repo 342 return 343 fi 344fi 345 346cd "$REPO_ROOT_PATH" 347if [[ "$TEST_DIR" == *.zip ]]; then 348 filename=${TEST_DIR##*/} 349 new_test_dir="${TEST_DIR%.*}" 350 if [ -d "$new_test_dir" ]; then 351 rm -r "$new_test_dir" 352 fi 353 unzip -oq "$TEST_DIR" -d "$new_test_dir" || $(print_error "Failed to unzip $TEST_DIR to $new_test_dir" "$LINENO") 354 case $filename in 355 "android-vts.zip" | "android-cts.zip") 356 new_test_dir+="/$(echo $filename | sed "s/.zip//g")" 357 ;; 358 *) 359 ;; 360 esac 361 TEST_DIR="$new_test_dir" # Update TEST_DIR to the unzipped directory 362fi 363 364print_info "Will run tests with test artifacts in $TEST_DIR" "$LINENO" 365 366if [ -f "${TEST_DIR}/tools/vts-tradefed" ]; then 367 TRADEFED="JAVA_HOME=${TEST_DIR}/jdk PATH=${TEST_DIR}/jdk/bin:$PATH ${TEST_DIR}/tools/vts-tradefed" 368 print_info "Will run tests with vts-tradefed from $TRADEFED" "$LINENO" 369 print_info "Many VTS tests need WIFI connection, please make sure WIFI is connected before you run the test." "$LINENO" 370 tf_cli="$TRADEFED run commandAndExit \ 371 vts --skip-device-info --log-level-display info --log-file-path=$LOG_DIR \ 372 $TEST_FILTERS -s $SERIAL_NUMBER" 373elif [ -f "${TEST_DIR}/tools/cts-tradefed" ]; then 374 TRADEFED="JAVA_HOME=${TEST_DIR}/jdk PATH=${TEST_DIR}/jdk/bin:$PATH ${TEST_DIR}/tools/cts-tradefed" 375 print_info "Will run tests with cts-tradefed from $TRADEFED" "$LINENO" 376 print_info "Many CTS tests need WIFI connection, please make sure WIFI is connected before you run the test." "$LINENO" 377 tf_cli="$TRADEFED run commandAndExit cts --skip-device-info \ 378 --log-level-display info --log-file-path=$LOG_DIR \ 379 $TEST_FILTERS -s $SERIAL_NUMBER" 380elif [ -f "${ANDROID_HOST_OUT}/bin/tradefed.sh" ] ; then 381 TRADEFED="${ANDROID_HOST_OUT}/bin/tradefed.sh" 382 print_info "Use the tradefed from the local built path $TRADEFED" "$LINENO" 383 tf_cli="$TRADEFED run commandAndExit template/local_min \ 384 --log-level-display info --log-file-path=$LOG_DIR \ 385 --template:map test=suite/test_mapping_suite --tests-dir=$TEST_DIR\ 386 $TEST_FILTERS -s $SERIAL_NUMBER" 387elif [ -f "$PLATFORM_TF_PREBUILT" ]; then 388 TRADEFED="JAVA_HOME=$PLATFORM_JDK_PATH PATH=$PLATFORM_JDK_PATH/bin:$PATH $PLATFORM_TF_PREBUILT" 389 print_info "Local Tradefed is not built yet. Use the prebuilt from $PLATFORM_TF_PREBUILT" "$LINENO" 390 tf_cli="$TRADEFED run commandAndExit template/local_min \ 391 --log-level-display info --log-file-path=$LOG_DIR \ 392 --template:map test=suite/test_mapping_suite --tests-dir=$TEST_DIR\ 393 $TEST_FILTERS -s $SERIAL_NUMBER" 394elif [ -f "$KERNEL_TF_PREBUILT" ]; then 395 TRADEFED="JAVA_HOME=$JDK_PATH PATH=$JDK_PATH/bin:$PATH $KERNEL_TF_PREBUILT" 396 print_info "Use the tradefed prebuilt from $KERNEL_TF_PREBUILT" "$LINENO" 397 tf_cli="$TRADEFED run commandAndExit template/local_min \ 398 --log-level-display info --log-file-path=$LOG_DIR \ 399 --template:map test=suite/test_mapping_suite --tests-dir=$TEST_DIR\ 400 $TEST_FILTERS -s $SERIAL_NUMBER" 401# No Tradefed found 402else 403 print_error "Can not find Tradefed binary. Please use flag -tf to specify the binary path." "$LINENO" 404fi 405 406# Construct the TradeFed command 407 408# Add GCOV options if enabled 409if $GCOV; then 410 tf_cli+=" --enable-root" 411 tf_cli+=$TRADEFED_GCOV_OPTIONS 412fi 413 414# Evaluate the TradeFed command with extra arguments 415print_info "Run test with: $tf_cli ${TEST_ARGS[*]}" "$LINENO" 416eval "$tf_cli" "${TEST_ARGS[*]}" 417exit_code=$? 418 419if $GCOV; then 420 create_tracefile_cli="$CREATE_TRACEFILE_SCRIPT -t $LOG_DIR -o $LOG_DIR/cov.info" 421 if [ -f $KERNEL_TF_PREBUILT ]; then 422 print_info "Create tracefile with $create_tracefile_cli" "$LINENO" 423 $create_tracefile_cli && \ 424 print_info "Created tracefile at $LOG_DIR/cov.info" "$LINENO" 425 else 426 print_info "Skip creating tracefile. If you have full kernel source, run the following command:" "$LINENO" 427 print_info "$create_tracefile_cli" "$LINENO" 428 fi 429fi 430 431cd $OLD_PWD 432exit $exit_code 433