summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules/bluetooth/testing/clusterfuzz/fuzz_main_run.py
blob: d4f2f055f3873f3a7e78b3483f300bb134b0ae35 (plain)
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Script to generate Web Bluetooth web tests that can be run in ClusterFuzz.

This script uses templates in the templates/ directory to generate html files
that can be run as web tests. The script reads a template, includes files
necessary to run as a web test, fuzzes its parameters and saves the result in
a new file in the directory specified when running the script.
"""

import argparse
import glob
import os
import sys
import tempfile
import time

from fuzzer_helpers import FillInParameter
import parameter_fuzzer
import test_case_fuzzer

JS_FILES_AND_PARAMETERS = (
    ('testharness.js', 'INCLUDE_TESTHARNESS'),
    ('testharnessreport.js', 'INCLUDE_REPORT'),
    ('bluetooth-helpers.js', 'INCLUDE_BLUETOOTH_HELPERS'))

SCRIPT_PREFIX = '<script type="text/javascript">\n'
SCRIPT_SUFFIX = '\n</script>\n'


def _GetArguments():
    """Parses the arguments passed when running this script.

    Returns:
      An argparse.Namespace object containing the arguments in sys.argv.
    """
    parser = argparse.ArgumentParser()

    # Arguments used by ClusterFuzz:
    parser.add_argument('-n', '--no_of_files', type=int, required=True,
                        help='The number of test cases that the fuzzer is '
                             'expected to generate')
    parser.add_argument('-i', '--input_dir',
                        help='The directory containing the fuzzer\'s data '
                             'bundle.')
    parser.add_argument('-o', '--output_dir', required=True,
                        help='The directory where test case files should be '
                             'written to.')

    parser.add_argument('--content_shell_dir',
                        help='The directory of content shell. If present the '
                             'program will print a command to run the '
                             'generated test file.')

    return parser.parse_args()


def FuzzTemplate(template_path, resources_path):
    """Uses a template to return a test case that can be run as a web test.

    This functions reads the template in |template_path|, injects the necessary
    js files to run as a web test and fuzzes the template's parameters to
    generate a test case.

    Args:
      template_path: The path to the template that will be used to generate
          a new test case.
      resources_path: Path to the js files that need to be included.

    Returns:
      A string containing the test case.
    """
    print 'Generating test file based on {}'.format(template_path)

    # Read the template.
    template_file_handle = open(template_path)
    template_file_data = template_file_handle.read().decode('utf-8')
    template_file_handle.close()

    # Generate a test file based on the template.
    generated_test = test_case_fuzzer.GenerateTestFile(template_file_data)
    # Fuzz parameters.
    fuzzed_file_data = parameter_fuzzer.FuzzParameters(generated_test)

    # Add includes
    for (js_file_name, include_parameter) in JS_FILES_AND_PARAMETERS:
        # Read js file.
        js_file_handle = open(os.path.join(resources_path, js_file_name))
        js_file_data = js_file_handle.read()
        js_file_handle.close()

        js_file_data = (SCRIPT_PREFIX + js_file_data + SCRIPT_SUFFIX)

        fuzzed_file_data = FillInParameter(include_parameter,
                                           lambda data=js_file_data: data,
                                           fuzzed_file_data)

    return fuzzed_file_data.encode('utf-8')


def WriteTestFile(test_file_data, test_file_prefix, output_dir):
    """Creates a new file with a unique name and writes the test case to it.

    Args:
      test_file_data: The data to be included in the new file.
      test_file_prefix: Used as a prefix when generating a new file.
      output_dir: The directory where the new file should be created.

    Returns:
      A string representing the file path to access the new file.
    """

    file_descriptor, file_path = tempfile.mkstemp(
        prefix=test_file_prefix,
        suffix='.html',
        dir=output_dir)

    with os.fdopen(file_descriptor, 'wb') as output:
        print 'Writing {} bytes to \'{}\''.format(len(test_file_data),
                                                  file_path)
        output.write(test_file_data)

    return file_path


def main():
    args = _GetArguments()

    print 'Generating {} test file(s).'.format(args.no_of_files)
    print 'Writing test files to: \'{}\''.format(args.output_dir)
    if args.input_dir:
        print 'Reading data bundle from: \'{}\''.format(args.input_dir)

    # Get Templates
    current_path = os.path.dirname(os.path.realpath(__file__))
    available_templates = glob.glob(os.path.join(current_path,
                                                 'templates',
                                                 '*.html'))

    # Generate Test Files
    resources_path = os.path.join(current_path, 'resources')
    start_time = time.time()
    for file_no in range(args.no_of_files):
        template_path = available_templates[file_no % len(available_templates)]

        test_file_data = FuzzTemplate(template_path, resources_path)

        # Get Test File
        template_name = os.path.splitext(os.path.basename(template_path))[0]
        test_file_name = 'fuzz-{}-{}-{}'.format(template_name,
                                                int(start_time),
                                                int(file_no))

        test_file_path = WriteTestFile(test_file_data,
                                       test_file_name,
                                       args.output_dir)

        if args.content_shell_dir:
            print '{} --run-web-tests {}'.format(args.content_shell_dir,
                                                 test_file_path)


if __name__ == '__main__':
    sys.exit(main())