| # Copyright 2023 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| import os |
| import pathlib |
| import shutil |
| import subprocess |
| import tempfile |
| import unittest |
| import sys |
| |
| |
| class RunAllFuzzersTest(unittest.TestCase): |
| @classmethod |
| def setUpClass(cls): |
| if sys.platform != 'linux': |
| return |
| gn_args = ('use_clang_coverage=true ' |
| 'dcheck_always_on=true ' |
| 'ffmpeg_branding=\"ChromeOS\" ' |
| 'is_component_build=true ' |
| 'is_debug=false ' |
| 'proprietary_codecs=true ' |
| 'use_reclient=true ' |
| 'use_libfuzzer=true') |
| cls.testfuzzer1 = 'xml_parser_fuzzer' |
| cls.testfuzzer2 = 'query_parser_fuzzer' |
| cls.chromium_src_dir = os.path.join( |
| os.path.abspath(os.path.dirname(__file__)), "..", "..") |
| fuzzer_binaries_dir = "out/run_all_fuzzers_test" |
| pathlib.Path(fuzzer_binaries_dir).mkdir(parents=True, exist_ok=True) |
| cls.fuzzer_binaries_dir = fuzzer_binaries_dir |
| cls.fuzzer_corpora_dir = tempfile.mkdtemp() |
| cls.profdata_outdir = tempfile.mkdtemp() |
| os.mkdir(os.path.join(cls.fuzzer_corpora_dir, cls.testfuzzer1)) |
| corporadir1 = os.path.join(cls.fuzzer_corpora_dir, cls.testfuzzer1) |
| os.mkdir(os.path.join(cls.fuzzer_corpora_dir, cls.testfuzzer2)) |
| corporadir2 = os.path.join(cls.fuzzer_corpora_dir, cls.testfuzzer2) |
| for letter in ["a", "b", "c", "d"]: |
| f1 = open(os.path.join(corporadir1, letter), "x") |
| f2 = open(os.path.join(corporadir2, letter), "x") |
| f1.write(letter) |
| f2.write(letter) |
| f1.close() |
| f2.close() |
| gn_gen_cmd = ['gn', 'gen', cls.fuzzer_binaries_dir, '--args=%s' % gn_args] |
| try: |
| subprocess.check_output(gn_gen_cmd, cwd=cls.chromium_src_dir) |
| except subprocess.CalledProcessError as e: |
| print("GN command failed. Error:") |
| print(e.output) |
| build_cmd = [ |
| 'autoninja', '-C', cls.fuzzer_binaries_dir, cls.testfuzzer1, |
| cls.testfuzzer2 |
| ] |
| with open("test.log", "wb") as f: |
| try: |
| process = subprocess.Popen(build_cmd, |
| cwd=cls.chromium_src_dir, |
| stdout=subprocess.PIPE) |
| for c in iter(lambda: process.stdout.read(1), b''): |
| f.write(c) |
| except subprocess.CalledProcessError as e: |
| print("Build command failed. Error:") |
| print(e.output) |
| |
| @classmethod |
| def tearDownClass(cls): |
| if sys.platform != 'linux': |
| return |
| # ignore_errors allows us to delete the directory even though the directory |
| # is non-empty. This is what we want, since we created these temporarily, |
| # only for the purpose of tests. |
| shutil.rmtree(cls.fuzzer_binaries_dir, ignore_errors=True) |
| shutil.rmtree(cls.fuzzer_corpora_dir, ignore_errors=True) |
| shutil.rmtree(cls.profdata_outdir, ignore_errors=True) |
| |
| def test_wrong_arguments(self): |
| if sys.platform != 'linux': |
| return |
| cmd = [ |
| 'python3', 'tools/code_coverage/run_all_fuzzers.py', |
| '--fuzzer-binaries-dir', self.__class__.fuzzer_binaries_dir, |
| '--fuzzer-corpora-dir', self.__class__.fuzzer_corpora_dir |
| ] |
| with self.assertRaises(subprocess.CalledProcessError) as e: |
| subprocess.check_call(cmd, cwd=self.__class__.chromium_src_dir) |
| assert ("returned non-zero exit status 2" in str(e.exception)) |
| cmd = [ |
| 'python3', 'tools/code_coverage/run_all_fuzzers.py', |
| '--fuzzer-binaries-dir', self.__class__.fuzzer_binaries_dir, |
| '--profdata-outdir', self.__class__.profdata_outdir |
| ] |
| with self.assertRaises(subprocess.CalledProcessError) as e: |
| subprocess.check_call(cmd, cwd=self.__class__.chromium_src_dir) |
| assert ("returned non-zero exit status 2" in str(e.exception)) |
| cmd = [ |
| 'python3', 'tools/code_coverage/run_all_fuzzers.py', |
| '--fuzzer-corpora-dir', self.__class__.fuzzer_corpora_dir, |
| '--profdata-outdir', self.__class__.profdata_outdir |
| ] |
| with self.assertRaises(subprocess.CalledProcessError) as e: |
| subprocess.check_call(cmd, cwd=self.__class__.chromium_src_dir) |
| assert ("returned non-zero exit status 2" in str(e.exception)) |
| |
| def test_all_fuzzers_succeed(self): |
| if sys.platform != 'linux': |
| return |
| cmd = [ |
| 'python3', 'tools/code_coverage/run_all_fuzzers.py', |
| '--fuzzer-binaries-dir', self.__class__.fuzzer_binaries_dir, |
| '--fuzzer-corpora-dir', self.__class__.fuzzer_corpora_dir, |
| '--profdata-outdir', self.__class__.profdata_outdir |
| ] |
| subprocess.check_call(cmd, cwd=self.__class__.chromium_src_dir) |
| |
| expected_profdata = sorted([ |
| self.__class__.testfuzzer1 + ".profraw", |
| self.__class__.testfuzzer2 + ".profraw" |
| ]) |
| actual_profdata = sorted(os.listdir(self.__class__.profdata_outdir)) |
| assert ( |
| expected_profdata == actual_profdata |
| ), "Expected " + str(expected_profdata) + " but got " + str(actual_profdata) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |