| """Bootstrap tests |
| |
| Run these with `x test bootstrap`, or `python -m unittest src/bootstrap/bootstrap_test.py`.""" |
| |
| from __future__ import absolute_import, division, print_function |
| import os |
| import unittest |
| import tempfile |
| import hashlib |
| import sys |
| |
| from shutil import rmtree |
| |
| # Allow running this from the top-level directory. |
| bootstrap_dir = os.path.dirname(os.path.abspath(__file__)) |
| # For the import below, have Python search in src/bootstrap first. |
| sys.path.insert(0, bootstrap_dir) |
| import bootstrap # noqa: E402 |
| import configure # noqa: E402 |
| |
| def serialize_and_parse(configure_args, bootstrap_args=None): |
| from io import StringIO |
| |
| if bootstrap_args is None: |
| bootstrap_args = bootstrap.FakeArgs() |
| |
| section_order, sections, targets = configure.parse_args(configure_args) |
| buffer = StringIO() |
| configure.write_config_toml(buffer, section_order, targets, sections) |
| build = bootstrap.RustBuild(config_toml=buffer.getvalue(), args=bootstrap_args) |
| |
| try: |
| import tomllib |
| # Verify this is actually valid TOML. |
| tomllib.loads(build.config_toml) |
| except ImportError: |
| print("WARNING: skipping TOML validation, need at least python 3.11", file=sys.stderr) |
| return build |
| |
| |
| class VerifyTestCase(unittest.TestCase): |
| """Test Case for verify""" |
| def setUp(self): |
| self.container = tempfile.mkdtemp() |
| self.src = os.path.join(self.container, "src.txt") |
| self.bad_src = os.path.join(self.container, "bad.txt") |
| content = "Hello world" |
| |
| self.expected = hashlib.sha256(content.encode("utf-8")).hexdigest() |
| |
| with open(self.src, "w") as src: |
| src.write(content) |
| with open(self.bad_src, "w") as bad: |
| bad.write("Hello!") |
| |
| def tearDown(self): |
| rmtree(self.container) |
| |
| def test_valid_file(self): |
| """Check if the sha256 sum of the given file is valid""" |
| self.assertTrue(bootstrap.verify(self.src, self.expected, False)) |
| |
| def test_invalid_file(self): |
| """Should verify that the file is invalid""" |
| self.assertFalse(bootstrap.verify(self.bad_src, self.expected, False)) |
| |
| |
| class ProgramOutOfDate(unittest.TestCase): |
| """Test if a program is out of date""" |
| def setUp(self): |
| self.container = tempfile.mkdtemp() |
| os.mkdir(os.path.join(self.container, "stage0")) |
| self.build = bootstrap.RustBuild() |
| self.build.date = "2017-06-15" |
| self.build.build_dir = self.container |
| self.rustc_stamp_path = os.path.join(self.container, "stage0", |
| ".rustc-stamp") |
| self.key = self.build.date + str(None) |
| |
| def tearDown(self): |
| rmtree(self.container) |
| |
| def test_stamp_path_does_not_exist(self): |
| """Return True when the stamp file does not exist""" |
| if os.path.exists(self.rustc_stamp_path): |
| os.unlink(self.rustc_stamp_path) |
| self.assertTrue(self.build.program_out_of_date(self.rustc_stamp_path, self.key)) |
| |
| def test_dates_are_different(self): |
| """Return True when the dates are different""" |
| with open(self.rustc_stamp_path, "w") as rustc_stamp: |
| rustc_stamp.write("2017-06-14None") |
| self.assertTrue(self.build.program_out_of_date(self.rustc_stamp_path, self.key)) |
| |
| def test_same_dates(self): |
| """Return False both dates match""" |
| with open(self.rustc_stamp_path, "w") as rustc_stamp: |
| rustc_stamp.write("2017-06-15None") |
| self.assertFalse(self.build.program_out_of_date(self.rustc_stamp_path, self.key)) |
| |
| |
| class GenerateAndParseConfig(unittest.TestCase): |
| """Test that we can serialize and deserialize a config.toml file""" |
| def test_no_args(self): |
| build = serialize_and_parse([]) |
| self.assertEqual(build.get_toml("profile"), 'dist') |
| self.assertIsNone(build.get_toml("llvm.download-ci-llvm")) |
| |
| def test_set_section(self): |
| build = serialize_and_parse(["--set", "llvm.download-ci-llvm"]) |
| self.assertEqual(build.get_toml("download-ci-llvm", section="llvm"), 'true') |
| |
| def test_set_target(self): |
| build = serialize_and_parse(["--set", "target.x86_64-unknown-linux-gnu.cc=gcc"]) |
| self.assertEqual(build.get_toml("cc", section="target.x86_64-unknown-linux-gnu"), 'gcc') |
| |
| def test_set_top_level(self): |
| build = serialize_and_parse(["--set", "profile=compiler"]) |
| self.assertEqual(build.get_toml("profile"), 'compiler') |
| |
| def test_set_codegen_backends(self): |
| build = serialize_and_parse(["--set", "rust.codegen-backends=cranelift"]) |
| self.assertNotEqual(build.config_toml.find("codegen-backends = ['cranelift']"), -1) |
| build = serialize_and_parse(["--set", "rust.codegen-backends=cranelift,llvm"]) |
| self.assertNotEqual(build.config_toml.find("codegen-backends = ['cranelift', 'llvm']"), -1) |
| build = serialize_and_parse(["--enable-full-tools"]) |
| self.assertNotEqual(build.config_toml.find("codegen-backends = ['llvm']"), -1) |
| |
| |
| class BuildBootstrap(unittest.TestCase): |
| """Test that we generate the appropriate arguments when building bootstrap""" |
| |
| def build_args(self, configure_args=None, args=None, env=None): |
| if configure_args is None: |
| configure_args = [] |
| if args is None: |
| args = [] |
| if env is None: |
| env = {} |
| |
| # This test ends up invoking build_bootstrap_cmd, which searches for |
| # the Cargo binary and errors out if it cannot be found. This is not a |
| # problem in most cases, but there is a scenario where it would cause |
| # the test to fail. |
| # |
| # When a custom local Cargo is configured in config.toml (with the |
| # build.cargo setting), no Cargo is downloaded to any location known by |
| # bootstrap, and bootstrap relies on that setting to find it. |
| # |
| # In this test though we are not using the config.toml of the caller: |
| # we are generating a blank one instead. If we don't set build.cargo in |
| # it, the test will have no way to find Cargo, failing the test. |
| cargo_bin = os.environ.get("BOOTSTRAP_TEST_CARGO_BIN") |
| if cargo_bin is not None: |
| configure_args += ["--set", "build.cargo=" + cargo_bin] |
| rustc_bin = os.environ.get("BOOTSTRAP_TEST_RUSTC_BIN") |
| if rustc_bin is not None: |
| configure_args += ["--set", "build.rustc=" + rustc_bin] |
| |
| env = env.copy() |
| env["PATH"] = os.environ["PATH"] |
| |
| parsed = bootstrap.parse_args(args) |
| build = serialize_and_parse(configure_args, parsed) |
| # Make these optional so that `python -m unittest` works when run manually. |
| build_dir = os.environ.get("BUILD_DIR") |
| if build_dir is not None: |
| build.build_dir = build_dir |
| build_platform = os.environ.get("BUILD_PLATFORM") |
| if build_platform is not None: |
| build.build = build_platform |
| return build.build_bootstrap_cmd(env), env |
| |
| def test_cargoflags(self): |
| args, _ = self.build_args(env={"CARGOFLAGS": "--timings"}) |
| self.assertTrue("--timings" in args) |
| |
| def test_warnings(self): |
| for toml_warnings in ['false', 'true', None]: |
| configure_args = [] |
| if toml_warnings is not None: |
| configure_args = ["--set", "rust.deny-warnings=" + toml_warnings] |
| |
| _, env = self.build_args(configure_args, args=["--warnings=warn"]) |
| self.assertFalse("-Dwarnings" in env["RUSTFLAGS"]) |
| |
| _, env = self.build_args(configure_args, args=["--warnings=deny"]) |
| self.assertTrue("-Dwarnings" in env["RUSTFLAGS"]) |