diff options
author | Salud Lemus <saludlemus@google.com> | 2019-09-10 13:00:27 -0700 |
---|---|---|
committer | Salud Lemus <saludlemus@google.com> | 2019-09-12 00:06:22 +0000 |
commit | 723eb0ff87880d5ce7ebc3697866b933e0aa7961 (patch) | |
tree | 4668d2775233f449b642d86d14bccd92b2ab5b2e /llvm_tools | |
parent | a7f8071ee3afaf3437603e8a66edf935a67f0728 (diff) | |
download | toolchain-utils-723eb0ff87880d5ce7ebc3697866b933e0aa7961.tar.gz |
LLVM tools: Updated unittest for llvm_patch_management.py
BUG=None
TEST='./llvm_patch_management_unittest.py' passes
Change-Id: I92c198ffefc51d0afa780de9e930a3db4260efbf
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/1795932
Reviewed-by: George Burgess <gbiv@chromium.org>
Reviewed-by: Manoj Gupta <manojgupta@chromium.org>
Tested-by: Salud Lemus <saludlemus@google.com>
Diffstat (limited to 'llvm_tools')
-rwxr-xr-x | llvm_tools/llvm_patch_management_unittest.py | 414 |
1 files changed, 138 insertions, 276 deletions
diff --git a/llvm_tools/llvm_patch_management_unittest.py b/llvm_tools/llvm_patch_management_unittest.py index 1456156d..c9bc7fce 100755 --- a/llvm_tools/llvm_patch_management_unittest.py +++ b/llvm_tools/llvm_patch_management_unittest.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright 2019 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be @@ -9,13 +9,12 @@ from __future__ import print_function from collections import namedtuple -import mock import os import unittest +import unittest.mock as mock -from cros_utils import command_executer from failure_modes import FailureModes -from test_helpers import CallCountsToMockFunctions +from get_llvm_hash import LLVMHash import llvm_patch_management import patch_manager @@ -23,64 +22,36 @@ import patch_manager class LlvmPatchManagementTest(unittest.TestCase): """Test class when constructing the arguments for the patch manager.""" - def testInvalidChrootPathWhenGetPathToFilesDir(self): + # Simulate the behavior of `os.path.isdir()` when the chroot path does not + # exist or is not a directory. + @mock.patch.object(os.path, 'isdir', return_value=False) + def testInvalidChrootPathWhenGetPathToFilesDir(self, mock_isdir): + chroot_path = '/some/path/to/chroot' + package = 'sys-devel/llvm' + # Verify the exception is raised when an invalid absolute path to the chroot # is passed in. with self.assertRaises(ValueError) as err: - llvm_patch_management.GetPathToFilesDirectory('/some/path/to/chroot', - 'sys-devel/llvm') - - self.assertEqual(err.exception.message, - 'Invalid chroot provided: /some/path/to/chroot') - - # Simulate the behavior of 'os.path.isdir()' when a valid chroot path is - # passed in. - @mock.patch.object(os.path, 'isdir', return_value=True) - @mock.patch.object(command_executer.CommandExecuter, - 'ChrootRunCommandWOutput') - def testFailedToGetChrootPathToEbuildWhenGetPathToFilesDir( - self, mock_chroot_cmd, mock_isdir): - - # Simulate behavior of 'ChrootRunCommandWOutput()' when failed to get the - # absolute chroot path to the package's ebuild. - # - # Returns shell error code, stdout, stderr. - mock_chroot_cmd.return_value = (1, None, 'Invalid package provided.') - - # Verify the exception is raised when failed to get the absolute chroot - # path to a package's ebuild. - with self.assertRaises(ValueError) as err: - llvm_patch_management.GetPathToFilesDirectory('/some/path/to/chroot', - 'test/package') + llvm_patch_management.GetPathToFilesDirectory(chroot_path, package) self.assertEqual( - err.exception.message, - 'Failed to get the absolute chroot path of the package ' - 'test/package: Invalid package provided.') - - mock_chroot_cmd.assert_called_once_with( - chromeos_root='/some/path/to/chroot', - command='equery w test/package', - print_to_console=False) + str(err.exception), 'Invalid chroot provided: %s' % chroot_path) mock_isdir.assert_called_once() # Simulate the behavior of 'os.path.isdir()' when a valid chroot path is # passed in. @mock.patch.object(os.path, 'isdir', return_value=True) - @mock.patch.object(command_executer.CommandExecuter, - 'ChrootRunCommandWOutput') + @mock.patch.object(llvm_patch_management, 'ChrootRunCommand') @mock.patch.object(llvm_patch_management, '_GetRelativePathOfChrootPath') def testSuccessfullyGetPathToFilesDir( self, mock_get_relative_path_of_chroot_path, mock_chroot_cmd, mock_isdir): - # Simulate behavior of 'ChrootRunCommandWOutput()' when successfully + package_chroot_path = '/mnt/host/source/path/to/llvm/llvm.ebuild' + + # Simulate behavior of 'ChrootRunCommand()' when successfully # retrieved the absolute chroot path to the package's ebuild. - # - # Returns shell error code, stdout, stderr. - mock_chroot_cmd.return_value = (0, - '/mnt/host/source/path/to/llvm/llvm.ebuild', - 0) + mock_chroot_cmd.return_value = package_chroot_path # Simulate behavior of '_GetRelativePathOfChrootPath()' when successfully # removed '/mnt/host/source' of the absolute chroot path to the package's @@ -89,9 +60,12 @@ class LlvmPatchManagementTest(unittest.TestCase): # Returns relative path after '/mnt/host/source/'. mock_get_relative_path_of_chroot_path.return_value = 'path/to/llvm' + chroot_path = '/some/path/to/chroot' + + package = 'sys-devel/llvm' + self.assertEqual( - llvm_patch_management.GetPathToFilesDirectory('/some/path/to/chroot', - 'sys-devel/llvm'), + llvm_patch_management.GetPathToFilesDirectory(chroot_path, package), '/some/path/to/chroot/path/to/llvm/files/') mock_isdir.assert_called_once() @@ -102,31 +76,40 @@ class LlvmPatchManagementTest(unittest.TestCase): '/mnt/host/source/path/to/llvm') def testInvalidPrefixForChrootPath(self): + package_chroot_path = '/path/to/llvm' + # Verify the exception is raised when the chroot path does not start with # '/mnt/host/source/'. with self.assertRaises(ValueError) as err: - llvm_patch_management._GetRelativePathOfChrootPath('/path/to/llvm') + llvm_patch_management._GetRelativePathOfChrootPath(package_chroot_path) - self.assertEqual(err.exception.message, - 'Invalid prefix for the chroot path: /path/to/llvm') + self.assertEqual( + str(err.exception), + 'Invalid prefix for the chroot path: %s' % package_chroot_path) def testValidPrefixForChrootPath(self): + package_chroot_path = '/mnt/host/source/path/to/llvm' + + package_rel_path = 'path/to/llvm' + self.assertEqual( - llvm_patch_management._GetRelativePathOfChrootPath( - '/mnt/host/source/path/to/llvm'), 'path/to/llvm') + llvm_patch_management._GetRelativePathOfChrootPath(package_chroot_path), + package_rel_path) # Simulate behavior of 'os.path.isfile()' when the patch metadata file does # not exist. @mock.patch.object(os.path, 'isfile', return_value=False) def testInvalidFileForPatchMetadataPath(self, mock_isfile): + abs_path_to_patch_file = '/abs/path/to/files/test.json' + # Verify the exception is raised when the absolute path to the patch # metadata file does not exist. with self.assertRaises(ValueError) as err: - llvm_patch_management._CheckPatchMetadataPath( - '/abs/path/to/files/test.json') + llvm_patch_management._CheckPatchMetadataPath(abs_path_to_patch_file) - self.assertEqual(err.exception.message, - 'Invalid file provided: /abs/path/to/files/test.json') + self.assertEqual( + str(err.exception), + 'Invalid file provided: %s' % abs_path_to_patch_file) mock_isfile.assert_called_once() @@ -134,262 +117,130 @@ class LlvmPatchManagementTest(unittest.TestCase): # patch metadata file exists. @mock.patch.object(os.path, 'isfile', return_value=True) def testPatchMetadataFileDoesNotEndInJson(self, mock_isfile): + abs_path_to_patch_file = '/abs/path/to/files/PATCHES' + # Verify the exception is raised when the patch metadata file does not end # in '.json'. with self.assertRaises(ValueError) as err: - llvm_patch_management._CheckPatchMetadataPath( - '/abs/path/to/files/PATCHES') + llvm_patch_management._CheckPatchMetadataPath(abs_path_to_patch_file) self.assertEqual( - err.exception.message, 'File does not end in \'.json\': ' - '/abs/path/to/files/PATCHES') + str(err.exception), + 'File does not end in ".json": %s' % abs_path_to_patch_file) mock_isfile.assert_called_once() @mock.patch.object(os.path, 'isfile') def testValidPatchMetadataFile(self, mock_isfile): + abs_path_to_patch_file = '/abs/path/to/files/PATCHES.json' + # Simulate behavior of 'os.path.isfile()' when the absolute path to the # patch metadata file exists. mock_isfile.return_value = True - llvm_patch_management._CheckPatchMetadataPath( - '/abs/path/to/files/PATCHES.json') + llvm_patch_management._CheckPatchMetadataPath(abs_path_to_patch_file) mock_isfile.assert_called_once() - @mock.patch.object(command_executer.CommandExecuter, - 'ChrootRunCommandWOutput') - def testFailedToUnpackPackage(self, mock_chroot_cmd): - # Simulate the behavior of 'ChrootRunCommandWOutput()' when unpacking fails - # on a package. - @CallCountsToMockFunctions - def MultipleCallsToGetSrcPath(call_count, - chromeos_root, - command, - print_to_console, - env=None): - - # First call to 'ChrootRunCommandWOutput()' which would successfully - # get the ebuild path of the package. - if call_count == 0: - # Returns shell error code, stdout, stderr. - return 0, '/mount/host/source/path/to/package/test-r1.ebuild', 0 - - # Second call to 'ChrootRunCommandWOutput()' which failed to unpack the - # package. - if call_count == 1: - # Returns shell error code, stdout, stderr. - return 1, None, 'Invalid package provided.' - - # 'ChrootRunCommandWOutput()' was called more times than expected (2 - # times). - assert False, ('Unexpectedly called more than 2 times.') - - # Use test function to simulate 'ChrootRunCommandWOutput()' behavior. - mock_chroot_cmd.side_effect = MultipleCallsToGetSrcPath - - # Verify the exception is raised when failed to unpack a package. - with self.assertRaises(ValueError) as err: - llvm_patch_management.UnpackLLVMPackage('/some/path/to/chroot', - 'test/package') - - self.assertEqual( - err.exception.message, 'Failed to unpack the package test/package: ' - 'Invalid package provided.') - - self.assertEqual(mock_chroot_cmd.call_count, 2) - - @mock.patch.object(command_executer.CommandExecuter, - 'ChrootRunCommandWOutput') - def testFailedToGetChrootPathToEbuild(self, mock_chroot_cmd): - # Simulate the behavior of 'ChrootRunCommandWOutput()' when failed to get - # the absolute chroot path to the package's ebuild. - mock_chroot_cmd.return_value = (1, None, 'Invalid package provided.') - - # Verify the exception is raised when failed to get the absolute chroot - # path to the package's ebuild. - with self.assertRaises(ValueError) as err: - llvm_patch_management.UnpackLLVMPackage('/some/path/to/chroot', - 'test/package') - - self.assertEqual( - err.exception.message, - 'Failed to get the absolute chroot path to the ebuild of ' - 'test/package: Invalid package provided.') - - mock_chroot_cmd.assert_called_once_with( - chromeos_root='/some/path/to/chroot', - command='equery w test/package', - print_to_console=False) - - @mock.patch.object(command_executer.CommandExecuter, - 'ChrootRunCommandWOutput') - @mock.patch.object(llvm_patch_management, '_ConstructPathToSources') - def testSuccessfullyGetSrcPath(self, mock_construct_src_path, - mock_chroot_cmd): - - # Simulate the behavior of 'ChrootRunCommandWOutput()' when successfully - # get the absolute chroot ebuild path to the package and successfully - # unpacked the package. - @CallCountsToMockFunctions - def MultipleCallsToGetSrcPath(call_count, - chromeos_root, - command, - print_to_console, - env=None): - - # First call to 'ChrootRunCommandWOutput()' which would successfully - # get the absolute chroot path to the package's ebuild. - if call_count == 0: - # Returns shell error code, stdout, stderr. - return 0, '/mount/host/source/path/to/package/test-r1.ebuild', 0 - - # Second call to 'ChrootRunCommandWOutput()' which would successfully - # unpack the package. - if call_count == 1: - # Returns shell error code, stdout, stderr. - return 0, None, 0 - - # 'ChrootRunCommandWOutput()' was called more times than expected (2 - # times). - assert False, ('Unexpectedly called more than 2 times.') - - # Use the test function to simulate 'ChrootRunCommandWOutput()' behavior. - mock_chroot_cmd.side_effect = MultipleCallsToGetSrcPath - - # Simulate the behavior of '_ConstructPathToSources()' when the ebuild name - # has a revision number and '.ebuild' and the absolute path to the src - # directory is valid. - mock_construct_src_path.return_value = ('/some/path/to/chroot/chroot/var' - '/tmp/portage/to/test-r1/work/' - 'test') - - self.assertEqual( - llvm_patch_management.UnpackLLVMPackage('/some/path/to/chroot', - 'package/test'), - '/some/path/to/chroot/chroot/var/tmp/portage/to/test-r1/work/test') - - self.assertEqual(mock_chroot_cmd.call_count, 2) - - mock_construct_src_path.assert_called_once_with('/some/path/to/chroot', - 'test-r1.ebuild', 'to') - - def testFailedToRemoveEbuildPartFromTheEbuildName(self): - # Verify the exception is raised when the ebuild name with the revision - # number does not have '.ebuild' in the name. - # - # Ex: llvm-9.0_pre361749_p20190714-r4 - # - # Does not have a '.ebuild' in the ebuild name. - with self.assertRaises(ValueError) as err: - llvm_patch_management._ConstructPathToSources('/some/path/to/chroot', - 'test-r1', 'test-packages') - - self.assertEqual(err.exception.message, - 'Failed to remove \'.ebuild\' from test-r1.') - - def testFailedToRemoveTheRevisionNumberFromTheEbuildName(self): - # Verify the exception is raised when the ebuild name with the revision - # number does not have the revision number in the name. - # - # Ex: llvm-9.0_pre361749_p20190714.ebuild - # - # Does not have a revision number in the ebuild name. - with self.assertRaises(ValueError) as err: - llvm_patch_management._ConstructPathToSources( - '/some/path/to/chroot', 'test.ebuild', 'test-packages') - - self.assertEqual(err.exception.message, - 'Failed to remove the revision number from test.') - - # Simulate behavior of 'os.path.isdir()' when the constructed absolute path to - # the unpacked sources does not exist. - @mock.patch.object(os.path, 'isdir', return_value=False) - def testInvalidPathToUnpackedSources(self, mock_isdir): - # Verify the exception is raised when the absolute path to the unpacked - # sources is constructed, but the path is invalid. - with self.assertRaises(ValueError) as err: - llvm_patch_management._ConstructPathToSources( - '/some/path/to/chroot', 'test-r1.ebuild', 'test-packages') - - self.assertEqual( - err.exception.message, - 'Failed to construct the absolute path to the unpacked ' - 'sources of the package test: ' - '/some/path/to/chroot/chroot/var/tmp/portage/test-packages' - '/test-r1/work/test') - - mock_isdir.assert_called_once() - - # Simulate the behavior of 'os.path.isdir()' when the absolute path to the - # src directory exists. - @mock.patch.object(os.path, 'isdir', return_value=True) - def testSuccessfullyConstructedSrcPath(self, mock_isdir): - self.assertEqual( - llvm_patch_management._ConstructPathToSources( - '/some/path/to/chroot', 'test-r1.ebuild', 'test-packages'), - '/some/path/to/chroot/chroot/var/tmp/portage/test-packages/' - 'test-r1/work/test') - - mock_isdir.assert_called_once() - + # Simulate `GetGitHashForVersion()` when successfully retrieved the git hash + # of the version passed in. + @mock.patch.object( + LLVMHash, 'GetGitHashForVersion', return_value='a123testhash1') + # Simulate `CreateTempLLVMRepo()` when successfully created a work tree from + # the LLVM repo copy in `llvm_tools` directory. + @mock.patch.object(llvm_patch_management, 'CreateTempLLVMRepo') + # Simulate behavior of `_MoveSrcTreeHEADToGitHash()` when successfully moved + # the head pointer to the git hash of the revision. + @mock.patch.object(llvm_patch_management, '_MoveSrcTreeHEADToGitHash') @mock.patch.object(llvm_patch_management, 'GetPathToFilesDirectory') @mock.patch.object(llvm_patch_management, '_CheckPatchMetadataPath') def testExceptionIsRaisedWhenUpdatingAPackagesMetadataFile( - self, mock_check_patch_metadata_path, mock_get_filesdir_path): + self, mock_check_patch_metadata_path, mock_get_filesdir_path, + mock_move_head_pointer, mock_create_temp_llvm_repo, mock_get_git_hash): + + abs_path_to_patch_file = \ + '/some/path/to/chroot/some/path/to/filesdir/PATCHES' # Simulate the behavior of '_CheckPatchMetadataPath()' when the patch # metadata file in $FILESDIR does not exist or does not end in '.json'. def InvalidPatchMetadataFile(patch_metadata_path): - self.assertEqual(patch_metadata_path, - '/some/path/to/chroot/some/path/to/filesdir/PATCHES') + self.assertEqual(patch_metadata_path, abs_path_to_patch_file) - raise ValueError('File does not end in \'.json\': ' - '/some/path/to/chroot/some/path/to/filesdir/PATCHES') + raise ValueError( + 'File does not end in ".json": %s' % abs_path_to_patch_file) # Use the test function to simulate behavior of '_CheckPatchMetadataPath()'. mock_check_patch_metadata_path.side_effect = InvalidPatchMetadataFile + abs_path_to_filesdir = '/some/path/to/chroot/some/path/to/filesdir' + # Simulate the behavior of 'GetPathToFilesDirectory()' when successfully # constructed the absolute path to $FILESDIR of a package. - mock_get_filesdir_path.return_value = ('/some/path/to/chroot/some/path/' - 'to/filesdir') + mock_get_filesdir_path.return_value = abs_path_to_filesdir + + temp_work_tree = '/abs/path/to/tmpWorkTree' + + # Simulate the behavior of returning the absolute path to a worktree via + # `git worktree add`. + mock_create_temp_llvm_repo.return_value.__enter__.return_value.name = \ + temp_work_tree + + chroot_path = '/some/path/to/chroot' + revision = 1000 + patch_file_name = 'PATCHES' + package_name = 'test-package/package1' # Verify the exception is raised when a package is constructing the # arguments for the patch manager to update its patch metadata file and an # exception is raised in the process. with self.assertRaises(ValueError) as err: llvm_patch_management.UpdatePackagesPatchMetadataFile( - '/some/path/to/chroot', 1000, 'PATCHES', ['test-packages/package1'], + chroot_path, revision, patch_file_name, [package_name], FailureModes.FAIL) self.assertEqual( - err.exception.message, 'File does not end in \'.json\': ' - '/some/path/to/chroot/some/path/to/filesdir/PATCHES') + str(err.exception), + 'File does not end in ".json": %s' % abs_path_to_patch_file) + + mock_get_filesdir_path.assert_called_once_with(chroot_path, package_name) - mock_get_filesdir_path.assert_called_once_with('/some/path/to/chroot', - 'test-packages/package1') + mock_get_git_hash.assert_called_once() mock_check_patch_metadata_path.assert_called_once() + mock_move_head_pointer.assert_called_once() + + mock_create_temp_llvm_repo.assert_called_once() + + # Simulate `CleanSrcTree()` when successfully removed changes from the + # worktree. + @mock.patch.object(patch_manager, 'CleanSrcTree') + # Simulate `GetGitHashForVersion()` when successfully retrieved the git hash + # of the version passed in. + @mock.patch.object( + LLVMHash, 'GetGitHashForVersion', return_value='a123testhash1') + # Simulate `CreateTempLLVMRepo()` when successfully created a work tree from + # the LLVM repo copy in `llvm_tools` directory. + @mock.patch.object(llvm_patch_management, 'CreateTempLLVMRepo') + # Simulate behavior of `_MoveSrcTreeHEADToGitHash()` when successfully moved + # the head pointer to the git hash of the revision. + @mock.patch.object(llvm_patch_management, '_MoveSrcTreeHEADToGitHash') @mock.patch.object(llvm_patch_management, 'GetPathToFilesDirectory') @mock.patch.object(llvm_patch_management, '_CheckPatchMetadataPath') - @mock.patch.object(llvm_patch_management, 'UnpackLLVMPackage') @mock.patch.object(patch_manager, 'HandlePatches') def testSuccessfullyRetrievedPatchResults( - self, mock_handle_patches, mock_unpack_package, - mock_check_patch_metadata_path, mock_get_filesdir_path): + self, mock_handle_patches, mock_check_patch_metadata_path, + mock_get_filesdir_path, mock_move_head_pointer, + mock_create_temp_llvm_repo, mock_get_git_hash, mock_clean_src_tree): + + abs_path_to_filesdir = '/some/path/to/chroot/some/path/to/filesdir' + + abs_path_to_patch_file = \ + '/some/path/to/chroot/some/path/to/filesdir/PATCHES.json' # Simulate the behavior of 'GetPathToFilesDirectory()' when successfully # constructed the absolute path to $FILESDIR of a package. - mock_get_filesdir_path.return_value = ('/some/path/to/chroot/some/path/' - 'to/filesdir') - - # Simulate the behavior of 'UnpackLLVMPackage()' when successfully unpacked - # the package and constructed the absolute path to the unpacked sources. - mock_unpack_package.return_value = ('/some/path/to/chroot/chroot/var/tmp/' - 'portage/test-packages/package2-r1/work' - '/package2') + mock_get_filesdir_path.return_value = abs_path_to_filesdir PatchInfo = namedtuple('PatchInfo', [ 'applied_patches', 'failed_patches', 'non_applicable_patches', @@ -407,6 +258,13 @@ class LlvmPatchManagementTest(unittest.TestCase): removed_patches=[], modified_metadata=None) + temp_work_tree = '/abs/path/to/tmpWorkTree' + + # Simulate the behavior of returning the absolute path to a worktree via + # `git worktree add`. + mock_create_temp_llvm_repo.return_value.__enter__.return_value.name = \ + temp_work_tree + expected_patch_results = { 'applied_patches': ['fixes_something.patch'], 'failed_patches': ['disables_output.patch'], @@ -416,27 +274,31 @@ class LlvmPatchManagementTest(unittest.TestCase): 'modified_metadata': None } + chroot_path = '/some/path/to/chroot' + revision = 1000 + patch_file_name = 'PATCHES.json' + package_name = 'test-package/package2' + patch_info = llvm_patch_management.UpdatePackagesPatchMetadataFile( - '/some/path/to/chroot', 1000, 'PATCHES.json', - ['test-packages/package2'], FailureModes.CONTINUE) + chroot_path, revision, patch_file_name, [package_name], + FailureModes.CONTINUE) - self.assertDictEqual(patch_info, - {'test-packages/package2': expected_patch_results}) + self.assertDictEqual(patch_info, {package_name: expected_patch_results}) - mock_get_filesdir_path.assert_called_once_with('/some/path/to/chroot', - 'test-packages/package2') + mock_get_filesdir_path.assert_called_once_with(chroot_path, package_name) mock_check_patch_metadata_path.assert_called_once_with( - '/some/path/to/chroot/some/path/to/filesdir/PATCHES.json') + abs_path_to_patch_file) + + mock_handle_patches.assert_called_once() + + mock_create_temp_llvm_repo.assert_called_once() + + mock_get_git_hash.assert_called_once() - mock_unpack_package.assert_called_once_with('/some/path/to/chroot', - 'test-packages/package2') + mock_move_head_pointer.assert_called_once() - mock_handle_patches.assert_called_once_with( - 1000, '/some/path/to/chroot/some/path/to/filesdir/PATCHES.json', - '/some/path/to/chroot/some/path/to/filesdir', - '/some/path/to/chroot/chroot/var/tmp/portage/test-packages/' - 'package2-r1/work/package2', FailureModes.CONTINUE) + mock_clean_src_tree.assert_called_once() if __name__ == '__main__': |