|
1 | 1 | load("@rules_cc//cc:cc_binary.bzl", "cc_binary") |
2 | | -load("@rules_shell//shell:sh_test.bzl", "sh_test") |
3 | 2 |
|
4 | 3 | def kj_test( |
5 | 4 | src, |
@@ -48,22 +47,118 @@ def kj_test( |
48 | 47 | }), |
49 | 48 | ) |
50 | 49 |
|
51 | | - sh_test( |
| 50 | + _kj_test( |
52 | 51 | name = test_name + "@", |
53 | 52 | size = size, |
54 | | - srcs = ["//build/fixtures:kj_test.sh"], |
55 | | - data = [cross_alias] + data, |
56 | | - args = ["$(location " + cross_alias + ")"], |
| 53 | + binary = cross_alias, |
| 54 | + data = data, |
57 | 55 | tags = tags, |
58 | 56 | ) |
59 | 57 |
|
60 | | - # Tagged with no-coverage to reduce coverage CI time |
61 | | - sh_test( |
| 58 | + _kj_test( |
62 | 59 | name = test_name + "@all-autogates", |
63 | 60 | size = size, |
64 | 61 | env = {"WORKERD_ALL_AUTOGATES": "1"}, |
65 | | - srcs = ["//build/fixtures:kj_test.sh"], |
66 | | - data = [cross_alias] + data, |
67 | | - args = ["$(location " + cross_alias + ")"], |
68 | | - tags = tags + ["no-coverage"], |
| 62 | + binary = cross_alias, |
| 63 | + data = data, |
| 64 | + tags = tags, |
69 | 65 | ) |
| 66 | + |
| 67 | +# Shell template for kj_test - sets up coverage environment for the subprocess |
| 68 | +_SH_TEMPLATE = """#!/bin/sh |
| 69 | +set -e |
| 70 | +{env_exports} |
| 71 | +# Set up coverage for the test binary subprocess |
| 72 | +if [ -n "$COVERAGE_DIR" ]; then |
| 73 | + # Fix directory permissions for coverage post-processing |
| 74 | + # (Bazel may create COVERAGE_DIR with read-only permissions) |
| 75 | + chmod -R u+w "$COVERAGE_DIR" 2>/dev/null || true |
| 76 | + export LLVM_PROFILE_FILE="$COVERAGE_DIR/%p.profraw" |
| 77 | + export KJ_CLEAN_SHUTDOWN=1 |
| 78 | +fi |
| 79 | +
|
| 80 | +exec {binary} "$@" |
| 81 | +""" |
| 82 | + |
| 83 | +_BAT_TEMPLATE = """@echo off |
| 84 | +{env_exports}{binary} %* |
| 85 | +""" |
| 86 | + |
| 87 | +def _kj_test_impl(ctx): |
| 88 | + is_windows = ctx.target_platform_has_constraint(ctx.attr._platforms_os_windows[platform_common.ConstraintValueInfo]) |
| 89 | + |
| 90 | + # Generate environment variable exports |
| 91 | + env_exports = "" |
| 92 | + for key, value in ctx.attr.env.items(): |
| 93 | + if is_windows: |
| 94 | + env_exports += "set {}={}\n".format(key, value) |
| 95 | + else: |
| 96 | + env_exports += "export {}=\"{}\"\n".format(key, value) |
| 97 | + |
| 98 | + if is_windows: |
| 99 | + executable = ctx.actions.declare_file("%s_kj_test.bat" % ctx.label.name) |
| 100 | + content = _BAT_TEMPLATE.format(binary = ctx.file.binary.short_path.replace("/", "\\"), env_exports = env_exports) |
| 101 | + else: |
| 102 | + executable = ctx.outputs.executable |
| 103 | + content = _SH_TEMPLATE.format(binary = ctx.file.binary.short_path, env_exports = env_exports) |
| 104 | + |
| 105 | + ctx.actions.write( |
| 106 | + output = executable, |
| 107 | + content = content, |
| 108 | + is_executable = True, |
| 109 | + ) |
| 110 | + |
| 111 | + runfiles = ctx.runfiles(files = ctx.files.data + [ctx.file.binary]) |
| 112 | + |
| 113 | + # Merge the binary's runfiles |
| 114 | + default_runfiles = ctx.attr.binary[DefaultInfo].default_runfiles |
| 115 | + if default_runfiles: |
| 116 | + runfiles = runfiles.merge(default_runfiles) |
| 117 | + |
| 118 | + # IMPORTANT: The binary must be listed in dependency_attributes to ensure |
| 119 | + # its transitive dependencies (all the C++ source files) are included in |
| 120 | + # coverage instrumentation. Without this, coverage data won't be collected. |
| 121 | + instrumented_files_info = coverage_common.instrumented_files_info( |
| 122 | + ctx, |
| 123 | + source_attributes = [], |
| 124 | + dependency_attributes = ["binary"], |
| 125 | + ) |
| 126 | + |
| 127 | + return [ |
| 128 | + DefaultInfo( |
| 129 | + executable = executable, |
| 130 | + runfiles = runfiles, |
| 131 | + ), |
| 132 | + instrumented_files_info, |
| 133 | + ] |
| 134 | + |
| 135 | +_kj_test = rule( |
| 136 | + implementation = _kj_test_impl, |
| 137 | + test = True, |
| 138 | + attrs = { |
| 139 | + # Implicit dependencies used by Bazel to generate coverage reports. |
| 140 | + "_lcov_merger": attr.label( |
| 141 | + default = configuration_field(fragment = "coverage", name = "output_generator"), |
| 142 | + executable = True, |
| 143 | + cfg = config.exec(exec_group = "test"), |
| 144 | + ), |
| 145 | + "_collect_cc_coverage": attr.label( |
| 146 | + default = "//build/coverage:collect_cc_coverage", |
| 147 | + executable = True, |
| 148 | + cfg = config.exec(exec_group = "test"), |
| 149 | + ), |
| 150 | + # The test binary to run |
| 151 | + "binary": attr.label( |
| 152 | + allow_single_file = True, |
| 153 | + executable = True, |
| 154 | + cfg = "target", |
| 155 | + mandatory = True, |
| 156 | + ), |
| 157 | + # Additional data files needed by the test |
| 158 | + "data": attr.label_list(allow_files = True), |
| 159 | + # Environment variables to set when running the test |
| 160 | + "env": attr.string_dict(default = {}), |
| 161 | + # Reference to Windows platform for cross-platform support |
| 162 | + "_platforms_os_windows": attr.label(default = "@platforms//os:windows"), |
| 163 | + }, |
| 164 | +) |
0 commit comments