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