diff --git a/.buildkite/pipeline_sanitizers.py b/.buildkite/pipeline_sanitizers.py new file mode 100755 index 00000000000..2c85a077888 --- /dev/null +++ b/.buildkite/pipeline_sanitizers.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Generate Buildkite pipelines dynamically.""" + +from common import BKPipeline + +pipeline = BKPipeline(with_build_step=False) + +pipeline.build_group_per_arch( + "sanitizers", + pipeline.devtool_test( + devtool_opts="--no-build", + pytest_opts="-m nonci integration_tests/build/test_sanitizers.py", + ), +) + +print(pipeline.to_json()) diff --git a/tests/README.md b/tests/README.md index d2fdfbc08f3..84fec0fd071 100644 --- a/tests/README.md +++ b/tests/README.md @@ -111,6 +111,18 @@ Unlike unit tests, Rust integration tests are each run in a separate process. To learn more about Rust integration test, see [the Rust book](https://doc.rust-lang.org/book/ch11-03-test-organization.html#integration-tests). +## Sanitizer Runs + +Firecracker also has a dedicated build test that runs Rust integration tests +under sanitizers: + +```bash +tools/devtool -y test -- -m nonci integration_tests/build/test_sanitizers.py +``` + +The Buildkite sanitizer pipeline is generated by +[`pipeline_sanitizers.py`](../.buildkite/pipeline_sanitizers.py). + ## A/B-Tests A/B-Testing is a testing strategy where some test function is executed twice in diff --git a/tests/integration_tests/build/test_sanitizers.py b/tests/integration_tests/build/test_sanitizers.py new file mode 100644 index 00000000000..20df9fde9b9 --- /dev/null +++ b/tests/integration_tests/build/test_sanitizers.py @@ -0,0 +1,42 @@ +# Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Run Rust integration tests under sanitizers.""" + +import platform + +import pytest + +from framework import defs +from host_tools.cargo_build import cargo, get_rustflags + +TARGET = f"{platform.machine()}-unknown-linux-gnu" +SANITIZERS = ("address",) +REPO_ROOT = defs.FC_WORKSPACE_DIR +VMM_TEST_TARGETS = sorted((REPO_ROOT / "src" / "vmm" / "tests").glob("*.rs")) + + +@pytest.mark.nonci +@pytest.mark.timeout(3600) +@pytest.mark.parametrize("sanitizer", SANITIZERS) +def test_rust_integration_tests_under_sanitizer(sanitizer): + """Run vmm Rust integration tests under the specified sanitizer.""" + cargo_args = " ".join( + [ + f"--target {TARGET}", + "-p vmm", + *(f"--test {path.stem}" for path in VMM_TEST_TARGETS), + ] + ) + target_dir = defs.LOCAL_BUILD_PATH / "cargo_target" / "sanitizers" / sanitizer + rustflags = get_rustflags() + f"-Zsanitizer={sanitizer}" + cargo( + "test", + cargo_args, + "--test-threads=1", + nightly=True, + cwd=str(REPO_ROOT), + env={ + "CARGO_TARGET_DIR": str(target_dir), + "RUSTFLAGS": rustflags, + }, + ) diff --git a/tools/test.sh b/tools/test.sh index 1da29efd575..94c747769bd 100755 --- a/tools/test.sh +++ b/tools/test.sh @@ -53,7 +53,7 @@ export PYTEST_ADDOPTS="${PYTEST_ADDOPTS:-} --pdbcls=IPython.terminal.debugger:Te # if the tests failed and we are running in CI, print some disk usage stats # to help troubleshooting -if [ $ret != 0 ] && [ "$BUILDKITE" == "true" ]; then +if [ $ret != 0 ] && [ "${BUILDKITE:-false}" == "true" ]; then df -ih df -h du -h / 2>/dev/null |sort -h |tail -32