def test_library_change_or_addition_runs_correct_commands(self): """Library is required by the 'requirements.txt' file but it doesn't exist in 'third_party/python_libs'. """ def mock_get_mismatches(): return { u'flask': (u'1.1.0.1', u'1.1.1.0'), u'six': (u'1.15.0', None), u'git-dep1': ( self.get_git_version_string('git-dep1', 'a'), self.get_git_version_string('git-dep1', 'b')), u'git-dep2': ( self.get_git_version_string('git-dep2', 'a'), None), } def mock_validate_metadata_directories(): pass swap_validate_metadata_directories = self.swap( install_backend_python_libs, 'validate_metadata_directories', mock_validate_metadata_directories) swap_get_mismatches = self.swap( install_backend_python_libs, 'get_mismatches', mock_get_mismatches) with self.swap_check_call, self.swap_Popen, self.open_file_swap: with swap_get_mismatches, swap_validate_metadata_directories: install_backend_python_libs.main() self.assertEqual( self.cmd_token_list, [ ['scripts.regenerate_requirements'], [ 'pip', 'install', '%s#egg=git-dep1' % ( self.get_git_version_string('git-dep1', 'a')), '--target', common.THIRD_PARTY_PYTHON_LIBS_DIR, '--upgrade', '--no-dependencies', ], [ 'pip', 'install', '%s#egg=git-dep2' % ( self.get_git_version_string('git-dep2', 'a')), '--target', common.THIRD_PARTY_PYTHON_LIBS_DIR, '--upgrade', '--no-dependencies', ], [ 'pip', 'install', '%s==%s' % ('flask', '1.1.0.1'), '--target', common.THIRD_PARTY_PYTHON_LIBS_DIR, '--upgrade', '--no-dependencies', ], [ 'pip', 'install', '%s==%s' % ('six', '1.15.0'), '--target', common.THIRD_PARTY_PYTHON_LIBS_DIR, '--upgrade', '--no-dependencies', ], ] )
def test_main_without_library_mismatches_calls_correct_functions(self): check_function_calls = { 'subprocess_call_is_called': False } expected_check_function_calls = { 'subprocess_call_is_called': True } def mock_call(unused_cmd_tokens, *args, **kwargs): # pylint: disable=unused-argument check_function_calls['subprocess_call_is_called'] = True class Ret(python_utils.OBJECT): """Return object with required attributes.""" def __init__(self): self.returncode = 0 def communicate(self): """Return required method.""" return '', '' return Ret() def mock_get_mismatches(): return {} print_statements = [] def mock_print(s): print_statements.append(s) def mock_validate_metadata_directories(): pass swap_validate_metadata_directories = self.swap( install_backend_python_libs, 'validate_metadata_directories', mock_validate_metadata_directories) swap_get_mismatches = self.swap( install_backend_python_libs, 'get_mismatches', mock_get_mismatches) swap_call = self.swap(subprocess, 'check_call', mock_call) swap_print = self.swap(python_utils, 'PRINT', mock_print) with swap_call, swap_get_mismatches, swap_print, self.open_file_swap: with swap_validate_metadata_directories: install_backend_python_libs.main() self.assertEqual(check_function_calls, expected_check_function_calls) self.assertEqual( print_statements, [ 'Regenerating "requirements.txt" file...', 'All third-party Python libraries are already installed ' 'correctly.' ])
def test_main_adds_comment_to_start_of_requirements(self): check_function_calls = { 'subprocess_call_is_called': False } expected_check_function_calls = { 'subprocess_call_is_called': True } def mock_call(unused_cmd_tokens, *args, **kwargs): # pylint: disable=unused-argument check_function_calls['subprocess_call_is_called'] = True class Ret(python_utils.OBJECT): """Return object with required attributes.""" def __init__(self): self.returncode = 0 def communicate(self): """Return required method.""" return '', '' return Ret() def mock_get_mismatches(): return {} def mock_validate_metadata_directories(): pass swap_validate_metadata_directories = self.swap( install_backend_python_libs, 'validate_metadata_directories', mock_validate_metadata_directories) swap_get_mismatches = self.swap( install_backend_python_libs, 'get_mismatches', mock_get_mismatches) swap_call = self.swap(subprocess, 'check_call', mock_call) expected_lines = [ '# Developers: Please do not modify this auto-generated file.' ' If\n# you want to add, remove, upgrade, or downgrade libraries,' '\n# please change the `requirements.in` file, and then follow\n#' ' the instructions there to regenerate this file.\n' ] self.assertEqual(self.file_arr, []) with self.swap_check_call, self.open_file_swap, swap_call: with swap_get_mismatches, swap_validate_metadata_directories: install_backend_python_libs.main() self.assertEqual( self.file_arr, expected_lines ) self.assertEqual(check_function_calls, expected_check_function_calls)
def test_large_number_of_discrepancies_results_in_clean_install(self): """Test that the function reinstalls all of the libraries from scratch when 5 or more mismatches are found. """ removed_dirs = [] def mock_remove_dir(directory): removed_dirs.append(directory) def mock_get_mismatches(): return { u'flask': (u'1.1.1', None), u'six': (u'1.15.0', None), u'simplejson': (None, u'3.16.0'), u'bleach': (u'3.1.4', u'3.1.5'), u'callbacks': (u'0.3.0', u'0.2.0'), } def mock_validate_metadata_directories(): pass swap_validate_metadata_directories = self.swap( install_backend_python_libs, 'validate_metadata_directories', mock_validate_metadata_directories) swap_get_mismatches = self.swap( install_backend_python_libs, 'get_mismatches', mock_get_mismatches) swap_remove_dir = self.swap(shutil, 'rmtree', mock_remove_dir) with self.swap_check_call, self.swap_Popen, swap_remove_dir: with self.open_file_swap, swap_get_mismatches: with swap_validate_metadata_directories: install_backend_python_libs.main() self.assertEqual( removed_dirs, [ common.THIRD_PARTY_PYTHON_LIBS_DIR ] ) self.assertEqual( self.cmd_token_list, [ ['scripts.regenerate_requirements'], [ 'pip', 'install', '--target', common.THIRD_PARTY_PYTHON_LIBS_DIR, '--no-dependencies', '-r', common.COMPILED_REQUIREMENTS_FILE_PATH, '--upgrade' ] ] )
def test_library_removal_runs_correct_commands(self): """Library exists in the 'third_party/python_libs' directory but it is not required in the 'requirements.txt' file. """ removed_dirs = [] def mock_remove_dir(directory): removed_dirs.append(directory) def mock_get_mismatches(): return { u'flask': (None, u'10.0.1'), u'six': (None, u'10.13.0.1') } def mock_validate_metadata_directories(): pass swap_validate_metadata_directories = self.swap( install_backend_python_libs, 'validate_metadata_directories', mock_validate_metadata_directories) swap_get_mismatches = self.swap( install_backend_python_libs, 'get_mismatches', mock_get_mismatches) swap_remove_dir = self.swap(shutil, 'rmtree', mock_remove_dir) with self.swap_check_call, self.swap_Popen, swap_remove_dir: with self.open_file_swap, swap_get_mismatches: with swap_validate_metadata_directories: install_backend_python_libs.main() self.assertEqual( removed_dirs, [ common.THIRD_PARTY_PYTHON_LIBS_DIR ] ) self.assertEqual( self.cmd_token_list, [ ['scripts.regenerate_requirements'], [ 'pip', 'install', '--target', common.THIRD_PARTY_PYTHON_LIBS_DIR, '--no-dependencies', '-r', common.COMPILED_REQUIREMENTS_FILE_PATH, '--upgrade' ] ] )
def test_library_version_change_is_handled_correctly(self): directory_names = [ 'webencodings-1.1.1.dist-info', 'webencodings-1.0.1.dist-info', 'webencodings', 'flask', 'flask-1.1.1.dist-info', 'flask-10.0.1.dist-info', 'six', 'six-1.15.0.dist-info', 'six-10.13.0.egg-info', 'google_cloud_datastore-1.15.0.dist-info', 'google_cloud_datastore-1.13.0.dist-info', 'google' ] def mock_list_dir(path): # pylint: disable=unused-argument return directory_names paths_to_delete = [] def mock_rm(path): paths_to_delete.append( path[len(common.THIRD_PARTY_PYTHON_LIBS_DIR) + 1:]) def mock_is_dir(path): # pylint: disable=unused-argument return True def mock_get_mismatches(): return { u'flask': (u'1.1.1', u'10.0.1'), u'six': (u'1.15.0', u'10.13.0'), u'webencodings': (u'1.1.1', u'1.0.1'), u'google-cloud-datastore': (u'1.15.0', u'1.13.0') } def mock_validate_metadata_directories(): pass swap_validate_metadata_directories = self.swap( install_backend_python_libs, 'validate_metadata_directories', mock_validate_metadata_directories) swap_get_mismatches = self.swap(install_backend_python_libs, 'get_mismatches', mock_get_mismatches) swap_rm_tree = self.swap(shutil, 'rmtree', mock_rm) swap_list_dir = self.swap(os, 'listdir', mock_list_dir) swap_is_dir = self.swap(os.path, 'isdir', mock_is_dir) with self.swap_check_call, self.swap_Popen, swap_get_mismatches: with swap_validate_metadata_directories, self.open_file_swap: with swap_rm_tree, swap_list_dir, swap_is_dir: install_backend_python_libs.main() self.assertEqual(self.cmd_token_list, [['scripts.regenerate_requirements'], [ 'pip', 'install', '%s==%s' % ('flask', '1.1.1'), '--target', common.THIRD_PARTY_PYTHON_LIBS_DIR, '--upgrade', '--no-dependencies', ], [ 'pip', 'install', '%s==%s' % ('webencodings', '1.1.1'), '--target', common.THIRD_PARTY_PYTHON_LIBS_DIR, '--upgrade', '--no-dependencies', ], [ 'pip', 'install', '%s==%s' % ('six', '1.15.0'), '--target', common.THIRD_PARTY_PYTHON_LIBS_DIR, '--upgrade', '--no-dependencies', ], [ 'pip', 'install', '%s==%s' % ('google-cloud-datastore', '1.15.0'), '--target', common.THIRD_PARTY_PYTHON_LIBS_DIR, '--upgrade', '--no-dependencies', ]]) self.assertEqual(paths_to_delete, [ u'flask-10.0.1.dist-info', u'webencodings-1.0.1.dist-info', u'six-10.13.0.egg-info', u'google_cloud_datastore-1.13.0.dist-info' ])