From afa4d4cc8211464111f62a6bcda3c5c08de434fc Mon Sep 17 00:00:00 2001 From: Charles Mita Date: Wed, 11 Feb 2026 11:43:08 +0100 Subject: [PATCH] Experimental POC for C++ integration tests --- BUILD | 10 ++++ MODULE.bazel | 16 ++++++ WORKSPACE | 28 +++++++++++ cc/BUILD | 4 ++ cc/private/BUILD | 1 + cc/private/toolchain/test/BUILD | 9 ++++ cc/proto/BUILD | 7 +++ tests/integration/BUILD | 50 +++++++++++++++++++ .../BUILD.test | 13 +++++ .../MODULE.bazel | 7 +++ .../a.cc | 5 ++ .../b1.h | 1 + .../b2.h | 1 + ...on_irrelevant_header_change_test_runner.sh | 34 +++++++++++++ tests/integration/test_utils.sh | 24 +++++++++ 15 files changed, 210 insertions(+) create mode 100644 tests/integration/BUILD create mode 100644 tests/integration/no_rebuild_on_irrelevant_header_change/BUILD.test create mode 100644 tests/integration/no_rebuild_on_irrelevant_header_change/MODULE.bazel create mode 100644 tests/integration/no_rebuild_on_irrelevant_header_change/a.cc create mode 100644 tests/integration/no_rebuild_on_irrelevant_header_change/b1.h create mode 100644 tests/integration/no_rebuild_on_irrelevant_header_change/b2.h create mode 100755 tests/integration/no_rebuild_on_irrelevant_header_change_test_runner.sh create mode 100644 tests/integration/test_utils.sh diff --git a/BUILD b/BUILD index 704df8aee..0859d0b8e 100644 --- a/BUILD +++ b/BUILD @@ -42,3 +42,13 @@ filegroup( ], visibility = ["//:__subpackages__"], ) + +filegroup( + name = "all_files_for_testing", + srcs = [ + "BUILD", + "WORKSPACE", + "MODULE.bazel", + "//cc:all_files_for_testing", + ] +) diff --git a/MODULE.bazel b/MODULE.bazel index 1f5839625..438689f7a 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -32,3 +32,19 @@ bazel_dep(name = "stardoc", version = "0.8.0", dev_dependency = True) # Compatibility layer compat = use_extension("//cc:extensions.bzl", "compatibility_proxy") use_repo(compat, "cc_compatibility_proxy") + +bazel_dep( + name = "rules_bazel_integration_test", + version = "0.36.0", + dev_dependency = True, +) + +bazel_binaries = use_extension( + "@rules_bazel_integration_test//:extensions.bzl", + "bazel_binaries", + dev_dependency = True, +) +bazel_binaries.download(version_file = "//:.bazelversion") +bazel_binaries.download(version = "8.5.1") +bazel_binaries.download(version = "last_green") +use_repo(bazel_binaries, "bazel_binaries", "bazel_binaries_bazelisk", "build_bazel_bazel_.bazelversion", "build_bazel_bazel_8_5_1", "build_bazel_bazel_last_green") diff --git a/WORKSPACE b/WORKSPACE index 70f17174b..5b1867d3b 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -65,3 +65,31 @@ bazel_features_deps() load("//cc:extensions.bzl", "compatibility_proxy_repo") compatibility_proxy_repo() + +http_archive( + name = "rules_bazel_integration_test", + sha256 = "caadcd3adafc2cdcd4b020cf0ae530ddab4dc61201a9948473909b75a91e9192", + urls = [ + "https://github.com/bazel-contrib/rules_bazel_integration_test/releases/download/v0.35.0/rules_bazel_integration_test.v0.35.0.tar.gz", + ], +) + +load("@rules_bazel_integration_test//bazel_integration_test:deps.bzl", "bazel_integration_test_rules_dependencies") + +bazel_integration_test_rules_dependencies() + +load("@cgrindel_bazel_starlib//:deps.bzl", "bazel_starlib_dependencies") + +bazel_starlib_dependencies() + +load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") + +bazel_skylib_workspace() + +load("@rules_bazel_integration_test//bazel_integration_test:defs.bzl", "bazel_binaries") + +bazel_binaries(versions = [ + "//:.bazelversion", + "8.5.1", + "last_green", +]) diff --git a/cc/BUILD b/cc/BUILD index 72e9d74b2..5e2891845 100644 --- a/cc/BUILD +++ b/cc/BUILD @@ -23,8 +23,12 @@ licenses(["notice"]) # Apache 2.0 filegroup( name = "all_files_for_testing", srcs = glob(["**"]) + [ + "//cc/private:srcs", "//cc/private/rules_impl:srcs", "//cc/private/toolchain:srcs", + "//cc/common:srcs", + "//cc/proto:srcs", + "//cc/toolchains:srcs", ], ) diff --git a/cc/private/BUILD b/cc/private/BUILD index 41575bc42..1ede1c0df 100644 --- a/cc/private/BUILD +++ b/cc/private/BUILD @@ -38,6 +38,7 @@ filegroup( "//cc/private/link:srcs", "//cc/private/rules_impl:srcs", "//cc/private/toolchain:srcs", + "//cc/private/toolchain/test:srcs", "//cc/private/toolchain_config:srcs", ], visibility = ["//visibility:public"], diff --git a/cc/private/toolchain/test/BUILD b/cc/private/toolchain/test/BUILD index 30bc7b94d..c66c94bd9 100644 --- a/cc/private/toolchain/test/BUILD +++ b/cc/private/toolchain/test/BUILD @@ -11,3 +11,12 @@ compat_toolchain( toolchain_type = "@bazel_tools//tools/cpp:test_runner_toolchain_type", use_target_platform_constraints = True, ) + +filegroup( + name = "srcs", + srcs = glob([ + "**/BUILD", + "*.bzl", + ]), + visibility = ["//cc/private:__pkg__"], +) diff --git a/cc/proto/BUILD b/cc/proto/BUILD index 3be618715..d5b477b75 100644 --- a/cc/proto/BUILD +++ b/cc/proto/BUILD @@ -2,3 +2,10 @@ package(default_visibility = ["//visibility:public"]) # Toolchain type provided by proto_lang_toolchain rule and used by cc_proto_library toolchain_type(name = "toolchain_type") + +filegroup( + name = "srcs", + srcs = glob([ + "**/BUILD", + ]), +) diff --git a/tests/integration/BUILD b/tests/integration/BUILD new file mode 100644 index 000000000..eb6d6111c --- /dev/null +++ b/tests/integration/BUILD @@ -0,0 +1,50 @@ +load("@bazel_binaries//:defs.bzl", "bazel_binaries") +load("@rules_bazel_integration_test//bazel_integration_test:defs.bzl", "default_test_runner") +load("@rules_bazel_integration_test//bazel_integration_test:defs.bzl", "bazel_integration_test") +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") +load("@rules_shell//shell:sh_library.bzl", "sh_library") + +sh_library( + name = "test_utils", + srcs = ["test_utils.sh"], +) + +genrule( + name = "no_rebuild_on_irrelevant_header_change_build_gen", + srcs = ["no_rebuild_on_irrelevant_header_change/BUILD.test"], + outs = ["no_rebuild_on_irrelevant_header_change/BUILD"], + cmd = "cp $< $@", +) + +filegroup( + name = "no_rebuild_on_irrelevant_header_change_files", + srcs = [ + ":no_rebuild_on_irrelevant_header_change/BUILD", + ] + glob(["no_rebuild_on_irrelevant_header_change/**"]) +) + +sh_binary( + name = "no_rebuild_on_irrelevant_header_change_test_runner", + testonly = True, + srcs = ["no_rebuild_on_irrelevant_header_change_test_runner.sh"], + deps = [ + ":test_utils", + "@rules_shell//shell/runfiles", + ], + data = [ + "@rules_bazel_integration_test//tools:create_scratch_dir", + ], +) + +bazel_integration_test( + name = "no_rebuild_on_irrelevant_header_change_test", + test_runner = ":no_rebuild_on_irrelevant_header_change_test_runner", + bazel_binaries = bazel_binaries, + bazel_version = "8.5.1", + workspace_path = "no_rebuild_on_irrelevant_header_change", + workspace_files = [ + ":no_rebuild_on_irrelevant_header_change_files", + "//:all_files_for_testing", + ], + tags = [], +) diff --git a/tests/integration/no_rebuild_on_irrelevant_header_change/BUILD.test b/tests/integration/no_rebuild_on_irrelevant_header_change/BUILD.test new file mode 100644 index 000000000..4513766d8 --- /dev/null +++ b/tests/integration/no_rebuild_on_irrelevant_header_change/BUILD.test @@ -0,0 +1,13 @@ +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") +load("@rules_cc//cc:cc_test.bzl", "cc_test") + +cc_library( + name = "b", + srcs = ["b1.h", "b2.h"], +) + +cc_binary( + name = "a", + srcs = ["a.cc"], + deps = [":b"], +) diff --git a/tests/integration/no_rebuild_on_irrelevant_header_change/MODULE.bazel b/tests/integration/no_rebuild_on_irrelevant_header_change/MODULE.bazel new file mode 100644 index 000000000..e5920359f --- /dev/null +++ b/tests/integration/no_rebuild_on_irrelevant_header_change/MODULE.bazel @@ -0,0 +1,7 @@ +module(name = "module_under_test") + +bazel_dep(name = "rules_cc", version = "0.0.0") +local_path_override( + module_name = "rules_cc", + path = "../../..", +) diff --git a/tests/integration/no_rebuild_on_irrelevant_header_change/a.cc b/tests/integration/no_rebuild_on_irrelevant_header_change/a.cc new file mode 100644 index 000000000..323e91a40 --- /dev/null +++ b/tests/integration/no_rebuild_on_irrelevant_header_change/a.cc @@ -0,0 +1,5 @@ +#include "b1.h" + +int main(void) { + return B_RETURN_VALUE; +} diff --git a/tests/integration/no_rebuild_on_irrelevant_header_change/b1.h b/tests/integration/no_rebuild_on_irrelevant_header_change/b1.h new file mode 100644 index 000000000..eb69677b2 --- /dev/null +++ b/tests/integration/no_rebuild_on_irrelevant_header_change/b1.h @@ -0,0 +1 @@ +#define B_RETURN_VALUE 31 diff --git a/tests/integration/no_rebuild_on_irrelevant_header_change/b2.h b/tests/integration/no_rebuild_on_irrelevant_header_change/b2.h new file mode 100644 index 000000000..a8b5d5be4 --- /dev/null +++ b/tests/integration/no_rebuild_on_irrelevant_header_change/b2.h @@ -0,0 +1 @@ +=== BANANA === diff --git a/tests/integration/no_rebuild_on_irrelevant_header_change_test_runner.sh b/tests/integration/no_rebuild_on_irrelevant_header_change_test_runner.sh new file mode 100755 index 000000000..33d93425c --- /dev/null +++ b/tests/integration/no_rebuild_on_irrelevant_header_change_test_runner.sh @@ -0,0 +1,34 @@ +set -euo pipefail + +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +# shellcheck disable=SC1090 +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- + +source tests/integration/test_utils.sh + +create_scratch_dir_sh_location=rules_bazel_integration_test/tools/create_scratch_dir.sh +create_scratch_dir_sh="$(rlocation "${create_scratch_dir_sh_location}")" || \ + (echo >&2 "Failed to locate ${create_scratch_dir_sh_location}" && exit 1) + +scratch_dir="$("${create_scratch_dir_sh}" --workspace "${BIT_WORKSPACE_DIR}")" + +TEST_log="$scratch_dir/test.log" + +# Change into scratch directory +cd "${scratch_dir}" + +"${BIT_BAZEL_BINARY}" build -s //:a &> $TEST_log || fail +expect_log "Compiling a.cc" + +echo "CHERRY" > b2.h + +"${BIT_BAZEL_BINARY}" build -s //:a &> $TEST_log || fail +expect_not_log "Compiling a.cc" diff --git a/tests/integration/test_utils.sh b/tests/integration/test_utils.sh new file mode 100644 index 000000000..46aab336a --- /dev/null +++ b/tests/integration/test_utils.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +function fail() { + echo "FAILED: $*." >&2 + exit 1 +} + +function expect_log() { + local pattern=$1 + local message=${2:-"Expected regexp '$pattern' not found"} + grep -sq -- "$pattern" $TEST_log && return 0 + + fail "$message" + return 1 +} + +function expect_not_log() { + local pattern=$1 + local message=${2:-"Unexpected regexp '$pattern' found"} + grep -sq -- "$pattern" $TEST_log || return 0 + + fail "$message" + return 1 +}