• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2021 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Tests for helper.py"""
15
16import datetime
17import os
18import tempfile
19import unittest
20from unittest import mock
21
22from pyfakefs import fake_filesystem_unittest
23
24import constants
25import helper
26import templates
27
28# pylint: disable=no-self-use,protected-access
29
30
31class ShellTest(unittest.TestCase):
32  """Tests 'shell' command."""
33
34  @mock.patch('helper.docker_run')
35  @mock.patch('helper.build_image_impl')
36  def test_base_runner_debug(self, _, __):
37    """Tests that shell base-runner-debug works as intended."""
38    image_name = 'base-runner-debug'
39    unparsed_args = ['shell', image_name]
40    parser = helper.get_parser()
41    args = helper.parse_args(parser, unparsed_args)
42    args.sanitizer = 'address'
43    result = helper.shell(args)
44    self.assertTrue(result)
45
46
47class BuildImageImplTest(unittest.TestCase):
48  """Tests for build_image_impl."""
49
50  @mock.patch('helper.docker_build')
51  def test_no_cache(self, mock_docker_build):
52    """Tests that cache=False is handled properly."""
53    image_name = 'base-image'
54    helper.build_image_impl(helper.Project(image_name), cache=False)
55    self.assertIn('--no-cache', mock_docker_build.call_args_list[0][0][0])
56
57  @mock.patch('helper.docker_build')
58  @mock.patch('helper.pull_images')
59  def test_pull(self, mock_pull_images, _):
60    """Tests that pull=True is handled properly."""
61    image_name = 'base-image'
62    project = helper.Project(image_name, is_external=True)
63    self.assertTrue(helper.build_image_impl(project, pull=True))
64    mock_pull_images.assert_called_with('c++')
65
66  @mock.patch('helper.docker_build')
67  def test_base_image(self, mock_docker_build):
68    """Tests that build_image_impl works as intended with a base-image."""
69    image_name = 'base-image'
70    self.assertTrue(helper.build_image_impl(helper.Project(image_name)))
71    build_dir = os.path.join(helper.OSS_FUZZ_DIR,
72                             'infra/base-images/base-image')
73    mock_docker_build.assert_called_with([
74        '-t', 'gcr.io/oss-fuzz-base/base-image', '--file',
75        os.path.join(build_dir, 'Dockerfile'), build_dir
76    ])
77
78  @mock.patch('helper.docker_build')
79  def test_oss_fuzz_project(self, mock_docker_build):
80    """Tests that build_image_impl works as intended with an OSS-Fuzz
81    project."""
82    project_name = 'example'
83    self.assertTrue(helper.build_image_impl(helper.Project(project_name)))
84    build_dir = os.path.join(helper.OSS_FUZZ_DIR, 'projects', project_name)
85    mock_docker_build.assert_called_with([
86        '-t', 'gcr.io/oss-fuzz/example', '--file',
87        os.path.join(build_dir, 'Dockerfile'), build_dir
88    ])
89
90  @mock.patch('helper.docker_build')
91  def test_external_project(self, mock_docker_build):
92    """Tests that build_image_impl works as intended with a non-OSS-Fuzz
93    project."""
94    with tempfile.TemporaryDirectory() as temp_dir:
95      project_src_path = os.path.join(temp_dir, 'example')
96      os.mkdir(project_src_path)
97      build_integration_path = 'build-integration'
98      project = helper.Project(project_src_path,
99                               is_external=True,
100                               build_integration_path=build_integration_path)
101      self.assertTrue(helper.build_image_impl(project))
102      mock_docker_build.assert_called_with([
103          '-t', 'gcr.io/oss-fuzz/example', '--file',
104          os.path.join(project_src_path, build_integration_path, 'Dockerfile'),
105          project_src_path
106      ])
107
108
109class GenerateImplTest(fake_filesystem_unittest.TestCase):
110  """Tests for _generate_impl."""
111  PROJECT_NAME = 'newfakeproject'
112  PROJECT_LANGUAGE = 'python'
113
114  def setUp(self):
115    self.setUpPyfakefs()
116    self.fs.add_real_directory(helper.OSS_FUZZ_DIR)
117
118  def _verify_templated_files(self, template_dict, directory, language):
119    template_args = {
120        'project_name': self.PROJECT_NAME,
121        'year': 2021,
122        'base_builder': helper._base_builder_from_language(language),
123        'language': language,
124    }
125    for filename, template in template_dict.items():
126      file_path = os.path.join(directory, filename)
127      with open(file_path, 'r') as file_handle:
128        contents = file_handle.read()
129      self.assertEqual(contents, template % template_args)
130
131  @mock.patch('helper._get_current_datetime',
132              return_value=datetime.datetime(year=2021, month=1, day=1))
133  def test_generate_oss_fuzz_project(self, _):
134    """Tests that the correct files are generated for an OSS-Fuzz project."""
135    helper._generate_impl(helper.Project(self.PROJECT_NAME),
136                          self.PROJECT_LANGUAGE)
137    self._verify_templated_files(
138        templates.TEMPLATES,
139        os.path.join(helper.OSS_FUZZ_DIR, 'projects', self.PROJECT_NAME),
140        self.PROJECT_LANGUAGE)
141
142  def test_generate_external_project(self):
143    """Tests that the correct files are generated for a non-OSS-Fuzz project."""
144    build_integration_path = '/newfakeproject/build-integration'
145    helper._generate_impl(
146        helper.Project('/newfakeproject/',
147                       is_external=True,
148                       build_integration_path=build_integration_path),
149        self.PROJECT_LANGUAGE)
150    self._verify_templated_files(templates.EXTERNAL_TEMPLATES,
151                                 build_integration_path, self.PROJECT_LANGUAGE)
152
153  def test_generate_swift_project(self):
154    """Tests that the swift project uses the correct base image."""
155    helper._generate_impl(helper.Project(self.PROJECT_NAME), 'swift')
156    self._verify_templated_files(
157        templates.TEMPLATES,
158        os.path.join(helper.OSS_FUZZ_DIR, 'projects', self.PROJECT_NAME),
159        'swift')
160
161
162class ProjectTest(fake_filesystem_unittest.TestCase):
163  """Tests for Project class."""
164
165  def setUp(self):
166    self.project_name = 'project'
167    self.internal_project = helper.Project(self.project_name)
168    self.external_project_path = os.path.join('/path', 'to', self.project_name)
169    self.external_project = helper.Project(self.external_project_path,
170                                           is_external=True)
171    self.setUpPyfakefs()
172
173  def test_init_external_project(self):
174    """Tests __init__ method for external projects."""
175    self.assertEqual(self.external_project.name, self.project_name)
176    self.assertEqual(self.external_project.path, self.external_project_path)
177    self.assertEqual(
178        self.external_project.build_integration_path,
179        os.path.join(self.external_project_path,
180                     constants.DEFAULT_EXTERNAL_BUILD_INTEGRATION_PATH))
181
182  def test_init_internal_project(self):
183    """Tests __init__ method for internal projects."""
184    self.assertEqual(self.internal_project.name, self.project_name)
185    path = os.path.join(helper.OSS_FUZZ_DIR, 'projects', self.project_name)
186    self.assertEqual(self.internal_project.path, path)
187    self.assertEqual(self.internal_project.build_integration_path, path)
188
189  def test_dockerfile_path_internal_project(self):
190    """Tests that dockerfile_path works as intended."""
191    self.assertEqual(
192        self.internal_project.dockerfile_path,
193        os.path.join(helper.OSS_FUZZ_DIR, 'projects', self.project_name,
194                     'Dockerfile'))
195
196  def test_dockerfile_path_external_project(self):
197    """Tests that dockerfile_path works as intended."""
198    self.assertEqual(
199        self.external_project.dockerfile_path,
200        os.path.join(self.external_project_path,
201                     constants.DEFAULT_EXTERNAL_BUILD_INTEGRATION_PATH,
202                     'Dockerfile'))
203
204  def test_out(self):
205    """Tests that out works as intended."""
206    out_dir = self.internal_project.out
207    self.assertEqual(
208        out_dir,
209        os.path.join(helper.OSS_FUZZ_DIR, 'build', 'out', self.project_name))
210    self.assertTrue(os.path.exists(out_dir))
211
212  def test_work(self):
213    """Tests that work works as intended."""
214    work_dir = self.internal_project.work
215    self.assertEqual(
216        work_dir,
217        os.path.join(helper.OSS_FUZZ_DIR, 'build', 'work', self.project_name))
218    self.assertTrue(os.path.exists(work_dir))
219
220  def test_corpus(self):
221    """Tests that corpus works as intended."""
222    corpus_dir = self.internal_project.corpus
223    self.assertEqual(
224        corpus_dir,
225        os.path.join(helper.OSS_FUZZ_DIR, 'build', 'corpus', self.project_name))
226    self.assertTrue(os.path.exists(corpus_dir))
227
228  def test_language_internal_project(self):
229    """Tests that language works as intended for an internal project."""
230    project_yaml_path = os.path.join(self.internal_project.path, 'project.yaml')
231    self.fs.create_file(project_yaml_path, contents='language: python')
232    self.assertEqual(self.internal_project.language, 'python')
233
234  def test_language_external_project(self):
235    """Tests that language works as intended for an external project."""
236    self.assertEqual(self.external_project.language, 'c++')
237