From 73a8d6c92505d3bdb86caa0a7fb1efc8ed86e540 Mon Sep 17 00:00:00 2001 From: Bo Zhang Date: Sun, 21 Aug 2022 18:26:28 +0800 Subject: [PATCH] Throw explicit exception if experimental_split_coverage_postprocessing is used without experimental_fetch_all_coverage_outputs This closes https://github.com/bazelbuild/bazel/issues/13185 According to https://github.com/bazelbuild/bazel/commit/a445cda122cb1214cc7c5beb0c1e944dfd9a0c59, The flag --experimental_split_coverage_postprocessing depends on the flag --experimental_fetch_all_coverage_outputs being enabled, but if the former one is set without the latter one, Bazel throws a quite confusing NullPointerException. Now we throw an explicit exception with proper error message. --- .../lib/exec/StandaloneTestStrategy.java | 32 ++++++++++++++----- .../shell/bazel/bazel_coverage_cc_test_gcc.sh | 26 +++++++++++++++ 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java index 1261a898eb80fd..adb603e6305fb2 100644 --- a/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java @@ -102,14 +102,10 @@ public TestRunnerSpawn createTestRunnerSpawn( TestRunnerAction action, ActionExecutionContext actionExecutionContext) throws ExecException, InterruptedException { if (action.getExecutionSettings().getInputManifest() == null) { - String errorMessage = "cannot run local tests with --nobuild_runfile_manifests"; - throw new TestExecException( - errorMessage, - FailureDetail.newBuilder() - .setTestAction( - TestAction.newBuilder().setCode(TestAction.Code.LOCAL_TEST_PREREQ_UNMET)) - .setMessage(errorMessage) - .build()); + throw createTestExecException( + TestAction.Code.LOCAL_TEST_PREREQ_UNMET, + "cannot run local tests with --nobuild_runfile_manifests" + ); } Map testEnvironment = createEnvironment( @@ -641,6 +637,16 @@ public void finalizeCancelledTest(List failedAttempts) thro } } + private static TestExecException createTestExecException(TestAction.Code errorCode, String errorMessage) { + return new TestExecException( + errorMessage, + FailureDetail.newBuilder() + .setTestAction(TestAction.newBuilder().setCode(errorCode)) + .setMessage(errorMessage) + .build() + ); + } + private final class BazelTestAttemptContinuation extends TestAttemptContinuation { private final TestRunnerAction testAction; private final ActionExecutionContext actionExecutionContext; @@ -760,6 +766,16 @@ public TestAttemptContinuation execute() .setHasCoverage(testAction.isCoverageMode()); if (testAction.isCoverageMode() && testAction.getSplitCoveragePostProcessing()) { + if (testAction.getCoverageDirectoryTreeArtifact() == null) { + // Otherwise we'll get a NPE https://github.com/bazelbuild/bazel/issues/13185 + TestExecException e = createTestExecException( + TestAction.Code.LOCAL_TEST_PREREQ_UNMET, + "coverageDirectoryTreeArtifact is null: --experimental_split_coverage_postprocessing depends on --experimental_fetch_all_coverage_outputs being enabled" + ); + closeSuppressed(e, streamed); + closeSuppressed(e, fileOutErr); + throw e; + } actionExecutionContext .getMetadataHandler() .getMetadata(testAction.getCoverageDirectoryTreeArtifact()); diff --git a/src/test/shell/bazel/bazel_coverage_cc_test_gcc.sh b/src/test/shell/bazel/bazel_coverage_cc_test_gcc.sh index a79a13c2748cc7..3ad7498d50a531 100755 --- a/src/test/shell/bazel/bazel_coverage_cc_test_gcc.sh +++ b/src/test/shell/bazel/bazel_coverage_cc_test_gcc.sh @@ -875,6 +875,32 @@ EOF assert_contains 'name: "test.lcov"' bep.txt } +function test_coverage_with_experimental_split_coverage_postprocessing_only() { + local -r LCOV=$(which lcov) + if [[ ! -x ${LCOV:-/usr/bin/lcov} ]]; then + echo "lcov not installed. Skipping test." + return + fi + + cat << EOF > BUILD +cc_test( + name = "hello-test", + srcs = ["hello-test.cc"], +) +EOF + + + cat << EOF > hello-test.cc +int main() { + return 0; +} +EOF + bazel coverage --test_output=all --experimental_split_coverage_postprocessing //:hello-test \ + &>$TEST_log && fail "Expected test failure" || : + + assert_contains '--experimental_split_coverage_postprocessing depends on --experimental_fetch_all_coverage_outputs being enabled' $TEST_log +} + function test_coverage_doesnt_fail_on_empty_output() { if is_gcov_missing_or_wrong_version; then echo "Skipping test." && return