diff --git a/src/clusterfuzz/_internal/bot/tasks/utasks/fuzz_task.py b/src/clusterfuzz/_internal/bot/tasks/utasks/fuzz_task.py index 044e5f0a4c..aa6f6ee47b 100644 --- a/src/clusterfuzz/_internal/bot/tasks/utasks/fuzz_task.py +++ b/src/clusterfuzz/_internal/bot/tasks/utasks/fuzz_task.py @@ -2284,8 +2284,9 @@ def run(self): # Delete the fuzzed testcases. This was once explicitly needed since some # testcases resided on NFS and would otherwise be left forever. Now it's # unclear if needed but it is kept because it is not harmful. - for testcase_file_path in testcase_file_paths: - shell.remove_file(testcase_file_path) + with self.steps_time_tracker.track('remove_testcase_file'): + for testcase_file_path in testcase_file_paths: + shell.remove_file(testcase_file_path) # TODO(dylanj): Handle cases where the blackbox fuzzer executes multiple # logical testcases per test file and we'd like to factor that multiplier diff --git a/src/clusterfuzz/_internal/metrics/fuzzer_stats.py b/src/clusterfuzz/_internal/metrics/fuzzer_stats.py index 487f400bcd..308d49d6be 100644 --- a/src/clusterfuzz/_internal/metrics/fuzzer_stats.py +++ b/src/clusterfuzz/_internal/metrics/fuzzer_stats.py @@ -66,6 +66,11 @@ 'type': 'INTERVAL', 'mode': 'NULLABLE', }, + { + 'name': 'remove_testcase_file', + 'type': 'INTERVAL', + 'mode': 'NULLABLE', + }, ] JOB_RUN_SCHEMA = { 'fields': [ diff --git a/src/clusterfuzz/_internal/tests/core/bot/tasks/utasks/fuzz_task_test.py b/src/clusterfuzz/_internal/tests/core/bot/tasks/utasks/fuzz_task_test.py index f7df5289e6..0fd23b6d78 100644 --- a/src/clusterfuzz/_internal/tests/core/bot/tasks/utasks/fuzz_task_test.py +++ b/src/clusterfuzz/_internal/tests/core/bot/tasks/utasks/fuzz_task_test.py @@ -1841,6 +1841,53 @@ def test_utask_main_blackbox_fuzzer_no_crashes( }) self.assertEqual(1, parse_dist.count) + @mock.patch( + 'clusterfuzz._internal.bot.tasks.utasks.fuzz_task.FuzzingSession.generate_blackbox_testcases' + ) + def test_utask_main_remove_testcase_file(self, + mock_generate_blackbox_testcases): + """Test that deleting the fuzzed testcases is tracked.""" + self._setup_utask_env() + fuzzer = self._create_test_fuzzer() + uworker_input = self._create_blackbox_uworker_input(fuzzer) + + testcase_file_paths = ['/tests/0', '/tests/1', '/tests/2'] + for path in testcase_file_paths: + self.fs.create_file(path, contents='testcase') + mock_generate_blackbox_testcases.return_value = ( + fuzz_task.GenerateBlackboxTestcasesResult( + True, testcase_file_paths, {'fuzzer_binary_name': fuzzer.name})) + + actual = fuzz_task.utask_main(uworker_input) + + for path in testcase_file_paths: + self.assertFalse(os.path.exists(path)) + self.assertGreater( + actual.fuzz_task_output.steps_duration['remove_testcase_file'] + .ToTimedelta().total_seconds(), 0) + dist = monitoring_metrics.FUZZ_TASK_STEPS_DURATION.get({ + 'fuzzer': fuzzer.name, + 'job': 'asan_test', + 'platform': environment.platform(), + 'runtime': environment.get_runtime().value, + 'step': 'remove_testcase_file', + 'success': True, + }) + self.assertEqual(1, dist.count) + self.assertGreater(dist.sum, 0) + + def _create_blackbox_uworker_input(self, fuzzer): + """Creates a uworker input for a blackbox fuzzing utask_main run.""" + fuzz_task_input = uworker_msg_pb2.FuzzTaskInput() + setup_input = uworker_msg_pb2.SetupInput( + fuzzer_name=fuzzer.name, fuzzer=uworker_io.entity_to_protobuf(fuzzer)) + return uworker_msg_pb2.Input( + fuzzer_name=fuzzer.name, + job_type='asan_test', + fuzz_task_input=fuzz_task_input, + setup_input=setup_input, + uworker_env={'FUZZ_TEST_TIMEOUT': '10'}) + class DoBlackboxFuzzingDeferredLoggingTest(fake_filesystem_unittest.TestCase): """do_blackbox_fuzzing deferred log upload unit tests without datastore dependency."""