def test_object_get(mocker): test_data = '01234' with TemporaryDirectory() as tmp_dir: with utils.temp_file(tmp_dir) as input_file: with open(input_file, 'w') as writer: writer.write(test_data) with open(input_file, 'rb') as reader: class MockRawRequest(): def __init__(self): self.raw = reader class MockOCI(): def __init__(self, *args, **kwargs): pass def get_object(self, *args, **kwargs): return MockResponse(200, MockRawRequest()) mocker.patch('backup_tool.oci_client.from_file', return_value='') mocker.patch('backup_tool.oci_client.ObjectStorageClient', return_value=MockOCI) mocker.patch('backup_tool.oci_client.to_dict', side_effect=to_dict_mock) client = OCIObjectStorageClient(FAKE_CONFIG, FAKE_SECTION) # Make sure to pass page limit of 1 with utils.temp_file(tmp_dir) as temp_file: objects = client.object_get(FAKE_NAMESPACE, FAKE_BUCKET, 'some-object-name', temp_file) md5 = utils.md5(temp_file) assert md5 == 'QQDE1E2pF3JH5EpfwVRneA=='
def test_object_put_invalid_status(mocker): class MockOCI(): def __init__(self, *args, **kwargs): pass class MockUploadManager(): def __init__(self, *args, **kwargs): pass def upload_file(self, *args, **kwargs): return MockResponse(400, f'This aint Valyrian steel') mocker.patch('backup_tool.oci_client.from_file', return_value='') mocker.patch('backup_tool.oci_client.ObjectStorageClient', return_value=MockOCI) mocker.patch('backup_tool.oci_client.UploadManager', return_value=MockUploadManager) mocker.patch('backup_tool.oci_client.to_dict', side_effect=to_dict_mock) client = OCIObjectStorageClient(FAKE_CONFIG, FAKE_SECTION) fake_data = utils.random_string() with TemporaryDirectory() as tmp_dir: with utils.temp_file(tmp_dir) as temp_file: with open(temp_file, 'w+') as writer: writer.write(fake_data) with pytest.raises(ObjectStorageException) as error: client.object_put(FAKE_NAMESPACE, FAKE_BUCKET, 'some-object-name', temp_file) assert str( error.value) == 'Error uploading object, Reponse code 400'
def test_object_put(mocker): class MockOCI(): def __init__(self, *args, **kwargs): pass class MockUploadManager(): def __init__(self, *args, **kwargs): pass def upload_file(self, *args, **kwargs): return MockResponse(200, None) mocker.patch('backup_tool.oci_client.from_file', return_value='') mocker.patch('backup_tool.oci_client.ObjectStorageClient', return_value=MockOCI) mocker.patch('backup_tool.oci_client.UploadManager', return_value=MockUploadManager) mocker.patch('backup_tool.oci_client.to_dict', side_effect=to_dict_mock) client = OCIObjectStorageClient(FAKE_CONFIG, FAKE_SECTION) fake_data = utils.random_string() with TemporaryDirectory() as tmp_dir: with utils.temp_file(tmp_dir) as temp_file: with open(temp_file, 'w+') as writer: writer.write(fake_data) client.object_put(FAKE_NAMESPACE, FAKE_BUCKET, 'some-object-name', temp_file)
def test_object_get_restore_invalid_status(mocker): class MockOCI(): def __init__(self, *args, **kwargs): pass def get_object(self, *args, **kwargs): raise ServiceError(400, 400, {}, "'code': 'NotRestored'") def restore_objects(self, *args, **kwargs): return MockResponse(400, None) mocker.patch('backup_tool.oci_client.from_file', return_value='') mocker.patch('backup_tool.oci_client.ObjectStorageClient', return_value=MockOCI) mocker.patch('backup_tool.oci_client.to_dict', side_effect=to_dict_mock) client = OCIObjectStorageClient(FAKE_CONFIG, FAKE_SECTION) # Make sure to pass page limit of 1 with TemporaryDirectory() as tmp_dir: with utils.temp_file(tmp_dir) as temp_file: with pytest.raises(ObjectStorageException) as error: client.object_get(FAKE_NAMESPACE, FAKE_BUCKET, 'some-object-name', temp_file, set_restore=True) assert str(error.value) == 'Error restoring object, Response code 400'
def test_setup_logger(): ''' Test basic logging to file ''' with TemporaryDirectory() as tmp_dir: with utils.temp_file(tmp_dir) as temp: log = utils.setup_logger('test', 10, logging_file=temp) log.debug(f'Running log test with log file {temp}')
def test_md5(): ''' Run md5 and make sure it matches expected ''' # Hardcoded, this is what the base64 hash of foo is value = '07BzhNET7exJ6qYjitX/AA==' with TemporaryDirectory() as tmp_dir: with utils.temp_file(tmp_dir) as temp: with open(temp, 'w') as writer: writer.write('foo\n') md5_value = utils.md5(temp) assert md5_value == value, 'MD5 value not equal to expected'
def _file_backup_encrypt(self, local_file_path, local_file_md5): with utils.temp_file(self.work_directory, delete=False) as encrypted_file: self.logger.debug(f'Creating encrypted file "{str(encrypted_file)}" from file "{str(local_file_path)}"') check_local_file_md5, encrypted_file_md5 = crypto.encrypt_file(str(local_file_path), str(encrypted_file), self.crypto_key) if check_local_file_md5 != local_file_md5: self.logger.error(f'Unable to verify md5 during crypto phase for file "{str(local_file_path)}"') raise BackupToolClientException(f'Unable to verify md5 during crypto phase for file "{str(local_file_path)}"') self.logger.debug(f'Created encrypted file "{str(encrypted_file)}" with md5 "{encrypted_file_md5}" ' f' from original file "{str(local_file_path)}" with md5 "{local_file_md5}"') return { 'local_file': str(local_file_path), 'local_file_md5': local_file_md5, 'encrypted_file': str(encrypted_file), 'encrypted_file_md5': encrypted_file_md5, }
def file_restore(self, local_file_id, overwrite=False, set_restore=False): #pylint: disable=too-many-return-statements ''' Restore file from object storage local_file_id : ID of local file database entry to restore locally overwrite : Overwrite local file if md5 does not match set_restore : If object is archived, attempt to restore ''' self.logger.info(f'Restoring local file: {local_file_id}') local_file = self.db_session.query(BackupEntryLocalFile).get(local_file_id) if not local_file: self.logger.error(f'Unable to find local file: {local_file_id}') return False if not local_file.backup_entry_id: self.logger.error(f'No backup entry for local file: {local_file_id}') return False backup_entry = self.db_session.query(BackupEntry).get(local_file.backup_entry_id) if not backup_entry: self.logger.error(f'Expecting backup entry {local_file.backup_entry_id} does not exist') local_file_path = Path(local_file.local_file_path) if self.relative_path: local_file_path = self.relative_path / local_file_path if local_file_path.is_file(): self.logger.debug(f'Checking local file "{str(local_file_path)}" md5') local_file_md5 = utils.md5(str(local_file_path)) self.logger.debug(f'Local file "{str(local_file_path)}" has md5 sum {local_file_md5}') if backup_entry.original_md5_checksum == local_file_md5: if not overwrite: self.logger.info(f'Local file "{str(local_file_path)}" has expected md5 {local_file_md5}') return True # Write file to temp dir with utils.temp_file(self.work_directory) as encrypted_file: self.logger.info(f'Downloading object {backup_entry.uploaded_file_path} to temp file "{str(encrypted_file)}"') self.os_client.object_get(self.oci_namespace, self.oci_bucket, backup_entry.uploaded_file_path, str(encrypted_file), set_restore=set_restore) self.logger.info(f'Downloaded of object {backup_entry.uploaded_file_path} complete, written to temp file "{str(encrypted_file)}"') # Ensure dir of new decrypted file is created if not local_file_path.parent.exists(): local_file_path.mkdir(parents=True) self.logger.debug(f'Decrypting temp file "{str(encrypted_file)}" to file "{str(local_file_path)}"') encrypted_file_md5, local_file_md5 = crypto.decrypt_file(str(encrypted_file), str(local_file_path), self.crypto_key) self.logger.debug(f'Decrypted file "{str(encrypted_file)}" with md5 "{encrypted_file_md5}" to ' f'file "{str(local_file_path)}" with md5 "{local_file_md5}"') if backup_entry.uploaded_md5_checksum != encrypted_file_md5: self.logger.error(f'Downloaded file "{str(encrypted_file)}" has unexpected md5 {encrypted_file_md5}, ' f'expected {backup_entry.uploaded_md5_checksum}') return False if local_file_md5 != backup_entry.original_md5_checksum: self.logger.error(f'MD5 {local_file_md5} of decrypted file "{str(local_file_path)}" does not match expected {backup_entry.original_md5_checksum}') return False return True