|
20 | 20 | import shutil
|
21 | 21 | import tempfile
|
22 | 22 | import unittest
|
| 23 | +from unittest.mock import patch |
23 | 24 |
|
24 | 25 | from clusterfuzz._internal.bot.fuzzers import options
|
25 | 26 | from clusterfuzz._internal.bot.fuzzers.centipede import \
|
@@ -107,6 +108,7 @@ def mocked_unpack_seed_corpus_if_needed(*args, **kwargs):
|
107 | 108 | self.corpus_dir = os.path.join(self.corpus_bucket, 'corpus')
|
108 | 109 | self.quarantine_dir = os.path.join(self.corpus_bucket, 'quarantine')
|
109 | 110 | self.shared_corpus_dir = os.path.join(self.corpus_bucket, 'shared')
|
| 111 | + self.quarantine_call_count = 0 |
110 | 112 |
|
111 | 113 | shutil.copytree(os.path.join(TEST_DIR, 'corpus'), self.corpus_dir)
|
112 | 114 | shutil.copytree(os.path.join(TEST_DIR, 'quarantine'), self.quarantine_dir)
|
@@ -146,6 +148,7 @@ def _mock_rsync_to_disk(self, _, sync_dir, timeout=None, delete=None):
|
146 | 148 |
|
147 | 149 | def _mock_rsync_from_disk(self, _, sync_dir, timeout=None, delete=None):
|
148 | 150 | """Mock rsync_from_disk."""
|
| 151 | + self.quarantine_call_count += 1 |
149 | 152 | if 'quarantine' in sync_dir:
|
150 | 153 | corpus_dir = self.quarantine_dir
|
151 | 154 | else:
|
@@ -307,6 +310,52 @@ def test_get_libfuzzer_flags(self):
|
307 | 310 | ]
|
308 | 311 | self.assertCountEqual(flags, expected_custom_flags)
|
309 | 312 |
|
| 313 | + def test_rsync_from_disk_when_quarantine_corpus_is_nonzero(self): |
| 314 | + """ |
| 315 | + do_corpus_pruning() calls rsync_from_disk() three times in total — twice |
| 316 | + with the minimized corpus and once with the quarantine corpus. The fix introduces |
| 317 | + a check to determine whether the quarantine corpus is empty before calling |
| 318 | + rsync_from_disk(), as this was not being verified anywhere in the control flow. |
| 319 | +
|
| 320 | + When the quarantine corpus is not empty, we expect rsync_from_disk() to be called |
| 321 | + three times. If the quarantine corpus is empty, we expect it to be called twice, as |
| 322 | + the fix ensures that the call to rsync_from_disk() is skipped. |
| 323 | + """ |
| 324 | + |
| 325 | + self.quarantine_call_count = 0 |
| 326 | + uworker_input = corpus_pruning_task.utask_preprocess( |
| 327 | + job_type='libfuzzer_asan_job', |
| 328 | + fuzzer_name='libFuzzer_test_fuzzer', |
| 329 | + uworker_env={}) |
| 330 | + |
| 331 | + corpus_pruning_task.utask_main(uworker_input) |
| 332 | + self.assertEqual(self.quarantine_call_count, 3) |
| 333 | + |
| 334 | + @patch('clusterfuzz._internal.system.shell.get_directory_file_count') |
| 335 | + def test_rsync_from_disk_when_quarantine_corpus_is_zero( |
| 336 | + self, mock_get_directory_file_count): |
| 337 | + """ |
| 338 | + do_corpus_pruning() calls rsync_from_disk() three times in total — twice |
| 339 | + with the minimized corpus and once with the quarantine corpus. The fix introduces |
| 340 | + a check to determine whether the quarantine corpus is empty before calling |
| 341 | + rsync_from_disk(), as this was not being verified anywhere in the control flow. |
| 342 | +
|
| 343 | + When the quarantine corpus is not empty, we expect rsync_from_disk() to be called |
| 344 | + three times. If the quarantine corpus is empty, we expect it to be called twice, as |
| 345 | + the fix ensures that the call to rsync_from_disk() is skipped. |
| 346 | + """ |
| 347 | + |
| 348 | + self.quarantine_call_count = 0 |
| 349 | + uworker_input = corpus_pruning_task.utask_preprocess( |
| 350 | + job_type='libfuzzer_asan_job', |
| 351 | + fuzzer_name='libFuzzer_test_fuzzer', |
| 352 | + uworker_env={}) |
| 353 | + |
| 354 | + mock_get_directory_file_count.return_value = 0 |
| 355 | + |
| 356 | + corpus_pruning_task.utask_main(uworker_input) |
| 357 | + self.assertEqual(self.quarantine_call_count, 2) |
| 358 | + |
310 | 359 |
|
311 | 360 | class CorpusPruningTestMinijail(CorpusPruningTest):
|
312 | 361 | """Tests for corpus pruning (minijail)."""
|
|
0 commit comments