xref: /aosp_15_r20/kernel/tests/tools/run_test_only.sh (revision 2f2c4c7ab4226c71756b9c31670392fdd6887c4f)
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>"
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)
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*)
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.build.product)
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    elif [[ "$BOARD" == "cutf"* ]] && [[ "$REPO_LIST_OUT" == *"common-modules/virtual-device"* ]]; then
281        # In the android kernel repo
282        if [[ "$ABI" == "arm64"* ]]; then
283            TEST_DIR="$REPO_ROOT_PATH/out/virtual_device_aarch64/dist/tests.zip"
284        elif [[ "$ABI" == "x86_64"* ]]; then
285            TEST_DIR="$REPO_ROOT_PATH/out/virtual_device_x86_64/dist/tests.zip"
286        else
287            print_error "No test builds for $ABI Cuttlefish in $REPO_ROOT_PATH" "$LINENO"
288        fi
289    elif [[ "$BOARD" == "raven"* || "$BOARD" == "oriole"* ]] && [[ "$REPO_LIST_OUT" == *"private/google-modules/display"* ]]; then
290        TEST_DIR="$REPO_ROOT_PATH/out/slider/dist/tests.zip"
291    elif [[ "$ABI" == "arm64"* ]] && [[ "$REPO_LIST_OUT" == *"kernel/common"* ]]; then
292        TEST_DIR="$REPO_ROOT_PATH/out/kernel_aarch64/dist/tests.zip"
293    else
294        print_error "No test builds for $ABI $BOARD in $REPO_ROOT_PATH" "$LINENO"
295    fi
296fi
297
298TEST_FILTERS=
299for i in "$TEST_NAMES"; do
300    TEST_NAME=$(echo $i | sed "s/:/ /g")
301    TEST_FILTERS+=" --include-filter '$TEST_NAME'"
302done
303
304if [[ "$TEST_DIR" == ab://* ]]; then
305    # Download test_file if it's remote file ab://
306    if [ -d "$DOWNLOAD_PATH" ]; then
307        rm -rf "$DOWNLOAD_PATH"
308    fi
309    mkdir -p "$DOWNLOAD_PATH" || $(print_error "Fail to create directory $DOWNLOAD_PATH" "$LINENO")
310    cd $DOWNLOAD_PATH || $(print_error "Fail to go to $DOWNLOAD_PATH" "$LINENO")
311    file_name=${TEST_DIR##*/}
312    eval "$FETCH_SCRIPT $TEST_DIR"
313    exit_code=$?
314    if [ $exit_code -eq 0 ]; then
315        print_info "$TEST_DIR is downloaded succeeded" "$LINENO"
316    else
317        print_error "Failed to download $TEST_DIR" "$LINENO"
318    fi
319
320    file_name=$(ls $file_name)
321    # Check if the download was successful
322    if [ ! -f "${file_name}" ]; then
323        print_error "Failed to download ${file_name}" "$LINENO"
324    fi
325    TEST_DIR="$DOWNLOAD_PATH/$file_name"
326elif [ ! -z "$TEST_DIR" ]; then
327    if [ -d $TEST_DIR ]; then
328        test_file_path=$TEST_DIR
329    elif [ -f "$TEST_DIR" ]; then
330        test_file_path=$(dirname "$TEST_DIR")
331    else
332        print_error "$TEST_DIR is neither a directory or file"  "$LINENO"
333    fi
334    cd "$test_file_path" || $(print_error "Failed to go to $test_file_path" "$LINENO")
335    TEST_REPO_LIST_OUT=$(repo list 2>&1)
336    if [[ "$TEST_REPO_LIST_OUT" == "error"* ]]; then
337        print_info "Test path $test_file_path is not in an Android repo. Will use $TEST_DIR directly." "$LINENO"
338    elif [[ "$TEST_REPO_LIST_OUT" == *"build/make"* ]]; then
339        # Test_dir is from the platform repo
340        print_info "Test_dir $TEST_DIR is from Android platform repo. Run test with atest" "$LINENO"
341        go_to_repo_root "$PWD"
342        run_test_in_platform_repo
343    fi
344fi
345
346cd "$REPO_ROOT_PATH"
347if [[ "$TEST_DIR" == *".zip"* ]]; then
348    filename=${TEST_DIR##*/}
349    new_test_dir="$REPO_ROOT_PATH/out/tests"
350    if [ ! -d "$new_test_dir" ]; then
351        mkdir -p "$new_test_dir" || $(print_error "Failed to make directory $new_test_dir" "$LINENO")
352    else
353        folder_name="${filenamef%.*}"
354        rm -r "$new_test_dir/$folder_name"
355    fi
356    unzip -oq "$TEST_DIR" -d "$new_test_dir" || $(print_error "Failed to unzip $TEST_DIR to $new_test_dir" "$LINENO")
357    case $filename in
358        "android-vts.zip" | "android-cts.zip")
359        new_test_dir+="/$(echo $filename | sed "s/.zip//g")"
360        ;;
361        *)
362        ;;
363    esac
364    TEST_DIR="$new_test_dir" # Update TEST_DIR to the unzipped directory
365fi
366
367print_info "Will run tests with test artifacts in $TEST_DIR" "$LINENO"
368
369if [ -f "${TEST_DIR}/tools/vts-tradefed" ]; then
370    TRADEFED="${TEST_DIR}/tools/vts-tradefed"
371    print_info "Will run tests with vts-tradefed from $TRADEFED" "$LINENO"
372    print_info "Many VTS tests need WIFI connection, please make sure WIFI is connected before you run the test." "$LINENO"
373    tf_cli="$TRADEFED run commandAndExit \
374    vts --skip-device-info --log-level-display info --log-file-path=$LOG_DIR \
375    $TEST_FILTERS -s $SERIAL_NUMBER"
376elif [ -f "${TEST_DIR}/tools/cts-tradefed" ]; then
377    TRADEFED="${TEST_DIR}/tools/cts-tradefed"
378    print_info "Will run tests with cts-tradefed from $TRADEFED" "$LINENO"
379    print_info "Many CTS tests need WIFI connection, please make sure WIFI is connected before you run the test." "$LINENO"
380    tf_cli="$TRADEFED run commandAndExit cts --skip-device-info \
381    --log-level-display info --log-file-path=$LOG_DIR \
382    $TEST_FILTERS -s $SERIAL_NUMBER"
383elif [ -f "${ANDROID_HOST_OUT}/bin/tradefed.sh" ] ; then
384    TRADEFED="${ANDROID_HOST_OUT}/bin/tradefed.sh"
385    print_info "Use the tradefed from the local built path $TRADEFED" "$LINENO"
386    tf_cli="$TRADEFED run commandAndExit template/local_min \
387    --log-level-display info --log-file-path=$LOG_DIR \
388    --template:map test=suite/test_mapping_suite  --tests-dir=$TEST_DIR\
389    $TEST_FILTERS -s $SERIAL_NUMBER"
390elif [ -f "$PLATFORM_TF_PREBUILT" ]; then
391    TRADEFED="JAVA_HOME=$PLATFORM_JDK_PATH PATH=$PLATFORM_JDK_PATH/bin:$PATH $PLATFORM_TF_PREBUILT"
392    print_info "Local Tradefed is not built yet. Use the prebuilt from $PLATFORM_TF_PREBUILT" "$LINENO"
393    tf_cli="$TRADEFED run commandAndExit template/local_min \
394    --log-level-display info --log-file-path=$LOG_DIR \
395    --template:map test=suite/test_mapping_suite  --tests-dir=$TEST_DIR\
396    $TEST_FILTERS -s $SERIAL_NUMBER"
397elif [ -f "$KERNEL_TF_PREBUILT" ]; then
398    TRADEFED="JAVA_HOME=$JDK_PATH PATH=$JDK_PATH/bin:$PATH $KERNEL_TF_PREBUILT"
399    print_info "Use the tradefed prebuilt from $KERNEL_TF_PREBUILT" "$LINENO"
400    tf_cli="$TRADEFED run commandAndExit template/local_min \
401    --log-level-display info --log-file-path=$LOG_DIR \
402    --template:map test=suite/test_mapping_suite  --tests-dir=$TEST_DIR\
403    $TEST_FILTERS -s $SERIAL_NUMBER"
404# No Tradefed found
405else
406    print_error "Can not find Tradefed binary. Please use flag -tf to specify the binary path." "$LINENO"
407fi
408
409# Construct the TradeFed command
410
411# Add GCOV options if enabled
412if $GCOV; then
413    tf_cli+=$TRADEFED_GCOV_OPTIONS
414fi
415
416# Evaluate the TradeFed command with extra arguments
417print_info "Run test with: $tf_cli" "${TEST_ARGS[*]}" "$LINENO"
418eval "$tf_cli" "${TEST_ARGS[*]}"
419exit_code=$?
420
421if $GCOV; then
422    create_tracefile_cli="$CREATE_TRACEFILE_SCRIPT -t $LOG_DIR -o $LOG_DIR/cov.info"
423    if [ -f $KERNEL_TF_PREBUILT ]; then
424        print_info "Create tracefile with $create_tracefile_cli" "$LINENO"
425        $create_tracefile_cli && \
426        print_info "Created tracefile at $LOG_DIR/cov.info" "$LINENO"
427    else
428        print_info "Skip creating tracefile. If you have full kernel source, run the following command:" "$LINENO"
429        print_info "$create_tracefile_cli" "$LINENO"
430    fi
431fi
432
433cd $OLD_PWD
434exit $exit_code
435