diff --git a/e2e_tests/functional_test.cc b/e2e_tests/functional_test.cc index 613347390..3327a3896 100644 --- a/e2e_tests/functional_test.cc +++ b/e2e_tests/functional_test.cc @@ -1525,7 +1525,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 0072126c4..9c3813cc6 100644 --- a/fuzztest/internal/centipede_adaptor.cc +++ b/fuzztest/internal/centipede_adaptor.cc @@ -510,14 +510,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,16 +968,27 @@ 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"; + std::error_code ec; + runtime_.SetShouldTerminateOnNonFatalFailure(false); + [&] { - runtime_.SetShouldTerminateOnNonFatalFailure(false); - std::unique_ptr workdir; - if (configuration.corpus_database.empty() || - (mode == RunMode::kUnitTest && 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() || + (mode == RunMode::kUnitTest && 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; @@ -994,17 +1010,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. @@ -1017,9 +1041,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); @@ -1027,6 +1055,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( @@ -1045,6 +1076,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..2a2d2b532 100644 --- a/fuzztest/internal/googletest_adaptor.h +++ b/fuzztest/internal/googletest_adaptor.h @@ -85,17 +85,22 @@ 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."; } + if (Runtime::instance().skipping_requested()) { + GTEST_SKIP() << "Test was skipped"; + } } static void SetUpTestSuite() {