1# Copyright 2019 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"""Test the functionality of the RepoManager class.""" 15 16import contextlib 17import os 18import tempfile 19import unittest 20from unittest import mock 21 22import repo_manager 23import utils 24 25# pylint: disable=protected-access 26 27OSS_FUZZ_REPO_URL = 'https://github.com/google/oss-fuzz' 28 29 30@contextlib.contextmanager 31def get_oss_fuzz_repo(): 32 """Clones a temporary copy of the OSS-Fuzz repo. Returns the path to the 33 repo.""" 34 repo_name = 'oss-fuzz' 35 with tempfile.TemporaryDirectory() as tmp_dir: 36 repo_manager._clone(OSS_FUZZ_REPO_URL, tmp_dir, repo_name) 37 yield os.path.join(tmp_dir, repo_name) 38 39 40class CloneTest(unittest.TestCase): 41 """Tests the _clone function.""" 42 43 @unittest.skipIf(not os.getenv('INTEGRATION_TESTS'), 44 'INTEGRATION_TESTS=1 not set') 45 def test_clone_valid_repo_integration(self): 46 """Integration test that tests the correct location of the git repo.""" 47 with get_oss_fuzz_repo() as oss_fuzz_repo: 48 git_path = os.path.join(oss_fuzz_repo, '.git') 49 self.assertTrue(os.path.isdir(git_path)) 50 51 def test_clone_invalid_repo(self): 52 """Tests that cloning an invalid repo will fail.""" 53 with tempfile.TemporaryDirectory() as tmp_dir: 54 with self.assertRaises(RuntimeError): 55 repo_manager._clone('https://github.com/oss-fuzz-not-real.git', tmp_dir, 56 'oss-fuzz') 57 58 59@unittest.skipIf(not os.getenv('INTEGRATION_TESTS'), 60 'INTEGRATION_TESTS=1 not set') 61class RepoManagerCheckoutTest(unittest.TestCase): 62 """Tests the checkout functionality of RepoManager.""" 63 64 def test_checkout_valid_commit(self): 65 """Tests that the git checkout command works.""" 66 with get_oss_fuzz_repo() as oss_fuzz_repo: 67 repo_man = repo_manager.RepoManager(oss_fuzz_repo) 68 commit_to_test = '04ea24ee15bbe46a19e5da6c5f022a2ffdfbdb3b' 69 repo_man.checkout_commit(commit_to_test) 70 self.assertEqual(commit_to_test, repo_man.get_current_commit()) 71 72 def test_checkout_invalid_commit(self): 73 """Tests that the git checkout invalid commit fails.""" 74 with get_oss_fuzz_repo() as oss_fuzz_repo: 75 repo_man = repo_manager.RepoManager(oss_fuzz_repo) 76 with self.assertRaises(ValueError): 77 repo_man.checkout_commit(' ') 78 with self.assertRaises(ValueError): 79 repo_man.checkout_commit('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') 80 with self.assertRaises(ValueError): 81 repo_man.checkout_commit('not-a-valid-commit') 82 83 84@unittest.skipIf(not os.getenv('INTEGRATION_TESTS'), 85 'INTEGRATION_TESTS=1 not set') 86class RepoManagerGetCommitListTest(unittest.TestCase): 87 """Tests the get_commit_list method of RepoManager.""" 88 89 def test_get_valid_commit_list(self): 90 """Tests an accurate commit list can be retrieved from the repo manager.""" 91 with get_oss_fuzz_repo() as oss_fuzz_repo: 92 repo_man = repo_manager.RepoManager(oss_fuzz_repo) 93 old_commit = '04ea24ee15bbe46a19e5da6c5f022a2ffdfbdb3b' 94 new_commit = 'fa662173bfeb3ba08d2e84cefc363be11e6c8463' 95 commit_list = [ 96 'fa662173bfeb3ba08d2e84cefc363be11e6c8463', 97 '17035317a44fa89d22fe6846d868d4bf57def78b', 98 '97dee00a3c4ce95071c3e061592f5fd577dea886', 99 '04ea24ee15bbe46a19e5da6c5f022a2ffdfbdb3b' 100 ] 101 result_list = repo_man.get_commit_list(new_commit, old_commit) 102 self.assertListEqual(commit_list, result_list) 103 104 def test_get_invalid_commit_list(self): 105 """Tests that the proper errors are thrown when invalid commits are 106 passed to get_commit_list.""" 107 with get_oss_fuzz_repo() as oss_fuzz_repo: 108 repo_man = repo_manager.RepoManager(oss_fuzz_repo) 109 old_commit = '04ea24ee15bbe46a19e5da6c5f022a2ffdfbdb3b' 110 new_commit = 'fa662173bfeb3ba08d2e84cefc363be11e6c8463' 111 with self.assertRaises(ValueError): 112 repo_man.get_commit_list('fakecommit', new_commit) 113 with self.assertRaises(ValueError): 114 repo_man.get_commit_list(new_commit, 'fakecommit') 115 with self.assertRaises(RuntimeError): 116 repo_man.get_commit_list(old_commit, new_commit) # pylint: disable=arguments-out-of-order 117 118 119@unittest.skipIf(not os.getenv('INTEGRATION_TESTS'), 120 'INTEGRATION_TESTS=1 not set') 121class GitDiffTest(unittest.TestCase): 122 """Tests get_git_diff.""" 123 124 def test_diff_exists(self): 125 """Tests that a real diff is returned when a valid repo manager exists.""" 126 with get_oss_fuzz_repo() as oss_fuzz_repo: 127 repo_man = repo_manager.RepoManager(oss_fuzz_repo) 128 with mock.patch.object(utils, 129 'execute', 130 return_value=('test.py\ndiff.py', None, 0)): 131 diff = repo_man.get_git_diff() 132 self.assertCountEqual(diff, ['test.py', 'diff.py']) 133 134 def test_diff_empty(self): 135 """Tests that None is returned when there is no difference between repos.""" 136 with get_oss_fuzz_repo() as oss_fuzz_repo: 137 repo_man = repo_manager.RepoManager(oss_fuzz_repo) 138 with mock.patch.object(utils, 'execute', return_value=('', None, 0)): 139 diff = repo_man.get_git_diff() 140 self.assertIsNone(diff) 141 142 def test_error_on_command(self): 143 """Tests that None is returned when the command errors out.""" 144 with get_oss_fuzz_repo() as oss_fuzz_repo: 145 repo_man = repo_manager.RepoManager(oss_fuzz_repo) 146 with mock.patch.object(utils, 147 'execute', 148 return_value=('', 'Test error.', 1)): 149 diff = repo_man.get_git_diff() 150 self.assertIsNone(diff) 151 152 def test_diff_no_change(self): 153 """Tests that None is returned when there is no difference between repos.""" 154 with get_oss_fuzz_repo() as oss_fuzz_repo: 155 repo_man = repo_manager.RepoManager(oss_fuzz_repo) 156 diff = repo_man.get_git_diff() 157 self.assertIsNone(diff) 158 159 160@unittest.skipIf(not os.getenv('INTEGRATION_TESTS'), 161 'INTEGRATION_TESTS=1 not set') 162class CheckoutPrIntegrationTest(unittest.TestCase): 163 """Does Integration tests on the checkout_pr method of RepoManager.""" 164 165 def test_pull_request_exists(self): 166 """Tests that a diff is returned when a valid PR is checked out.""" 167 with get_oss_fuzz_repo() as oss_fuzz_repo: 168 repo_man = repo_manager.RepoManager(oss_fuzz_repo) 169 repo_man.checkout_pr('refs/pull/3415/merge') 170 diff = repo_man.get_git_diff() 171 self.assertCountEqual(diff, ['README.md']) 172 173 def test_checkout_invalid_pull_request(self): 174 """Tests that the git checkout invalid pull request fails.""" 175 with get_oss_fuzz_repo() as oss_fuzz_repo: 176 repo_man = repo_manager.RepoManager(oss_fuzz_repo) 177 with self.assertRaises(RuntimeError): 178 repo_man.checkout_pr(' ') 179 with self.assertRaises(RuntimeError): 180 repo_man.checkout_pr('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') 181 with self.assertRaises(RuntimeError): 182 repo_man.checkout_pr('not/a/valid/pr') 183 184 185if __name__ == '__main__': 186 unittest.main() 187