From 0018a79bec8c4de7542071f9f93fd37ac530b5bb Mon Sep 17 00:00:00 2001 From: Xinhao Yuan Date: Thu, 23 Jul 2026 11:05:24 -0700 Subject: [PATCH] Handle test skipping and early termination without the special failure types. These failure types will not be supported when migrate to the engine ABI. PiperOrigin-RevId: 952854556 --- e2e_tests/functional_test.cc | 4 +- fuzztest/internal/centipede_adaptor.cc | 89 ++++++++++++++++++-------- fuzztest/internal/googletest_adaptor.h | 6 +- 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/e2e_tests/functional_test.cc b/e2e_tests/functional_test.cc index af8f9e2a5..64ecd2690 100644 --- a/e2e_tests/functional_test.cc +++ b/e2e_tests/functional_test.cc @@ -1541,7 +1541,9 @@ TEST_P(FuzzingModeFixtureTest, TestIsSkippedWhenRequestedInFixturePerTest) { EXPECT_THAT_LOG(std_err, HasSubstr("Skipping SkippedTestFixturePerTest.SkippedTest")); EXPECT_THAT_LOG(std_err, Not(HasSubstr("SkippedTest should not be run"))); - EXPECT_THAT(status, Eq(ExitCode(0))); +#ifdef FUZZTEST_USE_CENTIPEDE + EXPECT_THAT_LOG(std_err, HasSubstr("SETUP FAILURE: Test is skipped")); +#endif } TEST_P(FuzzingModeFixtureTest, diff --git a/fuzztest/internal/centipede_adaptor.cc b/fuzztest/internal/centipede_adaptor.cc index f13801bf8..7670d768a 100644 --- a/fuzztest/internal/centipede_adaptor.cc +++ b/fuzztest/internal/centipede_adaptor.cc @@ -41,7 +41,8 @@ #include #include #include -#include // NOLINT: For thread::get_id() only. +#include // NOLINT +#include // NOLINT: For thread::get_id() only. #include #include @@ -510,14 +511,19 @@ class CentipedeAdaptorRunnerCallbacks absl::FPrintF(GetStderr(), "[.] Skipping %s per request from the test setup.\n", fuzzer_impl_.test_.full_name()); - CentipedeSetFailureDescription("SKIPPED TEST: Requested from setup"); - return true; + if (const char* indicator = + std::getenv("FUZZTEST_SKIPPED_TEST_INDICATOR_FILE"); + indicator != nullptr) { + absl::FPrintF(GetStderr(), "[.] Touching the indicator file %s\n", + indicator); + WriteFile(indicator, ""); + } + CentipedeSetFailureDescription("SETUP FAILURE: Test is skipped"); + return false; } if (runtime_.termination_requested()) { absl::FPrintF(GetStderr(), - "[.] Termination requested - exiting without executing " - "further inputs.\n"); - CentipedeSetFailureDescription("IGNORED FAILURE: Termination requested"); + "[.] Termination requested - not executing input.\n"); return false; } // We should avoid doing anything other than executing the input here so @@ -963,17 +969,28 @@ bool CentipedeFuzzerAdaptor::Run(int* argc, char*** argv, RunMode mode, } // Run as the fuzzing engine. int result = EXIT_FAILURE; + TempDir temp_dir; + const std::string skipped_test_indicator_file = + temp_dir.path() / "skipped_test_indicator"; + std::error_code ec; + runtime_.SetShouldTerminateOnNonFatalFailure(false); + [&] { - runtime_.SetShouldTerminateOnNonFatalFailure(false); - std::unique_ptr workdir; - if (configuration.corpus_database.empty() || - (!configuration.update_corpus_database && - configuration.workdir_root.empty())) { - workdir = std::make_unique("fuzztest_workdir"); - } - const std::string workdir_path = workdir ? workdir->path() : ""; - const auto env = CreateCentipedeEnvironmentFromConfiguration( - configuration, workdir_path, test_.full_name(), mode); + const auto env = [&] { + std::string workdir_path; + if (configuration.corpus_database.empty() || + (!configuration.update_corpus_database && + configuration.workdir_root.empty())) { + workdir_path = temp_dir.path() / "workdir"; + } + auto env = CreateCentipedeEnvironmentFromConfiguration( + configuration, workdir_path, test_.full_name(), mode); + env.env_diff_for_binaries.push_back( + absl::StrCat("FUZZTEST_SKIPPED_TEST_INDICATOR_FILE=", + skipped_test_indicator_file)); + return env; + }(); + if (const char* minimize_dir_chars = std::getenv("FUZZTEST_MINIMIZE_TESTSUITE_DIR")) { const std::string minimize_dir = minimize_dir_chars; @@ -995,17 +1012,25 @@ bool CentipedeFuzzerAdaptor::Run(int* argc, char*** argv, RunMode mode, replay_env.corpus_dir = {"", minimize_dir}; replay_env.load_shards_only = true; replay_env.report_crash_summary = false; - FUZZTEST_CHECK( - RunCentipede(replay_env, configuration.centipede_command) == 0) - << "Failed to replaying the testsuite for minimization"; + result = RunCentipede(replay_env, configuration.centipede_command); + if (std::filesystem::exists(skipped_test_indicator_file, ec)) { + return; + } + if (result != 0) { + absl::FPrintF(GetStderr(), + "[!] Failed to replaying the corpus for minimization"); + return; + } absl::FPrintF(GetStderr(), "[.] Imported the corpus from %s.\n", minimize_dir); // 2. Run Centipede distillation on the shard. auto distill_env = env; distill_env.distill = true; - FUZZTEST_CHECK( - RunCentipede(distill_env, configuration.centipede_command) == 0) - << "Failed to minimize the testsuite"; + result = RunCentipede(distill_env, configuration.centipede_command); + if (result != 0) { + absl::FPrintF(GetStderr(), "[!] Failed to minimize the testsuite"); + return; + } absl::FPrintF(GetStderr(), "[.] Minimized the corpus using Centipede distillation.\n"); // 3. Replace the shard corpus data with the distillation result. @@ -1018,9 +1043,13 @@ bool CentipedeFuzzerAdaptor::Run(int* argc, char*** argv, RunMode mode, // 4. Export the corpus of the shard. auto export_env = env; export_env.corpus_to_files = corpus_out_dir; - FUZZTEST_CHECK( - RunCentipede(export_env, configuration.centipede_command) == 0) - << "Failed to export the corpus to FUZZTEST_MINIMIZE_TESTSUITE_DIR"; + result = RunCentipede(export_env, configuration.centipede_command); + if (result != 0) { + absl::FPrintF( + GetStderr(), + "Failed to export the corpus to FUZZTEST_MINIMIZE_TESTSUITE_DIR"); + return; + } absl::FPrintF(GetStderr(), "[.] Exported the minimized the corpus to %s.\n", corpus_out_dir); @@ -1028,6 +1057,9 @@ bool CentipedeFuzzerAdaptor::Run(int* argc, char*** argv, RunMode mode, return; } result = RunCentipede(env, configuration.centipede_command); + if (std::filesystem::exists(skipped_test_indicator_file, ec)) { + return; + } if (!env.workdir.empty()) { if (runtime_.termination_requested()) { absl::FPrintF( @@ -1046,6 +1078,13 @@ bool CentipedeFuzzerAdaptor::Run(int* argc, char*** argv, RunMode mode, } } }(); + if (std::filesystem::exists(skipped_test_indicator_file, ec)) { + absl::FPrintF( + GetStderr(), + "[.] Indicator file for skipped test found - ignoring any failures.\n"); + runtime_.SetSkippingRequested(true); + return true; + } return result == 0; } diff --git a/fuzztest/internal/googletest_adaptor.h b/fuzztest/internal/googletest_adaptor.h index 457178185..39ffcab40 100644 --- a/fuzztest/internal/googletest_adaptor.h +++ b/fuzztest/internal/googletest_adaptor.h @@ -85,14 +85,16 @@ class GTest_TestAdaptor : public ::testing::Test { EXPECT_TRUE(false) << "Death test is not supported."; #endif } else { - EXPECT_TRUE(test->RunInUnitTestMode(configuration_)) + EXPECT_TRUE(test->RunInUnitTestMode(configuration_) || + Runtime::instance().skipping_requested()) << "Failure(s) found in the unit-test mode - please see the test " "log for more details."; } } else { // TODO(b/245753736): Consider using `tolerate_failure` when FuzzTest can // tolerate crashes in fuzzing mode. - EXPECT_TRUE(test->RunInFuzzingMode(argc_, argv_, configuration_)) + EXPECT_TRUE(test->RunInFuzzingMode(argc_, argv_, configuration_) || + Runtime::instance().skipping_requested()) << "Failure(s) found in the fuzzing mode - please see the test log " "for more details."; }