class TestGcpClient:
    # Store all patchers
    patchers = []

    @classmethod
    def setup_class(self):
        self.patchers.append(create_start_patcher(
            patch_function='_get_device_of_volume', patch_object=BaseClient, side_effect=get_device_of_volume))
        self.patchers.append(create_start_patcher(
            patch_function='delete_snapshot', patch_object=BaseClient, return_value=True))
        self.patchers.append(create_start_patcher(
            patch_function='delete_volume', patch_object=BaseClient, return_value=True))
        self.patchers.append(create_start_patcher(
            patch_function='glob', patch_object=glob, side_effect=mockglob))
        self.patchers.append(create_start_patcher(patch_function='generate_name_by_prefix',
                                                  patch_object=BaseClient, side_effect=generate_name_by_prefix))
        self.patchers.append(create_start_patcher(
            patch_function='shell', patch_object=BaseClient, side_effect=shell))
        self.patchers.append(create_start_patcher(
            patch_function='last_operation', patch_object=BaseClient))
        self.patchers.append(create_start_patcher(
            patch_function='google.oauth2.service_account.Credentials.from_service_account_info'))
        self.patchers.append(create_start_patcher(
            patch_function='googleapiclient.discovery.build', return_value=ComputeClient()))
        self.patchers.append(create_start_patcher(
            patch_function='google.cloud.storage.Client', return_value=StorageClient()))
        self.patchers.append(create_start_patcher(
            patch_function='google.cloud.storage.Blob.upload_from_string'))
        self.patchers.append(create_start_patcher(
            patch_function='google.cloud.storage.Blob.delete'))
        self.patchers.append(create_start_patcher(
            patch_function='upload_from_filename', patch_object=Blob, side_effect=upload_from_filename))
        self.patchers.append(create_start_patcher(
            patch_function='download_to_filename', patch_object=Blob, side_effect=download_to_filename))

        os.environ['SF_BACKUP_RESTORE_LOG_DIRECTORY'] = log_dir
        os.environ['SF_BACKUP_RESTORE_LAST_OPERATION_DIRECTORY'] = log_dir

        self.gcpClient = GcpClient(operation_name, configuration, directory_persistent, directory_work_list,
                                   poll_delay_time, poll_maximum_time)

    @classmethod
    def teardown_class(self):
        stop_all_patchers(self.patchers)

    def test_create_gcp_client(self):
        assert self.gcpClient.project_id == project_id
        assert self.gcpClient.compute_client is not None
        assert self.gcpClient.storage_client is not None
        assert self.gcpClient.container == bucket
        assert self.gcpClient.availability_zone == availability_zone

    def test_get_container_exception(self):
        self.gcpClient.CONTAINER = invalid_container
        assert self.gcpClient.get_container() is None
        self.gcpClient.CONTAINER = valid_container

    def test_get_snapshot(self):
        expected_snapshot = Snapshot(valid_snapshot_name, '40', 'READY')
        snapshot = self.gcpClient.get_snapshot(valid_snapshot_name)
        assert expected_snapshot.id == snapshot.id
        assert expected_snapshot.size == snapshot.size
        assert expected_snapshot.status == snapshot.status

    def test_get_snapshot_exception(self):
        pytest.raises(Exception, self.gcpClient.get_snapshot,
                      invalid_snapshot_name)

    def test_snapshot_exists(self):
        assert self.gcpClient.snapshot_exists(valid_snapshot_name) == True

    def test_snapshot_exists_not_found(self):
        assert self.gcpClient.snapshot_exists(not_found_snapshot_name) == False

    def test_snapshot_exists_forbidden(self):
        pytest.raises(Exception, self.gcpClient.snapshot_exists,
                      invalid_snapshot_name)

    def test_get_volume(self):
        expected_volume = Volume(valid_disk_name, 'READY', '40')
        volume = self.gcpClient.get_volume(valid_disk_name)
        assert expected_volume.id == volume.id
        assert expected_volume.size == volume.size
        assert expected_volume.status == volume.status

    def test_get_volume_exception(self):
        self.gcpClient.get_volume(invalid_disk_name) is None

    def test_volume_exists(self):
        assert self.gcpClient.volume_exists(valid_disk_name) == True

    def test_volume_exists_not_found(self):
        assert self.gcpClient.volume_exists(not_found_disk_name) == False

    def test_volume_exists_forbidden(self):
        pytest.raises(Exception, self.gcpClient.volume_exists,
                      invalid_disk_name)

    def test_get_attached_volumes_for_instance(self):
        volume_list = self.gcpClient.get_attached_volumes_for_instance(
            valid_vm_id)
        assert volume_list[0].id == 'vm-id'
        assert volume_list[0].status == 'READY'
        assert volume_list[0].size == '10'
        assert volume_list[0].device == ephemeral_disk_device_id
        assert volume_list[1].id == 'disk-id'
        assert volume_list[1].status == 'READY'
        assert volume_list[1].size == '40'
        assert volume_list[1].device == persistent_disk_device_id

    def test_get_attached_volumes_for_instance_returns_empty(self):
        assert self.gcpClient.get_attached_volumes_for_instance(
            invalid_vm_id) == []

    def test_get_persistent_volume_for_instance(self):
        volume = self.gcpClient.get_persistent_volume_for_instance(valid_vm_id)
        assert volume.id == 'disk-id'
        assert volume.status == 'READY'
        assert volume.size == '40'
        assert volume.device == persistent_disk_device_id

    def test_get_persistent_volume_for_instance_returns_none(self):
        assert self.gcpClient.get_persistent_volume_for_instance(
            invalid_vm_id) is None

    def test_copy_snapshot(self):
        snapshot = self.gcpClient._copy_snapshot(valid_snapshot_name)
        assert snapshot.id == valid_snapshot_name
        assert snapshot.status == 'READY'
        assert snapshot.size == '40'

    def test_create_snapshot(self):
        snapshot = self.gcpClient._create_snapshot(
            valid_disk_name, 'test-backup')
        assert snapshot.id == valid_snapshot_name
        assert snapshot.status == 'READY'
        assert snapshot.size == '40'
        self.gcpClient.output_json['snapshotId'] = valid_snapshot_name

    def test_create_snapshot_exception(self):
        pytest.raises(Exception, self.gcpClient._create_snapshot,
                      invalid_disk_name)

    def test_delete_snapshot(self):
        assert self.gcpClient._delete_snapshot(delete_snapshot_name) == True

    def test_delete_snapshot_exception(self):
        pytest.raises(Exception, self.gcpClient._delete_snapshot,
                      valid_snapshot_name)

    def test_get_mountpoint_returns_none(self):
        assert self.gcpClient.get_mountpoint(invalid_disk_name, "1") is None

    def test_get_mountpoint_without_partition(self):
        assert self.gcpClient.get_mountpoint(
            valid_disk_name) == persistent_disk_device_id

    def test_get_mountpoint(self):
        assert self.gcpClient.get_mountpoint(
            valid_disk_name, "1") == (persistent_disk_device_id + "1")

    def test_find_volume_device(self):
        assert self.gcpClient._find_volume_device(
            valid_disk_name) == persistent_disk_device_id

    def test_find_volume_device_returns_none(self):
        assert self.gcpClient._find_volume_device('invalid_disk_name') is None

    def test_get_operation_status_zonal_operation(self):
        assert self.gcpClient.get_operation_status(
            valid_operation_id, True) == 'DONE'

    def test_get_operation_status_global_operation(self):
        assert self.gcpClient.get_operation_status(
            valid_operation_id, False) == 'DONE'

    def test_get_operation_status_zonal_operation_pending(self):
        assert self.gcpClient.get_operation_status(
            pending_operation_id, True) == 'RUNNING'

    def test_get_operation_status_zonal_operation_error(self):
        pytest.raises(Exception, self.gcpClient.get_operation_status,
                      error_operation_id, True)

    def test_create_volume(self):
        volume = self.gcpClient._create_volume('40', valid_snapshot_name)
        assert volume.id == valid_disk_name
        assert volume.status == 'READY'
        assert volume.size == '40'

    def test_create_volume_exception(self):
        pytest.raises(Exception, self.gcpClient._create_volume,
                      '40', invalid_snapshot_name)

    def test_delete_volume(self):
        assert self.gcpClient._delete_volume(delete_disk_name) == True

    def test_delete_volume_exception(self):
        pytest.raises(Exception, self.gcpClient._delete_volume,
                      valid_disk_name)

    def test_create_attachment(self):
        attachment = self.gcpClient._create_attachment(
            valid_disk_name, valid_vm_id)
        assert attachment.id == 0
        assert attachment.instance_id == valid_vm_id
        assert attachment.volume_id == valid_disk_name

    def test_create_attachment_exception(self):
        pytest.raises(Exception, self.gcpClient._create_attachment,
                      some_disk_name, valid_vm_id)

    def test_delete_attachment(self):
        assert self.gcpClient._delete_attachment(
            valid_disk_name, valid_vm_id) == True

    def test_delete_attachment_exception(self):
        pytest.raises(Exception, self.gcpClient._delete_attachment,
                      invalid_disk_name, invalid_vm_id)

    def test_upload_to_blobstore(self):
        assert self.gcpClient._upload_to_blobstore(
            valid_blob_path, 'blob') == True

    def test_upload_to_blobstore_raises_exception(self):
        pytest.raises(Exception, self.gcpClient._upload_to_blobstore,
                      invalid_blob_path, 'blob')

    def test_upload_to_blobstore_raises_exception_on_invalid_container(self):
        prev_container = self.gcpClient.container
        self.gcpClient.container = None
        pytest.raises(Exception, self.gcpClient._upload_to_blobstore,
                      invalid_blob_path, 'blob')
        self.gcpClient.container = prev_container

    def test_download_from_blobstore(self):
        assert self.gcpClient._download_from_blobstore(
            'blob', valid_blob_path) == True

    def test_download_from_blobstore_raises_exception(self):
        pytest.raises(
            Exception, self.gcpClient._download_from_blobstore, 'blob', invalid_blob_path)

    def test_download_from_blobstore_raises_exception_on_invalid_container(self):
        prev_container = self.gcpClient.container
        self.gcpClient.container = None
        pytest.raises(
            Exception, self.gcpClient._download_from_blobstore, 'blob', invalid_blob_path)
        self.gcpClient.container = prev_container

    @patch('lib.clients.BaseClient.requests.post')
    @patch('lib.clients.BaseClient.requests.get')
    def test_gcp_client_creation_with_credhub(self,  mock_get, mock_post):
        credhub_config = {
            'type': 'online',
            'backup_guid': 'backup-guid',
            'instance_id': 'vm-id',
            'secret': 'xyz',
            'job_name': 'service-job-name',
            'container': valid_container,
            'projectId': project_id,
            'credhub_url': '/credhub',
            'credhub_uaa_url': '/oauth',
            'credhub_key': '/test',
            'credhub_client_id': '1',
            'credhub_client_secret': 'secret',
            'credhub_username': '******',
            'credhub_user_password': '******'
        }
        auth_response = {
            'access_token': 'auth-token-response'
        }
        mock_post.return_value = Mock(ok=True)
        mock_post.return_value.json.return_value = auth_response
        mock_get.return_value = Mock(ok=True)
        mock_get.return_value.json.return_value = {
            'data': [{
                'value': {
                    'type': 'service_account',
                    'project_id': 'gcp-dev',
                    'private_key_id': '2222',
                    'private_key': '-----BEGIN PRIVATE KEY-----\\nMIIEFatI0=\\n-----END PRIVATE KEY-----\\n',
                    'client_email': '*****@*****.**',
                    'client_id': '6666',
                    'auth_uri': 'auth_uri',
                    'token_uri': 'token_uri',
                    'auth_provider_x509_cert_url': 'cert_url',
                    'client_x509_cert_url': 'cert_url'}}]}
        gcpClient = GcpClient(operation_name, credhub_config, directory_persistent, directory_work_list,
                  poll_delay_time, poll_maximum_time)
        assert gcpClient.project_id == project_id
        assert gcpClient.project_id == project_id
        assert gcpClient.compute_client is not None
        assert gcpClient.storage_client is not None
        assert gcpClient.container == bucket
        assert gcpClient.availability_zone == availability_zone
Esempio n. 2
0
class TestGcpClient:
    # Store all patchers
    patchers = []

    @classmethod
    def setup_class(self):
        self.patchers.append(
            create_start_patcher(patch_function='_get_device_of_volume',
                                 patch_object=BaseClient,
                                 side_effect=get_device_of_volume))
        self.patchers.append(
            create_start_patcher(patch_function='delete_snapshot',
                                 patch_object=BaseClient,
                                 return_value=True))
        self.patchers.append(
            create_start_patcher(patch_function='delete_volume',
                                 patch_object=BaseClient,
                                 return_value=True))
        self.patchers.append(
            create_start_patcher(patch_function='glob',
                                 patch_object=glob,
                                 side_effect=mockglob))
        self.patchers.append(
            create_start_patcher(patch_function='generate_name_by_prefix',
                                 patch_object=BaseClient,
                                 side_effect=generate_name_by_prefix))
        self.patchers.append(
            create_start_patcher(patch_function='shell',
                                 patch_object=BaseClient,
                                 side_effect=shell))
        self.patchers.append(
            create_start_patcher(patch_function='last_operation',
                                 patch_object=BaseClient))
        self.patchers.append(
            create_start_patcher(
                patch_function=
                'google.oauth2.service_account.Credentials.from_service_account_info'
            ))
        self.patchers.append(
            create_start_patcher(
                patch_function='googleapiclient.discovery.build',
                return_value=ComputeClient()))
        self.patchers.append(
            create_start_patcher(patch_function='google.cloud.storage.Client',
                                 return_value=StorageClient()))
        self.patchers.append(
            create_start_patcher(
                patch_function='google.cloud.storage.Blob.upload_from_string'))
        self.patchers.append(
            create_start_patcher(
                patch_function='google.cloud.storage.Blob.delete'))
        self.patchers.append(
            create_start_patcher(patch_function='upload_from_filename',
                                 patch_object=Blob,
                                 side_effect=upload_from_filename))
        self.patchers.append(
            create_start_patcher(patch_function='download_to_filename',
                                 patch_object=Blob,
                                 side_effect=download_to_filename))

        os.environ['SF_BACKUP_RESTORE_LOG_DIRECTORY'] = log_dir
        os.environ['SF_BACKUP_RESTORE_LAST_OPERATION_DIRECTORY'] = log_dir

        self.gcpClient = GcpClient(operation_name, configuration,
                                   directory_persistent, directory_work_list,
                                   poll_delay_time, poll_maximum_time)

    @classmethod
    def teardown_class(self):
        stop_all_patchers(self.patchers)

    def test_create_gcp_client(self):
        assert self.gcpClient.project_id == project_id
        assert self.gcpClient.compute_client is not None
        assert self.gcpClient.storage_client is not None
        assert self.gcpClient.container == bucket
        assert self.gcpClient.availability_zone == availability_zone

    def test_get_container_exception(self):
        self.gcpClient.CONTAINER = invalid_container
        assert self.gcpClient.get_container() is None
        self.gcpClient.CONTAINER = valid_container

    def test_get_snapshot(self):
        expected_snapshot = Snapshot(valid_snapshot_name, '40', 'READY')
        snapshot = self.gcpClient.get_snapshot(valid_snapshot_name)
        assert expected_snapshot.id == snapshot.id
        assert expected_snapshot.size == snapshot.size
        assert expected_snapshot.status == snapshot.status

    def test_get_snapshot_exception(self):
        pytest.raises(Exception, self.gcpClient.get_snapshot,
                      invalid_snapshot_name)

    def test_snapshot_exists(self):
        assert self.gcpClient.snapshot_exists(valid_snapshot_name) == True

    def test_snapshot_exists_not_found(self):
        assert self.gcpClient.snapshot_exists(not_found_snapshot_name) == False

    def test_snapshot_exists_forbidden(self):
        pytest.raises(Exception, self.gcpClient.snapshot_exists,
                      invalid_snapshot_name)

    def test_get_volume(self):
        expected_volume = Volume(valid_disk_name, 'READY', '40')
        volume = self.gcpClient.get_volume(valid_disk_name)
        assert expected_volume.id == volume.id
        assert expected_volume.size == volume.size
        assert expected_volume.status == volume.status

    def test_get_volume_exception(self):
        self.gcpClient.get_volume(invalid_disk_name) is None

    def test_volume_exists(self):
        assert self.gcpClient.volume_exists(valid_disk_name) == True

    def test_volume_exists_not_found(self):
        assert self.gcpClient.volume_exists(not_found_disk_name) == False

    def test_volume_exists_forbidden(self):
        pytest.raises(Exception, self.gcpClient.volume_exists,
                      invalid_disk_name)

    def test_get_attached_volumes_for_instance(self):
        volume_list = self.gcpClient.get_attached_volumes_for_instance(
            valid_vm_id)
        assert volume_list[0].id == 'vm-id'
        assert volume_list[0].status == 'READY'
        assert volume_list[0].size == '10'
        assert volume_list[0].device == ephemeral_disk_device_id
        assert volume_list[1].id == 'disk-id'
        assert volume_list[1].status == 'READY'
        assert volume_list[1].size == '40'
        assert volume_list[1].device == persistent_disk_device_id

    def test_get_attached_volumes_for_instance_returns_empty(self):
        assert self.gcpClient.get_attached_volumes_for_instance(
            invalid_vm_id) == []

    def test_get_persistent_volume_for_instance(self):
        volume = self.gcpClient.get_persistent_volume_for_instance(valid_vm_id)
        assert volume.id == 'disk-id'
        assert volume.status == 'READY'
        assert volume.size == '40'
        assert volume.device == persistent_disk_device_id

    def test_get_persistent_volume_for_instance_returns_none(self):
        assert self.gcpClient.get_persistent_volume_for_instance(
            invalid_vm_id) is None

    def test_copy_snapshot(self):
        snapshot = self.gcpClient._copy_snapshot(valid_snapshot_name)
        assert snapshot.id == valid_snapshot_name
        assert snapshot.status == 'READY'
        assert snapshot.size == '40'

    def test_create_snapshot(self):
        snapshot = self.gcpClient._create_snapshot(valid_disk_name,
                                                   'test-backup')
        assert snapshot.id == valid_snapshot_name
        assert snapshot.status == 'READY'
        assert snapshot.size == '40'
        self.gcpClient.output_json['snapshotId'] = valid_snapshot_name

    def test_create_snapshot_exception(self):
        pytest.raises(Exception, self.gcpClient._create_snapshot,
                      invalid_disk_name)

    def test_delete_snapshot(self):
        assert self.gcpClient._delete_snapshot(delete_snapshot_name) == True

    def test_delete_snapshot_exception(self):
        pytest.raises(Exception, self.gcpClient._delete_snapshot,
                      valid_snapshot_name)

    def test_get_mountpoint_returns_none(self):
        assert self.gcpClient.get_mountpoint(invalid_disk_name, "1") is None

    def test_get_mountpoint_without_partition(self):
        assert self.gcpClient.get_mountpoint(
            valid_disk_name) == persistent_disk_device_id

    def test_get_mountpoint(self):
        assert self.gcpClient.get_mountpoint(
            valid_disk_name, "1") == (persistent_disk_device_id + "1")

    def test_find_volume_device(self):
        assert self.gcpClient._find_volume_device(
            valid_disk_name) == persistent_disk_device_id

    def test_find_volume_device_returns_none(self):
        assert self.gcpClient._find_volume_device('invalid_disk_name') is None

    def test_get_operation_status_zonal_operation(self):
        assert self.gcpClient.get_operation_status(valid_operation_id,
                                                   True) == 'DONE'

    def test_get_operation_status_global_operation(self):
        assert self.gcpClient.get_operation_status(valid_operation_id,
                                                   False) == 'DONE'

    def test_get_operation_status_zonal_operation_pending(self):
        assert self.gcpClient.get_operation_status(pending_operation_id,
                                                   True) == 'RUNNING'

    def test_get_operation_status_zonal_operation_error(self):
        pytest.raises(Exception, self.gcpClient.get_operation_status,
                      error_operation_id, True)

    def test_create_volume(self):
        volume = self.gcpClient._create_volume('40', valid_snapshot_name)
        assert volume.id == valid_disk_name
        assert volume.status == 'READY'
        assert volume.size == '40'

    def test_create_volume_exception(self):
        pytest.raises(Exception, self.gcpClient._create_volume, '40',
                      invalid_snapshot_name)

    def test_delete_volume(self):
        assert self.gcpClient._delete_volume(delete_disk_name) == True

    def test_delete_volume_exception(self):
        pytest.raises(Exception, self.gcpClient._delete_volume,
                      valid_disk_name)

    def test_create_attachment(self):
        attachment = self.gcpClient._create_attachment(valid_disk_name,
                                                       valid_vm_id)
        assert attachment.id == 0
        assert attachment.instance_id == valid_vm_id
        assert attachment.volume_id == valid_disk_name

    def test_create_attachment_exception(self):
        pytest.raises(Exception, self.gcpClient._create_attachment,
                      some_disk_name, valid_vm_id)

    def test_delete_attachment(self):
        assert self.gcpClient._delete_attachment(valid_disk_name,
                                                 valid_vm_id) == True

    def test_delete_attachment_exception(self):
        pytest.raises(Exception, self.gcpClient._delete_attachment,
                      invalid_disk_name, invalid_vm_id)

    def test_upload_to_blobstore(self):
        assert self.gcpClient._upload_to_blobstore(valid_blob_path,
                                                   'blob') == True

    def test_upload_to_blobstore_raises_exception(self):
        pytest.raises(Exception, self.gcpClient._upload_to_blobstore,
                      invalid_blob_path, 'blob')

    def test_upload_to_blobstore_raises_exception_on_invalid_container(self):
        prev_container = self.gcpClient.container
        self.gcpClient.container = None
        pytest.raises(Exception, self.gcpClient._upload_to_blobstore,
                      invalid_blob_path, 'blob')
        self.gcpClient.container = prev_container

    def test_download_from_blobstore(self):
        assert self.gcpClient._download_from_blobstore('blob',
                                                       valid_blob_path) == True

    def test_download_from_blobstore_raises_exception(self):
        pytest.raises(Exception, self.gcpClient._download_from_blobstore,
                      'blob', invalid_blob_path)

    def test_download_from_blobstore_raises_exception_on_invalid_container(
            self):
        prev_container = self.gcpClient.container
        self.gcpClient.container = None
        pytest.raises(Exception, self.gcpClient._download_from_blobstore,
                      'blob', invalid_blob_path)
        self.gcpClient.container = prev_container