File: run_all_fuzzers_test.py

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (128 lines) | stat: -rw-r--r-- 5,059 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# 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()