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"""Module for getting the configuration CIFuzz needs to run.""" 15import os 16import unittest 17from unittest import mock 18 19import config_utils 20import constants 21import test_helpers 22 23# pylint: disable=no-self-use,protected-access 24 25 26class BaseConfigTest(unittest.TestCase): 27 """Tests for BaseConfig.""" 28 29 def setUp(self): 30 test_helpers.patch_environ(self) 31 32 def _create_config(self): 33 return config_utils.BuildFuzzersConfig() 34 35 def test_language_default(self): 36 """Tests that the correct default language is set.""" 37 config = self._create_config() 38 self.assertEqual(config.language, 'c++') 39 40 def test_language(self): 41 """Tests that the correct language is set.""" 42 language = 'python' 43 os.environ['LANGUAGE'] = language 44 config = self._create_config() 45 self.assertEqual(config.language, language) 46 47 def test_is_coverage(self): 48 """Tests that is_coverage is set correctly.""" 49 # Test it is set when it is supposed to be. 50 os.environ['SANITIZER'] = 'coverage' 51 config = self._create_config() 52 self.assertTrue(config.is_coverage) 53 54 # Test it is not set when it is not supposed to be. 55 os.environ['SANITIZER'] = 'address' 56 config = self._create_config() 57 self.assertFalse(config.is_coverage) 58 59 @mock.patch('logging.error') 60 def test_validate_no_workspace(self, mock_error): 61 """Tests that validate returns False if GITHUB_WORKSPACE isn't set.""" 62 os.environ['OSS_FUZZ_PROJECT_NAME'] = 'example' 63 config = self._create_config() 64 self.assertFalse(config.validate()) 65 mock_error.assert_called_with('Must set WORKSPACE.') 66 67 @mock.patch('logging.error') 68 def test_validate_invalid_language(self, mock_error): 69 """Tests that validate returns False if GITHUB_WORKSPACE isn't set.""" 70 os.environ['OSS_FUZZ_PROJECT_NAME'] = 'example' 71 os.environ['WORKSPACE'] = '/workspace' 72 os.environ['LANGUAGE'] = 'invalid-language' 73 config = self._create_config() 74 self.assertFalse(config.validate()) 75 mock_error.assert_called_with('Invalid LANGUAGE: %s. Must be one of: %s.', 76 os.environ['LANGUAGE'], constants.LANGUAGES) 77 78 @mock.patch('logging.error') 79 def test_validate_invalid_sanitizer(self, mock_error): 80 """Tests that validate returns False if GITHUB_WORKSPACE isn't set.""" 81 os.environ['OSS_FUZZ_PROJECT_NAME'] = 'example' 82 os.environ['WORKSPACE'] = '/workspace' 83 os.environ['SANITIZER'] = 'invalid-sanitizer' 84 config = self._create_config() 85 self.assertFalse(config.validate()) 86 mock_error.assert_called_with('Invalid SANITIZER: %s. Must be one of: %s.', 87 os.environ['SANITIZER'], 88 config_utils.SANITIZERS) 89 90 def test_validate(self): 91 """Tests that validate returns True if config is valid.""" 92 os.environ['OSS_FUZZ_PROJECT_NAME'] = 'example' 93 os.environ['WORKSPACE'] = '/workspace' 94 config = self._create_config() 95 self.assertTrue(config.validate()) 96 97 98class BuildFuzzersConfigTest(unittest.TestCase): 99 """Tests for BuildFuzzersConfig.""" 100 101 def setUp(self): 102 test_helpers.patch_environ(self) 103 104 def _create_config(self): 105 return config_utils.BuildFuzzersConfig() 106 107 def test_base_ref(self): 108 """Tests that base_ref is set properly.""" 109 expected_base_ref = 'expected_base_ref' 110 os.environ['GITHUB_BASE_REF'] = expected_base_ref 111 config = self._create_config() 112 self.assertEqual(config.base_ref, expected_base_ref) 113 114 def test_keep_unaffected_defaults_to_true(self): 115 """Tests that keep_unaffected_fuzz_targets defaults to true.""" 116 config = self._create_config() 117 self.assertTrue(config.keep_unaffected_fuzz_targets) 118 119 def test_keep_unaffected_defaults_to_false_when_pr(self): 120 """Tests that keep_unaffected_fuzz_targets defaults to false when from a 121 pr.""" 122 os.environ['GITHUB_BASE_REF'] = 'base-ref' 123 config = self._create_config() 124 self.assertFalse(config.keep_unaffected_fuzz_targets) 125 126 127class RunFuzzersConfigTest(unittest.TestCase): 128 """Tests for RunFuzzersConfig.""" 129 130 def setUp(self): 131 test_helpers.patch_environ(self) 132 133 def _create_config(self): 134 return config_utils.RunFuzzersConfig() 135 136 def test_coverage(self): 137 """Tests that run_fuzzers_mode is overriden properly based on 138 is_coverage.""" 139 # Test that it is overriden when it is supposed to be. 140 os.environ['SANITIZER'] = 'coverage' 141 os.environ['RUN_FUZZERS_MODE'] = 'ci' 142 config = self._create_config() 143 self.assertEqual(config.run_fuzzers_mode, 'coverage') 144 145 # Test that it isn't overriden when it isn't supposed to be. 146 os.environ['SANITIZER'] = 'address' 147 run_fuzzers_mode = 'ci' 148 os.environ['RUN_FUZZERS_MODE'] = run_fuzzers_mode 149 config = self._create_config() 150 self.assertEqual(config.run_fuzzers_mode, run_fuzzers_mode) 151 152 def test_run_config_validate(self): 153 """Tests that _run_config_validate returns True when the config is valid.""" 154 self.assertTrue(self._create_config()._run_config_validate()) 155 156 @mock.patch('logging.error') 157 def test_run_config_invalid_mode(self, mock_error): 158 """Tests that _run_config_validate returns False when run_fuzzers_mode is 159 invalid.""" 160 fake_mode = 'fake-mode' 161 os.environ['RUN_FUZZERS_MODE'] = fake_mode 162 self.assertFalse(self._create_config()._run_config_validate()) 163 mock_error.assert_called_with( 164 'Invalid RUN_FUZZERS_MODE: %s. Must be one of %s.', fake_mode, 165 config_utils.RUN_FUZZERS_MODES) 166 167 168class GetProjectRepoOwnerAndNameTest(unittest.TestCase): 169 """Tests for BaseCiEnv.get_project_repo_owner_and_name.""" 170 171 def setUp(self): 172 test_helpers.patch_environ(self) 173 self.repo_owner = 'repo-owner' 174 self.repo_name = 'repo-name' 175 self.github_env = config_utils.GithubEnvironment() 176 self.generic_ci_env = config_utils.GenericCiEnvironment() 177 178 def test_unset_repository(self): 179 """Tests that the correct result is returned when repository is not set.""" 180 self.assertEqual(self.generic_ci_env.project_repo_owner_and_name, 181 (None, None)) 182 183 def test_empty_repository(self): 184 """Tests that the correct result is returned when repository is an empty 185 string.""" 186 os.environ['REPOSITORY'] = '' 187 self.assertEqual(self.generic_ci_env.project_repo_owner_and_name, 188 (None, '')) 189 190 def test_github_repository(self): 191 """Tests that the correct result is returned when repository contains the 192 owner and repo name (as it does on GitHub).""" 193 os.environ['GITHUB_REPOSITORY'] = f'{self.repo_owner}/{self.repo_name}' 194 self.assertEqual(self.github_env.project_repo_owner_and_name, 195 (self.repo_owner, self.repo_name)) 196 197 def test_nongithub_repository(self): 198 """Tests that the correct result is returned when repository contains the 199 just the repo name (as it does outside of GitHub).""" 200 os.environ['REPOSITORY'] = self.repo_name 201 self.assertEqual(self.generic_ci_env.project_repo_owner_and_name, 202 (None, self.repo_name)) 203 204 205class GetSanitizerTest(unittest.TestCase): 206 """Tests for _get_sanitizer.""" 207 208 def setUp(self): 209 test_helpers.patch_environ(self) 210 self.sanitizer = 'memory' 211 212 def test_default_value(self): 213 """Tests that the default value returned by _get_sanitizer is correct.""" 214 self.assertEqual(config_utils._get_sanitizer(), 'address') 215 216 def test_normal_case(self): 217 """Tests that _get_sanitizer returns the correct value in normal cases.""" 218 os.environ['SANITIZER'] = self.sanitizer 219 self.assertEqual(config_utils._get_sanitizer(), self.sanitizer) 220 221 def test_capitalization(self): 222 """Tests that that _get_sanitizer handles capitalization properly.""" 223 os.environ['SANITIZER'] = self.sanitizer.upper() 224 self.assertEqual(config_utils._get_sanitizer(), self.sanitizer) 225 226 227class ProjectSrcPathTest(unittest.TestCase): 228 """Tests for project_src_path.""" 229 230 def setUp(self): 231 test_helpers.patch_environ(self) 232 self.workspace = '/workspace' 233 os.environ['GITHUB_WORKSPACE'] = self.workspace 234 235 self.project_src_dir_name = 'project-src' 236 237 def test_unset(self): 238 """Tests that project_src_path returns None when no PROJECT_SRC_PATH is 239 set.""" 240 github_env = config_utils.GithubEnvironment() 241 self.assertIsNone(github_env.project_src_path) 242 243 def test_github(self): 244 """Tests that project_src_path returns the correct result on GitHub.""" 245 os.environ['PROJECT_SRC_PATH'] = self.project_src_dir_name 246 expected_project_src_path = os.path.join(self.workspace, 247 self.project_src_dir_name) 248 github_env = config_utils.GithubEnvironment() 249 self.assertEqual(github_env.project_src_path, expected_project_src_path) 250 251 def test_not_github(self): 252 """Tests that project_src_path returns the correct result not on 253 GitHub.""" 254 project_src_path = os.path.join('/', self.project_src_dir_name) 255 os.environ['PROJECT_SRC_PATH'] = project_src_path 256 generic_ci_env = config_utils.GenericCiEnvironment() 257 self.assertEqual(generic_ci_env.project_src_path, project_src_path) 258 259 260if __name__ == '__main__': 261 unittest.main() 262