| #!/usr/bin/env python3 |
| # -*- coding: utf-8 -*- |
| # Copyright 2020 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Unit tests for git helper functions.""" |
| |
| from __future__ import print_function |
| |
| import os |
| import subprocess |
| import unittest |
| import unittest.mock as mock |
| |
| import git |
| |
| # These are unittests; protected access is OK to a point. |
| # pylint: disable=protected-access |
| |
| |
| class HelperFunctionsTest(unittest.TestCase): |
| """Test class for updating LLVM hashes of packages.""" |
| |
| @mock.patch.object(os.path, 'isdir', return_value=False) |
| def testFailedToCreateBranchForInvalidDirectoryPath(self, mock_isdir): |
| path_to_repo = '/invalid/path/to/repo' |
| branch = 'branch-name' |
| |
| # Verify the exception is raised when provided an invalid directory path. |
| with self.assertRaises(ValueError) as err: |
| git.CreateBranch(path_to_repo, branch) |
| |
| self.assertEqual( |
| str(err.exception), |
| 'Invalid directory path provided: %s' % path_to_repo) |
| |
| mock_isdir.assert_called_once() |
| |
| @mock.patch.object(os.path, 'isdir', return_value=True) |
| @mock.patch.object(subprocess, 'check_output', return_value=None) |
| def testSuccessfullyCreatedBranch(self, mock_command_output, mock_isdir): |
| path_to_repo = '/path/to/repo' |
| branch = 'branch-name' |
| |
| git.CreateBranch(path_to_repo, branch) |
| |
| mock_isdir.assert_called_once_with(path_to_repo) |
| |
| self.assertEqual(mock_command_output.call_count, 2) |
| |
| @mock.patch.object(os.path, 'isdir', return_value=False) |
| def testFailedToDeleteBranchForInvalidDirectoryPath(self, mock_isdir): |
| path_to_repo = '/invalid/path/to/repo' |
| branch = 'branch-name' |
| |
| # Verify the exception is raised on an invalid repo path. |
| with self.assertRaises(ValueError) as err: |
| git.DeleteBranch(path_to_repo, branch) |
| |
| self.assertEqual( |
| str(err.exception), |
| 'Invalid directory path provided: %s' % path_to_repo) |
| |
| mock_isdir.assert_called_once() |
| |
| @mock.patch.object(os.path, 'isdir', return_value=True) |
| @mock.patch.object(subprocess, 'check_output', return_value=None) |
| def testSuccessfullyDeletedBranch(self, mock_command_output, mock_isdir): |
| path_to_repo = '/valid/path/to/repo' |
| branch = 'branch-name' |
| |
| git.DeleteBranch(path_to_repo, branch) |
| |
| mock_isdir.assert_called_once_with(path_to_repo) |
| |
| self.assertEqual(mock_command_output.call_count, 3) |
| |
| @mock.patch.object(os.path, 'isdir', return_value=False) |
| def testFailedToUploadChangesForInvalidDirectoryPath(self, mock_isdir): |
| path_to_repo = '/some/path/to/repo' |
| branch = 'update-LLVM_NEXT_HASH-a123testhash3' |
| commit_messages = ['Test message'] |
| |
| # Verify exception is raised when on an invalid repo path. |
| with self.assertRaises(ValueError) as err: |
| git.UploadChanges(path_to_repo, branch, commit_messages) |
| |
| self.assertEqual( |
| str(err.exception), 'Invalid path provided: %s' % path_to_repo) |
| |
| mock_isdir.assert_called_once() |
| |
| @mock.patch.object(os.path, 'isdir', return_value=True) |
| @mock.patch.object(subprocess, 'check_output', return_value=None) |
| @mock.patch.object(subprocess, 'Popen') |
| def testFailedToUploadChangesForReview(self, mock_repo_upload, |
| mock_command_output, mock_isdir): |
| |
| # Simulate the behavior of 'subprocess.Popen()' when uploading the changes |
| # for review |
| # |
| # `Popen.communicate()` returns a tuple of `stdout` and `stderr`. |
| mock_repo_upload.return_value.communicate.return_value = ( |
| None, 'Branch does not exist.') |
| |
| # Exit code of 1 means failed to upload changes for review. |
| mock_repo_upload.return_value.returncode = 1 |
| |
| path_to_repo = '/some/path/to/repo' |
| branch = 'invalid-branch-name' |
| commit_messages = ['Test message'] |
| |
| # Verify exception is raised when failed to upload the changes for review. |
| with self.assertRaises(ValueError) as err: |
| git.UploadChanges(path_to_repo, branch, commit_messages) |
| |
| self.assertEqual(str(err.exception), 'Failed to upload changes for review') |
| |
| mock_isdir.assert_called_once_with(path_to_repo) |
| |
| mock_command_output.assert_called_once() |
| mock_command_output_args = mock_command_output.call_args_list[0][0][0] |
| expected_mock_command_output_prefix = ['git', 'commit', '-F'] |
| self.assertEqual( |
| mock_command_output_args[:len(expected_mock_command_output_prefix)], |
| expected_mock_command_output_prefix) |
| |
| mock_repo_upload.assert_called_once() |
| |
| @mock.patch.object(os.path, 'isdir', return_value=True) |
| @mock.patch.object(subprocess, 'check_output', return_value=None) |
| @mock.patch.object(subprocess, 'Popen') |
| def testSuccessfullyUploadedChangesForReview(self, mock_repo_upload, |
| mock_command_output, mock_isdir): |
| |
| # A test CL generated by `repo upload`. |
| repo_upload_contents = ('remote: https://chromium-review.googlesource.' |
| 'com/c/chromiumos/overlays/chromiumos-overlay/' |
| '+/193147 Fix stdout') |
| |
| # Simulate the behavior of 'subprocess.Popen()' when uploading the changes |
| # for review |
| # |
| # `Popen.communicate()` returns a tuple of `stdout` and `stderr`. |
| mock_repo_upload.return_value.communicate.return_value = ( |
| repo_upload_contents, None) |
| |
| # Exit code of 0 means successfully uploaded changes for review. |
| mock_repo_upload.return_value.returncode = 0 |
| |
| path_to_repo = '/some/path/to/repo' |
| branch = 'branch-name' |
| commit_messages = ['Test message'] |
| |
| change_list = git.UploadChanges(path_to_repo, branch, commit_messages) |
| |
| self.assertEqual( |
| change_list.url, |
| 'https://chromium-review.googlesource.com/c/chromiumos/overlays/' |
| 'chromiumos-overlay/+/193147') |
| |
| self.assertEqual(change_list.cl_number, 193147) |
| |
| mock_isdir.assert_called_once_with(path_to_repo) |
| |
| mock_command_output.assert_called_once() |
| |
| mock_repo_upload.assert_called_once() |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |