xref: /aosp_15_r20/tools/asuite/atest/atest_completion.sh (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
1*c2e18aaaSAndroid Build Coastguard Worker# Copyright 2018, The Android Open Source Project
2*c2e18aaaSAndroid Build Coastguard Worker#
3*c2e18aaaSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*c2e18aaaSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*c2e18aaaSAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*c2e18aaaSAndroid Build Coastguard Worker#
7*c2e18aaaSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*c2e18aaaSAndroid Build Coastguard Worker#
9*c2e18aaaSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*c2e18aaaSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*c2e18aaaSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*c2e18aaaSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*c2e18aaaSAndroid Build Coastguard Worker# limitations under the License.
14*c2e18aaaSAndroid Build Coastguard Worker
15*c2e18aaaSAndroid Build Coastguard Worker# This function returns devices recognised by adb.
16*c2e18aaaSAndroid Build Coastguard Worker_fetch_adb_devices() {
17*c2e18aaaSAndroid Build Coastguard Worker    while read dev; do echo $dev | awk '{print $1}'; done < <(adb devices | egrep -v "^List|^$"||true)
18*c2e18aaaSAndroid Build Coastguard Worker}
19*c2e18aaaSAndroid Build Coastguard Worker
20*c2e18aaaSAndroid Build Coastguard Worker# This function returns all paths contain TEST_MAPPING.
21*c2e18aaaSAndroid Build Coastguard Worker_fetch_test_mapping_files() {
22*c2e18aaaSAndroid Build Coastguard Worker    [[ -z $ANDROID_BUILD_TOP ]] && return 0
23*c2e18aaaSAndroid Build Coastguard Worker    find -maxdepth 5 -type f -name TEST_MAPPING |sed 's/^.\///g'| xargs dirname 2>/dev/null
24*c2e18aaaSAndroid Build Coastguard Worker}
25*c2e18aaaSAndroid Build Coastguard Worker
26*c2e18aaaSAndroid Build Coastguard Workerfunction _pip_install() {
27*c2e18aaaSAndroid Build Coastguard Worker    _deb_installer python3-venv python3-pip || return 1
28*c2e18aaaSAndroid Build Coastguard Worker    _activate_venv || return 1
29*c2e18aaaSAndroid Build Coastguard Worker    requirements=(venv pyinstrument snakeviz)
30*c2e18aaaSAndroid Build Coastguard Worker    for mod in "${requirements[@]}"; do
31*c2e18aaaSAndroid Build Coastguard Worker        if ! _has_py_module $mod; then
32*c2e18aaaSAndroid Build Coastguard Worker            echo "Installing $mod..."
33*c2e18aaaSAndroid Build Coastguard Worker            pip3 install $mod >/dev/null
34*c2e18aaaSAndroid Build Coastguard Worker            if [ "$?" -ne 0 ]; then
35*c2e18aaaSAndroid Build Coastguard Worker                echo "pip3 install $mod failure."
36*c2e18aaaSAndroid Build Coastguard Worker                return 1
37*c2e18aaaSAndroid Build Coastguard Worker            fi
38*c2e18aaaSAndroid Build Coastguard Worker        fi
39*c2e18aaaSAndroid Build Coastguard Worker    done
40*c2e18aaaSAndroid Build Coastguard Worker}
41*c2e18aaaSAndroid Build Coastguard Worker
42*c2e18aaaSAndroid Build Coastguard Workerfunction _has_py_module() {
43*c2e18aaaSAndroid Build Coastguard Worker    [[ -z "$1" ]] && { echo "requires a module name."; return 1; }
44*c2e18aaaSAndroid Build Coastguard Worker
45*c2e18aaaSAndroid Build Coastguard Worker    cmd="python3 -c '
46*c2e18aaaSAndroid Build Coastguard Workerimport importlib.util as ut
47*c2e18aaaSAndroid Build Coastguard Workerprint(0 if ut.find_spec(\"$1\") else 1)
48*c2e18aaaSAndroid Build Coastguard Worker'"
49*c2e18aaaSAndroid Build Coastguard Worker    return $(eval "$cmd")
50*c2e18aaaSAndroid Build Coastguard Worker}
51*c2e18aaaSAndroid Build Coastguard Worker
52*c2e18aaaSAndroid Build Coastguard Workerfunction _deb_installer() {
53*c2e18aaaSAndroid Build Coastguard Worker    [[ -z "$@" ]] && { echo "requires a package name."; return 1; }
54*c2e18aaaSAndroid Build Coastguard Worker
55*c2e18aaaSAndroid Build Coastguard Worker    declare -a missing_pkgs
56*c2e18aaaSAndroid Build Coastguard Worker    for pkg in "$@"; do
57*c2e18aaaSAndroid Build Coastguard Worker        if ! $(dpkg -l $pkg | egrep -q '^ii'); then
58*c2e18aaaSAndroid Build Coastguard Worker            missing_pkgs+=($pkg)
59*c2e18aaaSAndroid Build Coastguard Worker        fi
60*c2e18aaaSAndroid Build Coastguard Worker    done
61*c2e18aaaSAndroid Build Coastguard Worker
62*c2e18aaaSAndroid Build Coastguard Worker    if [ ${#missing_pkgs[@]} -gt 0 ]; then
63*c2e18aaaSAndroid Build Coastguard Worker        echo -n "$(tput setaf 3)${missing_pkgs[@]}$(tput sgr0) are required. "
64*c2e18aaaSAndroid Build Coastguard Worker        read -p "Do you want to procees? [N/y] " answer
65*c2e18aaaSAndroid Build Coastguard Worker        case "$answer" in
66*c2e18aaaSAndroid Build Coastguard Worker            [yY])
67*c2e18aaaSAndroid Build Coastguard Worker                sudo apt install "${missing_pkgs[@]}" -y
68*c2e18aaaSAndroid Build Coastguard Worker                ;;
69*c2e18aaaSAndroid Build Coastguard Worker            *)
70*c2e18aaaSAndroid Build Coastguard Worker                echo "No action taken. Exiting."; return 1
71*c2e18aaaSAndroid Build Coastguard Worker                ;;
72*c2e18aaaSAndroid Build Coastguard Worker        esac
73*c2e18aaaSAndroid Build Coastguard Worker    fi
74*c2e18aaaSAndroid Build Coastguard Worker}
75*c2e18aaaSAndroid Build Coastguard Worker
76*c2e18aaaSAndroid Build Coastguard Workerfunction _activate_venv() {
77*c2e18aaaSAndroid Build Coastguard Worker    local VENV="$ANDROID_HOST_OUT/.atest_venv"
78*c2e18aaaSAndroid Build Coastguard Worker    [[ ! -d "$VENV" ]] && python3 -m venv "$VENV"
79*c2e18aaaSAndroid Build Coastguard Worker    source "$VENV/bin/activate" || {
80*c2e18aaaSAndroid Build Coastguard Worker        echo unable to activate venv.
81*c2e18aaaSAndroid Build Coastguard Worker        deactivate
82*c2e18aaaSAndroid Build Coastguard Worker        return 1
83*c2e18aaaSAndroid Build Coastguard Worker    }
84*c2e18aaaSAndroid Build Coastguard Worker}
85*c2e18aaaSAndroid Build Coastguard Worker
86*c2e18aaaSAndroid Build Coastguard Workerfunction _atest_profile_cli() {
87*c2e18aaaSAndroid Build Coastguard Worker    echo "_atest_profile_cli is deprecated. Use _atest_pyinstrument instead."
88*c2e18aaaSAndroid Build Coastguard Worker    return 1
89*c2e18aaaSAndroid Build Coastguard Worker}
90*c2e18aaaSAndroid Build Coastguard Worker
91*c2e18aaaSAndroid Build Coastguard Workerfunction _atest_pyinstrument() {
92*c2e18aaaSAndroid Build Coastguard Worker    local T="$ANDROID_BUILD_TOP"
93*c2e18aaaSAndroid Build Coastguard Worker    profile="$HOME/.atest/$(date +'%FT%H-%M-%S').pyisession"
94*c2e18aaaSAndroid Build Coastguard Worker
95*c2e18aaaSAndroid Build Coastguard Worker    _pip_install || return 1
96*c2e18aaaSAndroid Build Coastguard Worker    m atest && python3 $T/tools/asuite/atest/profiler.py pyinstrument $profile\
97*c2e18aaaSAndroid Build Coastguard Worker        $ANDROID_SOONG_HOST_OUT/bin/atest-dev --no-metrics "$@"
98*c2e18aaaSAndroid Build Coastguard Worker    if [ "$?" -eq 0 ]; then
99*c2e18aaaSAndroid Build Coastguard Worker        pyinstrument -t --load $profile || deactivate
100*c2e18aaaSAndroid Build Coastguard Worker    fi
101*c2e18aaaSAndroid Build Coastguard Worker    deactivate
102*c2e18aaaSAndroid Build Coastguard Worker}
103*c2e18aaaSAndroid Build Coastguard Worker
104*c2e18aaaSAndroid Build Coastguard Workerfunction _atest_profile_web() {
105*c2e18aaaSAndroid Build Coastguard Worker    echo _atest_profile_web is deprecated. Use _atest_cprofile_snakeviz instead.
106*c2e18aaaSAndroid Build Coastguard Worker    return 1
107*c2e18aaaSAndroid Build Coastguard Worker}
108*c2e18aaaSAndroid Build Coastguard Worker
109*c2e18aaaSAndroid Build Coastguard Workerfunction _atest_cprofile_snakeviz() {
110*c2e18aaaSAndroid Build Coastguard Worker    local T="$ANDROID_BUILD_TOP"
111*c2e18aaaSAndroid Build Coastguard Worker    profile="$HOME/.atest/$(date +'%F_%H-%M-%S').pstats"
112*c2e18aaaSAndroid Build Coastguard Worker
113*c2e18aaaSAndroid Build Coastguard Worker    _pip_install || return 1
114*c2e18aaaSAndroid Build Coastguard Worker    m atest && python3 $T/tools/asuite/atest/profiler.py cProfile $profile \
115*c2e18aaaSAndroid Build Coastguard Worker        $ANDROID_SOONG_HOST_OUT/bin/atest-dev --no-metrics "$@"
116*c2e18aaaSAndroid Build Coastguard Worker    if [ "$?" -eq 0 ]; then
117*c2e18aaaSAndroid Build Coastguard Worker        echo "$(tput bold)Use Ctrl-C to stop.$(tput sgr0)"
118*c2e18aaaSAndroid Build Coastguard Worker        snakeviz $profile >/dev/null || deactivate
119*c2e18aaaSAndroid Build Coastguard Worker    fi
120*c2e18aaaSAndroid Build Coastguard Worker    deactivate
121*c2e18aaaSAndroid Build Coastguard Worker}
122*c2e18aaaSAndroid Build Coastguard Worker
123*c2e18aaaSAndroid Build Coastguard Worker# The main tab completion function.
124*c2e18aaaSAndroid Build Coastguard Worker_atest() {
125*c2e18aaaSAndroid Build Coastguard Worker    COMPREPLY=()
126*c2e18aaaSAndroid Build Coastguard Worker    local cmd=$(which $1)
127*c2e18aaaSAndroid Build Coastguard Worker    local cur="${COMP_WORDS[COMP_CWORD]}"
128*c2e18aaaSAndroid Build Coastguard Worker    local prev="${COMP_WORDS[COMP_CWORD-1]}"
129*c2e18aaaSAndroid Build Coastguard Worker    _get_comp_words_by_ref -n : cur prev || true
130*c2e18aaaSAndroid Build Coastguard Worker
131*c2e18aaaSAndroid Build Coastguard Worker    if [[ "$cmd" == *prebuilts/asuite/atest/linux-x86/atest ]]; then
132*c2e18aaaSAndroid Build Coastguard Worker        # prebuilts/asuite/atest/linux-x86/atest is shell script wrapper around
133*c2e18aaaSAndroid Build Coastguard Worker        # atest-py3, which is what we should actually use.
134*c2e18aaaSAndroid Build Coastguard Worker        cmd=$ANDROID_BUILD_TOP/prebuilts/asuite/atest/linux-x86/atest-py3
135*c2e18aaaSAndroid Build Coastguard Worker    fi
136*c2e18aaaSAndroid Build Coastguard Worker
137*c2e18aaaSAndroid Build Coastguard Worker    case "$cur" in
138*c2e18aaaSAndroid Build Coastguard Worker        -*)
139*c2e18aaaSAndroid Build Coastguard Worker            COMPREPLY=($(compgen -W "$(unzip -p $cmd atest/atest_flag_list_for_completion.txt)" -- $cur))
140*c2e18aaaSAndroid Build Coastguard Worker            ;;
141*c2e18aaaSAndroid Build Coastguard Worker        */*)
142*c2e18aaaSAndroid Build Coastguard Worker            ;;
143*c2e18aaaSAndroid Build Coastguard Worker        *)
144*c2e18aaaSAndroid Build Coastguard Worker            # Use grep instead of compgen -W because compgen -W is very slow. It takes
145*c2e18aaaSAndroid Build Coastguard Worker            # ~0.7 seconds for compgen to read the all_modules.txt file.
146*c2e18aaaSAndroid Build Coastguard Worker            # TODO(b/256228056) This fails if $cur has special characters in it
147*c2e18aaaSAndroid Build Coastguard Worker            COMPREPLY=($(ls | grep "^$cur"; grep "^$cur" $ANDROID_PRODUCT_OUT/all_modules.txt 2>/dev/null))
148*c2e18aaaSAndroid Build Coastguard Worker            ;;
149*c2e18aaaSAndroid Build Coastguard Worker    esac
150*c2e18aaaSAndroid Build Coastguard Worker
151*c2e18aaaSAndroid Build Coastguard Worker    case "$prev" in
152*c2e18aaaSAndroid Build Coastguard Worker        --iterations|--retry-any-failure|--rerun-until-failure)
153*c2e18aaaSAndroid Build Coastguard Worker            COMPREPLY=(10) ;;
154*c2e18aaaSAndroid Build Coastguard Worker        --list-modules|-L)
155*c2e18aaaSAndroid Build Coastguard Worker            # TODO: genetate the list automately when the API is available.
156*c2e18aaaSAndroid Build Coastguard Worker            COMPREPLY=($(compgen -W "cts vts" -- $cur)) ;;
157*c2e18aaaSAndroid Build Coastguard Worker        --serial|-s)
158*c2e18aaaSAndroid Build Coastguard Worker            local adb_devices="$(_fetch_adb_devices)"
159*c2e18aaaSAndroid Build Coastguard Worker            if [ -n "$adb_devices" ]; then
160*c2e18aaaSAndroid Build Coastguard Worker                COMPREPLY=($(compgen -W "$(_fetch_adb_devices)" -- $cur))
161*c2e18aaaSAndroid Build Coastguard Worker            else
162*c2e18aaaSAndroid Build Coastguard Worker                # Don't complete files/dirs when there'is no devices.
163*c2e18aaaSAndroid Build Coastguard Worker                compopt -o nospace
164*c2e18aaaSAndroid Build Coastguard Worker                COMPREPLY=("")
165*c2e18aaaSAndroid Build Coastguard Worker            fi ;;
166*c2e18aaaSAndroid Build Coastguard Worker        --test-mapping|-p)
167*c2e18aaaSAndroid Build Coastguard Worker            local mapping_files="$(_fetch_test_mapping_files)"
168*c2e18aaaSAndroid Build Coastguard Worker            if [ -n "$mapping_files" ]; then
169*c2e18aaaSAndroid Build Coastguard Worker                COMPREPLY=($(compgen -W "$mapping_files" -- $cur))
170*c2e18aaaSAndroid Build Coastguard Worker            else
171*c2e18aaaSAndroid Build Coastguard Worker                # Don't complete files/dirs when TEST_MAPPING wasn't found.
172*c2e18aaaSAndroid Build Coastguard Worker                compopt -o nospace
173*c2e18aaaSAndroid Build Coastguard Worker                COMPREPLY=("")
174*c2e18aaaSAndroid Build Coastguard Worker            fi ;;
175*c2e18aaaSAndroid Build Coastguard Worker    esac
176*c2e18aaaSAndroid Build Coastguard Worker    __ltrim_colon_completions "$cur" "$prev" || true
177*c2e18aaaSAndroid Build Coastguard Worker    return 0
178*c2e18aaaSAndroid Build Coastguard Worker}
179*c2e18aaaSAndroid Build Coastguard Worker
180*c2e18aaaSAndroid Build Coastguard Workerfunction _atest_main() {
181*c2e18aaaSAndroid Build Coastguard Worker    # Only use this in interactive mode.
182*c2e18aaaSAndroid Build Coastguard Worker    # Warning: below check must be "return", not "exit". "exit" won't break the
183*c2e18aaaSAndroid Build Coastguard Worker    # build in interactive shell(e.g VM), but will result in build breakage in
184*c2e18aaaSAndroid Build Coastguard Worker    # non-interactive shell(e.g docker container); therefore, using "return"
185*c2e18aaaSAndroid Build Coastguard Worker    # adapts both conditions.
186*c2e18aaaSAndroid Build Coastguard Worker    [[ ! $- =~ 'i' ]] && return 0
187*c2e18aaaSAndroid Build Coastguard Worker
188*c2e18aaaSAndroid Build Coastguard Worker    # Complete file/dir name first by using option "nosort".
189*c2e18aaaSAndroid Build Coastguard Worker    # BASH version <= 4.3 doesn't have nosort option.
190*c2e18aaaSAndroid Build Coastguard Worker    # Note that nosort has no effect for zsh.
191*c2e18aaaSAndroid Build Coastguard Worker    local _atest_comp_options="-o default -o nosort"
192*c2e18aaaSAndroid Build Coastguard Worker    local _atest_executables=(atest
193*c2e18aaaSAndroid Build Coastguard Worker                              atest-dev
194*c2e18aaaSAndroid Build Coastguard Worker                              atest-py3
195*c2e18aaaSAndroid Build Coastguard Worker                              _atest_pyinstrument
196*c2e18aaaSAndroid Build Coastguard Worker                              _atest_cprofile_snakeviz)
197*c2e18aaaSAndroid Build Coastguard Worker    for exec in "${_atest_executables[*]}"; do
198*c2e18aaaSAndroid Build Coastguard Worker        complete -F _atest $_atest_comp_options $exec 2>/dev/null || \
199*c2e18aaaSAndroid Build Coastguard Worker        complete -F _atest -o default $exec
200*c2e18aaaSAndroid Build Coastguard Worker    done
201*c2e18aaaSAndroid Build Coastguard Worker
202*c2e18aaaSAndroid Build Coastguard Worker    function atest-src() {
203*c2e18aaaSAndroid Build Coastguard Worker        echo "atest-src is deprecated, use m atest && atest-dev instead" >&2
204*c2e18aaaSAndroid Build Coastguard Worker        return 1
205*c2e18aaaSAndroid Build Coastguard Worker    }
206*c2e18aaaSAndroid Build Coastguard Worker
207*c2e18aaaSAndroid Build Coastguard Worker    # Use prebuilt python3 for atest-dev
208*c2e18aaaSAndroid Build Coastguard Worker    function atest-dev() {
209*c2e18aaaSAndroid Build Coastguard Worker        atest_dev="$ANDROID_SOONG_HOST_OUT/bin/atest-dev"
210*c2e18aaaSAndroid Build Coastguard Worker        if [ ! -f $atest_dev ]; then
211*c2e18aaaSAndroid Build Coastguard Worker            echo "Cannot find atest-dev. Run 'm atest' to generate one."
212*c2e18aaaSAndroid Build Coastguard Worker            return 1
213*c2e18aaaSAndroid Build Coastguard Worker        fi
214*c2e18aaaSAndroid Build Coastguard Worker        PREBUILT_TOOLS_DIR="$ANDROID_BUILD_TOP/prebuilts/build-tools/path/linux-x86"
215*c2e18aaaSAndroid Build Coastguard Worker        PATH=$PREBUILT_TOOLS_DIR:$PATH $atest_dev "$@"
216*c2e18aaaSAndroid Build Coastguard Worker    }
217*c2e18aaaSAndroid Build Coastguard Worker}
218*c2e18aaaSAndroid Build Coastguard Worker
219*c2e18aaaSAndroid Build Coastguard Worker_atest_main
220