blob: 5977448d07220270da3c617e928164a158f7f189 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (C) 2024 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.
import os
import pathlib
import subprocess
import sys
SOURCE_ENVSETUP="source build/make/envsetup.sh && "
def update_display():
sys.stderr.write("passed\n")
def go_to_root():
while True:
if os.path.exists("build/make/envsetup.sh"):
return
if os.getcwd() == "/":
sys.stderr.write("Can't find root of the source tree\n");
print("\nFAILED")
sys.exit(1)
os.chdir("..")
def is_test(name, thing):
if not callable(thing):
return False
if name == "test":
return False
return name.startswith("test")
def test(shell, command, expected_return, expected_stdout, expected_stderr, expected_env):
command += "; _rc=$?"
for env in expected_env.keys():
command += f"; echo ENV: {env}=\\\"${env}\\\""
command += "; exit $_rc"
cmd = [shell, "-c", command]
result = subprocess.run(cmd, capture_output=True, text=True)
status = True
if result.returncode != expected_return:
print()
print(f"Expected return code: {expected_return}")
print(f"Actual return code: {result.returncode}")
status = False
printed_stdout = False
if expected_stdout and expected_stdout not in result.stdout:
print()
print(f"Expected stdout to contain:\n{expected_stdout}")
print(f"\nActual stdout:\n{result.stdout}")
printed_stdout = True
status = False
if expected_stderr and expected_stderr not in result.stderr:
print()
print(f"Expected stderr to contain:\n{expected_stderr}")
print(f"\nActual stderr:\n{result.stderr}")
status = False
env_failure = False
for k, v in expected_env.items():
if f"{k}=\"{v}\"" not in result.stdout:
print()
print(f"Expected environment variable {k} to be: {v} --- {k}=\"{v}\"")
env_failure = True
status = False
if env_failure and not printed_stdout:
print()
print("See stdout:")
print(result.stdout)
if not status:
print()
print("Command to reproduce:")
print(command)
print()
return status
NO_LUNCH = {
"TARGET_PRODUCT": "",
"TARGET_RELEASE": "",
"TARGET_BUILD_VARIANT": "",
}
def test_invalid_lunch_target(shell):
return test(shell, SOURCE_ENVSETUP + "lunch invalid-trunk_staging-eng",
expected_return=1, expected_stdout=None,
expected_stderr="Cannot locate config makefile for product",
expected_env=NO_LUNCH)
def test_aosp_arm(shell):
return test(shell, SOURCE_ENVSETUP + "lunch aosp_arm-trunk_staging-eng",
expected_return=0, expected_stdout=None, expected_stderr=None,
expected_env={
"TARGET_PRODUCT": "aosp_arm",
"TARGET_RELEASE": "trunk_staging",
"TARGET_BUILD_VARIANT": "eng",
})
def test_lunch2_empty(shell):
return test(shell, SOURCE_ENVSETUP + "lunch2",
expected_return=1, expected_stdout=None,
expected_stderr="No target specified. See lunch --help",
expected_env=NO_LUNCH)
def test_lunch2_four_params(shell):
return test(shell, SOURCE_ENVSETUP + "lunch2 a b c d",
expected_return=1, expected_stdout=None,
expected_stderr="Too many parameters given. See lunch --help",
expected_env=NO_LUNCH)
def test_lunch2_aosp_arm(shell):
return test(shell, SOURCE_ENVSETUP + "lunch2 aosp_arm",
expected_return=0, expected_stdout="=========", expected_stderr=None,
expected_env={
"TARGET_PRODUCT": "aosp_arm",
"TARGET_RELEASE": "trunk_staging",
"TARGET_BUILD_VARIANT": "eng",
})
def test_lunch2_aosp_arm_trunk_staging(shell):
# Somewhat unfortunate because trunk_staging is the only config in
# aosp so we can't really test that this isn't just getting the default
return test(shell, SOURCE_ENVSETUP + "lunch2 aosp_arm trunk_staging",
expected_return=0, expected_stdout="=========", expected_stderr=None,
expected_env={
"TARGET_PRODUCT": "aosp_arm",
"TARGET_RELEASE": "trunk_staging",
"TARGET_BUILD_VARIANT": "eng",
})
def test_lunch2_aosp_arm_trunk_staging_userdebug(shell):
return test(shell, SOURCE_ENVSETUP + "lunch2 aosp_arm trunk_staging userdebug",
expected_return=0, expected_stdout="=========", expected_stderr=None,
expected_env={
"TARGET_PRODUCT": "aosp_arm",
"TARGET_RELEASE": "trunk_staging",
"TARGET_BUILD_VARIANT": "userdebug",
})
def test_list_products(shell):
return test(shell, "build/soong/bin/list_products",
expected_return=0, expected_stdout="aosp_arm", expected_stderr=None,
expected_env=NO_LUNCH)
def test_list_releases_param(shell):
return test(shell, "build/soong/bin/list_releases aosp_arm",
expected_return=0, expected_stdout="trunk_staging", expected_stderr=None,
expected_env=NO_LUNCH)
def test_list_releases_env(shell):
return test(shell, "TARGET_PRODUCT=aosp_arm build/soong/bin/list_releases",
expected_return=0, expected_stdout="trunk_staging", expected_stderr=None,
expected_env=NO_LUNCH)
def test_list_releases_no_product(shell):
return test(shell, "build/soong/bin/list_releases",
expected_return=1, expected_stdout=None, expected_stderr=None,
expected_env=NO_LUNCH)
def test_list_variants(shell):
return test(shell, "build/soong/bin/list_variants",
expected_return=0, expected_stdout="userdebug", expected_stderr=None,
expected_env=NO_LUNCH)
def test_get_build_var_in_path(shell):
return test(shell, SOURCE_ENVSETUP + "which get_build_var ",
expected_return=0, expected_stdout="soong/bin", expected_stderr=None,
expected_env=NO_LUNCH)
TESTS=sorted([(name, thing) for name, thing in locals().items() if is_test(name, thing)])
def main():
if any([x.endswith("/soong/bin") for x in os.getenv("PATH").split(":")]):
sys.stderr.write("run_envsetup_tests must be run in a shell that has not sourced"
+ " envsetup.sh\n\nFAILED\n")
return 1
go_to_root()
tests = TESTS
if len(sys.argv) > 1:
tests = [(name, func) for name, func in tests if name in sys.argv]
shells = ["/usr/bin/bash", "/usr/bin/zsh"]
total_count = len(tests) * len(shells)
index = 1
failed_tests = 0
for name, func in tests:
for shell in shells:
sys.stdout.write(f"\33[2K\r{index} of {total_count}: {name} in {shell}")
passed = func(shell)
if not passed:
failed_tests += 1
index += 1
if failed_tests > 0:
print(f"\n\nFAILED: {failed_tests} of {total_count}")
return 1
else:
print("\n\nSUCCESS")
return 0
if __name__ == "__main__":
sys.exit(main())