xref: /aosp_15_r20/build/make/tools/envsetup/run_envsetup_tests (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*9e94795aSAndroid Build Coastguard Worker
3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2024 The Android Open Source Project
4*9e94795aSAndroid Build Coastguard Worker#
5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*9e94795aSAndroid Build Coastguard Worker#
9*9e94795aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*9e94795aSAndroid Build Coastguard Worker#
11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*9e94795aSAndroid Build Coastguard Worker# limitations under the License.
16*9e94795aSAndroid Build Coastguard Worker
17*9e94795aSAndroid Build Coastguard Workerimport os
18*9e94795aSAndroid Build Coastguard Workerimport pathlib
19*9e94795aSAndroid Build Coastguard Workerimport subprocess
20*9e94795aSAndroid Build Coastguard Workerimport sys
21*9e94795aSAndroid Build Coastguard Worker
22*9e94795aSAndroid Build Coastguard WorkerSOURCE_ENVSETUP="source build/make/envsetup.sh && "
23*9e94795aSAndroid Build Coastguard Worker
24*9e94795aSAndroid Build Coastguard Workerdef update_display():
25*9e94795aSAndroid Build Coastguard Worker    sys.stderr.write("passed\n")
26*9e94795aSAndroid Build Coastguard Worker
27*9e94795aSAndroid Build Coastguard Workerdef go_to_root():
28*9e94795aSAndroid Build Coastguard Worker    while True:
29*9e94795aSAndroid Build Coastguard Worker        if os.path.exists("build/make/envsetup.sh"):
30*9e94795aSAndroid Build Coastguard Worker            return
31*9e94795aSAndroid Build Coastguard Worker        if os.getcwd() == "/":
32*9e94795aSAndroid Build Coastguard Worker            sys.stderr.write("Can't find root of the source tree\n");
33*9e94795aSAndroid Build Coastguard Worker            print("\nFAILED")
34*9e94795aSAndroid Build Coastguard Worker            sys.exit(1)
35*9e94795aSAndroid Build Coastguard Worker        os.chdir("..")
36*9e94795aSAndroid Build Coastguard Worker
37*9e94795aSAndroid Build Coastguard Workerdef is_test(name, thing):
38*9e94795aSAndroid Build Coastguard Worker    if not callable(thing):
39*9e94795aSAndroid Build Coastguard Worker        return False
40*9e94795aSAndroid Build Coastguard Worker    if name == "test":
41*9e94795aSAndroid Build Coastguard Worker        return False
42*9e94795aSAndroid Build Coastguard Worker    return name.startswith("test")
43*9e94795aSAndroid Build Coastguard Worker
44*9e94795aSAndroid Build Coastguard Worker
45*9e94795aSAndroid Build Coastguard Workerdef test(shell, command, expected_return, expected_stdout, expected_stderr, expected_env):
46*9e94795aSAndroid Build Coastguard Worker    command += "; _rc=$?"
47*9e94795aSAndroid Build Coastguard Worker    for env in expected_env.keys():
48*9e94795aSAndroid Build Coastguard Worker        command += f"; echo ENV: {env}=\\\"${env}\\\""
49*9e94795aSAndroid Build Coastguard Worker    command += "; exit $_rc"
50*9e94795aSAndroid Build Coastguard Worker
51*9e94795aSAndroid Build Coastguard Worker    cmd = [shell, "-c", command]
52*9e94795aSAndroid Build Coastguard Worker    result = subprocess.run(cmd, capture_output=True, text=True)
53*9e94795aSAndroid Build Coastguard Worker
54*9e94795aSAndroid Build Coastguard Worker    status = True
55*9e94795aSAndroid Build Coastguard Worker
56*9e94795aSAndroid Build Coastguard Worker    if result.returncode != expected_return:
57*9e94795aSAndroid Build Coastguard Worker        print()
58*9e94795aSAndroid Build Coastguard Worker        print(f"Expected return code: {expected_return}")
59*9e94795aSAndroid Build Coastguard Worker        print(f"Actual return code:   {result.returncode}")
60*9e94795aSAndroid Build Coastguard Worker        status = False
61*9e94795aSAndroid Build Coastguard Worker
62*9e94795aSAndroid Build Coastguard Worker    printed_stdout = False
63*9e94795aSAndroid Build Coastguard Worker    if expected_stdout and expected_stdout not in result.stdout:
64*9e94795aSAndroid Build Coastguard Worker        print()
65*9e94795aSAndroid Build Coastguard Worker        print(f"Expected stdout to contain:\n{expected_stdout}")
66*9e94795aSAndroid Build Coastguard Worker        print(f"\nActual stdout:\n{result.stdout}")
67*9e94795aSAndroid Build Coastguard Worker        printed_stdout = True
68*9e94795aSAndroid Build Coastguard Worker        status = False
69*9e94795aSAndroid Build Coastguard Worker
70*9e94795aSAndroid Build Coastguard Worker    if expected_stderr and expected_stderr not in result.stderr:
71*9e94795aSAndroid Build Coastguard Worker        print()
72*9e94795aSAndroid Build Coastguard Worker        print(f"Expected stderr to contain:\n{expected_stderr}")
73*9e94795aSAndroid Build Coastguard Worker        print(f"\nActual stderr:\n{result.stderr}")
74*9e94795aSAndroid Build Coastguard Worker        status = False
75*9e94795aSAndroid Build Coastguard Worker
76*9e94795aSAndroid Build Coastguard Worker    env_failure = False
77*9e94795aSAndroid Build Coastguard Worker    for k, v in expected_env.items():
78*9e94795aSAndroid Build Coastguard Worker        if f"{k}=\"{v}\"" not in result.stdout:
79*9e94795aSAndroid Build Coastguard Worker            print()
80*9e94795aSAndroid Build Coastguard Worker            print(f"Expected environment variable {k} to be: {v} --- {k}=\"{v}\"")
81*9e94795aSAndroid Build Coastguard Worker            env_failure = True
82*9e94795aSAndroid Build Coastguard Worker            status = False
83*9e94795aSAndroid Build Coastguard Worker
84*9e94795aSAndroid Build Coastguard Worker    if env_failure and not printed_stdout:
85*9e94795aSAndroid Build Coastguard Worker        print()
86*9e94795aSAndroid Build Coastguard Worker        print("See stdout:")
87*9e94795aSAndroid Build Coastguard Worker        print(result.stdout)
88*9e94795aSAndroid Build Coastguard Worker
89*9e94795aSAndroid Build Coastguard Worker    if not status:
90*9e94795aSAndroid Build Coastguard Worker        print()
91*9e94795aSAndroid Build Coastguard Worker        print("Command to reproduce:")
92*9e94795aSAndroid Build Coastguard Worker        print(command)
93*9e94795aSAndroid Build Coastguard Worker        print()
94*9e94795aSAndroid Build Coastguard Worker
95*9e94795aSAndroid Build Coastguard Worker    return status
96*9e94795aSAndroid Build Coastguard Worker
97*9e94795aSAndroid Build Coastguard WorkerNO_LUNCH = {
98*9e94795aSAndroid Build Coastguard Worker    "TARGET_PRODUCT": "",
99*9e94795aSAndroid Build Coastguard Worker    "TARGET_RELEASE": "",
100*9e94795aSAndroid Build Coastguard Worker    "TARGET_BUILD_VARIANT": "",
101*9e94795aSAndroid Build Coastguard Worker}
102*9e94795aSAndroid Build Coastguard Worker
103*9e94795aSAndroid Build Coastguard Workerdef test_invalid_lunch_target(shell):
104*9e94795aSAndroid Build Coastguard Worker    return test(shell, SOURCE_ENVSETUP + "lunch invalid-trunk_staging-eng",
105*9e94795aSAndroid Build Coastguard Worker         expected_return=1, expected_stdout=None,
106*9e94795aSAndroid Build Coastguard Worker         expected_stderr="Cannot locate config makefile for product",
107*9e94795aSAndroid Build Coastguard Worker         expected_env=NO_LUNCH)
108*9e94795aSAndroid Build Coastguard Worker
109*9e94795aSAndroid Build Coastguard Worker
110*9e94795aSAndroid Build Coastguard Workerdef test_aosp_arm(shell):
111*9e94795aSAndroid Build Coastguard Worker    return test(shell, SOURCE_ENVSETUP + "lunch aosp_arm-trunk_staging-eng",
112*9e94795aSAndroid Build Coastguard Worker         expected_return=0, expected_stdout=None, expected_stderr=None,
113*9e94795aSAndroid Build Coastguard Worker         expected_env={
114*9e94795aSAndroid Build Coastguard Worker            "TARGET_PRODUCT": "aosp_arm",
115*9e94795aSAndroid Build Coastguard Worker            "TARGET_RELEASE": "trunk_staging",
116*9e94795aSAndroid Build Coastguard Worker            "TARGET_BUILD_VARIANT": "eng",
117*9e94795aSAndroid Build Coastguard Worker        })
118*9e94795aSAndroid Build Coastguard Worker
119*9e94795aSAndroid Build Coastguard Worker
120*9e94795aSAndroid Build Coastguard Workerdef test_lunch2_empty(shell):
121*9e94795aSAndroid Build Coastguard Worker    return test(shell, SOURCE_ENVSETUP + "lunch2",
122*9e94795aSAndroid Build Coastguard Worker         expected_return=1, expected_stdout=None,
123*9e94795aSAndroid Build Coastguard Worker         expected_stderr="No target specified. See lunch --help",
124*9e94795aSAndroid Build Coastguard Worker         expected_env=NO_LUNCH)
125*9e94795aSAndroid Build Coastguard Worker
126*9e94795aSAndroid Build Coastguard Workerdef test_lunch2_four_params(shell):
127*9e94795aSAndroid Build Coastguard Worker    return test(shell, SOURCE_ENVSETUP + "lunch2 a b c d",
128*9e94795aSAndroid Build Coastguard Worker         expected_return=1, expected_stdout=None,
129*9e94795aSAndroid Build Coastguard Worker         expected_stderr="Too many parameters given. See lunch --help",
130*9e94795aSAndroid Build Coastguard Worker         expected_env=NO_LUNCH)
131*9e94795aSAndroid Build Coastguard Worker
132*9e94795aSAndroid Build Coastguard Workerdef test_lunch2_aosp_arm(shell):
133*9e94795aSAndroid Build Coastguard Worker    return test(shell, SOURCE_ENVSETUP + "lunch2 aosp_arm",
134*9e94795aSAndroid Build Coastguard Worker         expected_return=0, expected_stdout="=========", expected_stderr=None,
135*9e94795aSAndroid Build Coastguard Worker         expected_env={
136*9e94795aSAndroid Build Coastguard Worker            "TARGET_PRODUCT": "aosp_arm",
137*9e94795aSAndroid Build Coastguard Worker            "TARGET_RELEASE": "trunk_staging",
138*9e94795aSAndroid Build Coastguard Worker            "TARGET_BUILD_VARIANT": "eng",
139*9e94795aSAndroid Build Coastguard Worker        })
140*9e94795aSAndroid Build Coastguard Worker
141*9e94795aSAndroid Build Coastguard Workerdef test_lunch2_aosp_arm_trunk_staging(shell):
142*9e94795aSAndroid Build Coastguard Worker    # Somewhat unfortunate because trunk_staging is the only config in
143*9e94795aSAndroid Build Coastguard Worker    # aosp so we can't really test that this isn't just getting the default
144*9e94795aSAndroid Build Coastguard Worker    return test(shell, SOURCE_ENVSETUP + "lunch2 aosp_arm trunk_staging",
145*9e94795aSAndroid Build Coastguard Worker         expected_return=0, expected_stdout="=========", expected_stderr=None,
146*9e94795aSAndroid Build Coastguard Worker         expected_env={
147*9e94795aSAndroid Build Coastguard Worker            "TARGET_PRODUCT": "aosp_arm",
148*9e94795aSAndroid Build Coastguard Worker            "TARGET_RELEASE": "trunk_staging",
149*9e94795aSAndroid Build Coastguard Worker            "TARGET_BUILD_VARIANT": "eng",
150*9e94795aSAndroid Build Coastguard Worker        })
151*9e94795aSAndroid Build Coastguard Worker
152*9e94795aSAndroid Build Coastguard Workerdef test_lunch2_aosp_arm_trunk_staging_userdebug(shell):
153*9e94795aSAndroid Build Coastguard Worker    return test(shell, SOURCE_ENVSETUP + "lunch2 aosp_arm trunk_staging userdebug",
154*9e94795aSAndroid Build Coastguard Worker         expected_return=0, expected_stdout="=========", expected_stderr=None,
155*9e94795aSAndroid Build Coastguard Worker         expected_env={
156*9e94795aSAndroid Build Coastguard Worker            "TARGET_PRODUCT": "aosp_arm",
157*9e94795aSAndroid Build Coastguard Worker            "TARGET_RELEASE": "trunk_staging",
158*9e94795aSAndroid Build Coastguard Worker            "TARGET_BUILD_VARIANT": "userdebug",
159*9e94795aSAndroid Build Coastguard Worker        })
160*9e94795aSAndroid Build Coastguard Worker
161*9e94795aSAndroid Build Coastguard Workerdef test_list_products(shell):
162*9e94795aSAndroid Build Coastguard Worker    return test(shell, "build/soong/bin/list_products",
163*9e94795aSAndroid Build Coastguard Worker         expected_return=0, expected_stdout="aosp_arm", expected_stderr=None,
164*9e94795aSAndroid Build Coastguard Worker         expected_env=NO_LUNCH)
165*9e94795aSAndroid Build Coastguard Worker
166*9e94795aSAndroid Build Coastguard Workerdef test_list_releases_param(shell):
167*9e94795aSAndroid Build Coastguard Worker    return test(shell, "build/soong/bin/list_releases aosp_arm",
168*9e94795aSAndroid Build Coastguard Worker         expected_return=0, expected_stdout="trunk_staging", expected_stderr=None,
169*9e94795aSAndroid Build Coastguard Worker         expected_env=NO_LUNCH)
170*9e94795aSAndroid Build Coastguard Worker
171*9e94795aSAndroid Build Coastguard Workerdef test_list_releases_env(shell):
172*9e94795aSAndroid Build Coastguard Worker    return test(shell, "TARGET_PRODUCT=aosp_arm build/soong/bin/list_releases",
173*9e94795aSAndroid Build Coastguard Worker         expected_return=0, expected_stdout="trunk_staging", expected_stderr=None,
174*9e94795aSAndroid Build Coastguard Worker         expected_env=NO_LUNCH)
175*9e94795aSAndroid Build Coastguard Worker
176*9e94795aSAndroid Build Coastguard Workerdef test_list_releases_no_product(shell):
177*9e94795aSAndroid Build Coastguard Worker    return test(shell, "build/soong/bin/list_releases",
178*9e94795aSAndroid Build Coastguard Worker         expected_return=1, expected_stdout=None, expected_stderr=None,
179*9e94795aSAndroid Build Coastguard Worker         expected_env=NO_LUNCH)
180*9e94795aSAndroid Build Coastguard Worker
181*9e94795aSAndroid Build Coastguard Workerdef test_list_variants(shell):
182*9e94795aSAndroid Build Coastguard Worker    return test(shell, "build/soong/bin/list_variants",
183*9e94795aSAndroid Build Coastguard Worker         expected_return=0, expected_stdout="userdebug", expected_stderr=None,
184*9e94795aSAndroid Build Coastguard Worker         expected_env=NO_LUNCH)
185*9e94795aSAndroid Build Coastguard Worker
186*9e94795aSAndroid Build Coastguard Worker
187*9e94795aSAndroid Build Coastguard Workerdef test_get_build_var_in_path(shell):
188*9e94795aSAndroid Build Coastguard Worker    return test(shell, SOURCE_ENVSETUP + "which get_build_var ",
189*9e94795aSAndroid Build Coastguard Worker         expected_return=0, expected_stdout="soong/bin", expected_stderr=None,
190*9e94795aSAndroid Build Coastguard Worker         expected_env=NO_LUNCH)
191*9e94795aSAndroid Build Coastguard Worker
192*9e94795aSAndroid Build Coastguard Worker
193*9e94795aSAndroid Build Coastguard Worker
194*9e94795aSAndroid Build Coastguard WorkerTESTS=sorted([(name, thing) for name, thing in locals().items() if is_test(name, thing)])
195*9e94795aSAndroid Build Coastguard Worker
196*9e94795aSAndroid Build Coastguard Workerdef main():
197*9e94795aSAndroid Build Coastguard Worker    if any([x.endswith("/soong/bin") for x in os.getenv("PATH").split(":")]):
198*9e94795aSAndroid Build Coastguard Worker        sys.stderr.write("run_envsetup_tests must be run in a shell that has not sourced"
199*9e94795aSAndroid Build Coastguard Worker                + " envsetup.sh\n\nFAILED\n")
200*9e94795aSAndroid Build Coastguard Worker        return 1
201*9e94795aSAndroid Build Coastguard Worker
202*9e94795aSAndroid Build Coastguard Worker    go_to_root()
203*9e94795aSAndroid Build Coastguard Worker
204*9e94795aSAndroid Build Coastguard Worker    tests = TESTS
205*9e94795aSAndroid Build Coastguard Worker    if len(sys.argv) > 1:
206*9e94795aSAndroid Build Coastguard Worker        tests = [(name, func) for name, func in tests if name in sys.argv]
207*9e94795aSAndroid Build Coastguard Worker
208*9e94795aSAndroid Build Coastguard Worker    shells = ["/usr/bin/bash", "/usr/bin/zsh"]
209*9e94795aSAndroid Build Coastguard Worker    total_count = len(tests) * len(shells)
210*9e94795aSAndroid Build Coastguard Worker    index = 1
211*9e94795aSAndroid Build Coastguard Worker    failed_tests = 0
212*9e94795aSAndroid Build Coastguard Worker
213*9e94795aSAndroid Build Coastguard Worker    for name, func in tests:
214*9e94795aSAndroid Build Coastguard Worker        for shell in shells:
215*9e94795aSAndroid Build Coastguard Worker            sys.stdout.write(f"\33[2K\r{index} of {total_count}: {name} in {shell}")
216*9e94795aSAndroid Build Coastguard Worker            passed = func(shell)
217*9e94795aSAndroid Build Coastguard Worker            if not passed:
218*9e94795aSAndroid Build Coastguard Worker                failed_tests += 1
219*9e94795aSAndroid Build Coastguard Worker            index += 1
220*9e94795aSAndroid Build Coastguard Worker
221*9e94795aSAndroid Build Coastguard Worker    if failed_tests > 0:
222*9e94795aSAndroid Build Coastguard Worker        print(f"\n\nFAILED: {failed_tests} of {total_count}")
223*9e94795aSAndroid Build Coastguard Worker        return 1
224*9e94795aSAndroid Build Coastguard Worker    else:
225*9e94795aSAndroid Build Coastguard Worker        print("\n\nSUCCESS")
226*9e94795aSAndroid Build Coastguard Worker        return 0
227*9e94795aSAndroid Build Coastguard Worker
228*9e94795aSAndroid Build Coastguard Workerif __name__ == "__main__":
229*9e94795aSAndroid Build Coastguard Worker    sys.exit(main())
230