text: #
  # Copyright 2012 OpenStack Foundation
  # All Rights Reserved.
  #
  #    Licensed under the Apache License, Version 2.0 (the "License"); you may
  #    not use this file except in compliance with the License. You may obtain
  #    a copy of the License at
  #
  #         http://www.apache.org/licenses/LICENSE-2.0
  #
  #    Unless required by applicable law or agreed to in writing, software
  #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  #    License for the specific language governing permissions and limitations
  #    under the License.
  
  import datetime
  import re
  import six
  
  from ddt import data
  from ddt import ddt
  from ddt import file_data
  from ddt import unpack
  import mock
  from oslo_utils import timeutils
  from oslo_utils import units
  
  from cinder import context
  from cinder import exception
  from cinder.objects import fields
  from cinder import test
  from cinder.tests.unit.api import fakes
  from cinder.tests.unit import fake_group_snapshot
  from cinder.tests.unit import fake_snapshot
  from cinder.tests.unit import fake_volume
  from cinder.tests.unit.image import fake as fake_image
  from cinder.tests.unit import utils as test_utils
  from cinder.volume import configuration as conf
  from cinder.volume.drivers import solidfire
  from cinder.volume import qos_specs
  from cinder.volume import volume_types
  
  
  class mock_vref(object):
      def __init__(self):
          self._name_id = None
          self.admin_metadata = {}
          self.attach_status = 'detached'
          self.id = '262b9ce2-a71a-4fbe-830c-c20c5596caea'
          self.project_id = '52423d9394ad4c67b3b9034da58cedbc'
          self.provider_id = '5 4 6ecebf5d-5521-4ce1-80f3-358ebc1b9cdc'
          self.size = 20
  
      def __setitem__(self, item, value):
          self.__dict__[item] = value
  
      def __getitem__(self, item):
          return self.__dict__[item]
  
      def get(self, item, arg2 = None):
          return self.__dict__[item]
  
  
  f_uuid = ['262b9ce2-a71a-4fbe-830c-c20c5596caea',
            '362b9ce2-a71a-4fbe-830c-c20c5596caea']
  
  
  @ddt
  class SolidFireVolumeTestCase(test.TestCase):
  
      EXPECTED_QOS = {'minIOPS': 110, 'burstIOPS': 1530, 'maxIOPS': 1020}
  
      def setUp(self):
          self.ctxt = context.get_admin_context()
          self.configuration = conf.BackendGroupConfiguration(
              [], conf.SHARED_CONF_GROUP)
          self.configuration.sf_allow_tenant_qos = True
          self.configuration.san_is_local = True
          self.configuration.sf_emulate_512 = True
          self.configuration.sf_account_prefix = 'cinder'
          self.configuration.reserved_percentage = 25
          self.configuration.target_helper = None
          self.configuration.sf_template_account_name = 'openstack-vtemplate'
          self.configuration.sf_allow_template_caching = False
          self.configuration.sf_svip = None
          self.configuration.sf_volume_prefix = 'UUID-'
          self.configuration.sf_enable_vag = False
          self.configuration.replication_device = []
          self.configuration.max_over_subscription_ratio = 2
  
          super(SolidFireVolumeTestCase, self).setUp()
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
  
          self.mock_object(solidfire.SolidFireDriver,
                           '_get_provisioned_capacity_iops',
                           return_value=(0, 0))
  
          self.expected_qos_results = {'minIOPS': 1000,
                                       'maxIOPS': 10000,
                                       'burstIOPS': 20000}
          self.mock_stats_data =\
              {'result':
                  {'clusterCapacity': {'maxProvisionedSpace': 107374182400,
                                       'usedSpace': 1073741824,
                                       'compressionPercent': 100,
                                       'deDuplicationPercent': 100,
                                       'thinProvisioningPercent': 100}}}
          vol_updates = {'project_id': 'testprjid',
                         'name': 'testvol',
                         'size': 1,
                         'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                         'volume_type_id': 'fast',
                         'created_at': timeutils.utcnow(),
                         'attributes':
                             {'uuid': '262b9ce2-a71a-4fbe-830c-c20c5596caea'}}
          ctx = context.get_admin_context()
          self.mock_volume = fake_volume.fake_volume_obj(ctx, **vol_updates)
  
          self.fake_image_meta = {'id': '17c550bb-a411-44c0-9aaf-0d96dd47f501',
                                  'updated_at': datetime.datetime(2013, 9,
                                                                  28, 15,
                                                                  27, 36,
                                                                  325355),
                                  'is_public': True,
                                  'owner': 'testprjid'}
          self.fake_image_service = fake_image.FakeImageService()
  
          self.vol = test_utils.create_volume(
              self.ctxt, volume_id='b831c4d1-d1f0-11e1-9b23-0800200c9a66')
          self.snap = test_utils.create_snapshot(
              self.ctxt, volume_id=self.vol.id)
  
          self.fake_sfaccount = {'accountID': 25,
                                 'targetSecret': 'shhhh',
                                 'username': 'prefix-testprjid',
                                 'volumes': [6, 7, 20]}
  
          self.fake_sfvol = {'volumeID': 6,
                             'name': 'test_volume',
                             'accountID': 25,
                             'sliceCount': 1,
                             'totalSize': 1 * units.Gi,
                             'enable512e': True,
                             'access': "readWrite",
                             'status': "active",
                             'attributes': {'uuid': f_uuid[0]},
                             'qos': None,
                             'iqn': 'super_fake_iqn'}
  
          self.cluster_pairs = (
              [{'uniqueID': 'lu9f',
                'endpoint': {'passwd': 'admin', 'port': 443,
                             'url': 'https://192.168.139.102:443',
                             'svip': '10.10.8.134',
                             'mvip': '192.168.139.102',
                             'login': 'admin'},
                'name': 'AutoTest2-6AjG-FOR-TEST-ONLY',
                'clusterPairID': 33,
                'clusterAPIVersion': '9.4',
                'uuid': '9c499d4b-8fff-48b4-b875-27601d5d9889',
                'svip': '10.10.23.2',
                'mvipNodeID': 1,
                'repCount': 1,
                'encryptionAtRestState': 'disabled',
                'attributes': {},
                'mvip': '192.168.139.102',
                'ensemble': ['10.10.5.130'],
                'svipNodeID': 1}])
  
          self.mvip = '192.168.139.102'
          self.svip = '10.10.8.134'
  
          self.fake_sfsnap_name = '%s%s' % (self.configuration.sf_volume_prefix,
                                            self.snap.id)
          self.fake_sfsnaps = [{'snapshotID': '5',
                                'name': self.fake_sfsnap_name,
                                'volumeID': 6}]
  
      def fake_issue_api_request(self, method, params, version='1.0',
                                 endpoint=None, timeout=None):
          if method == 'GetClusterCapacity':
              data = {}
              if version == '1.0':
                  data = {'result': {'clusterCapacity': {
                          'maxProvisionedSpace': 107374182400,
                          'usedSpace': 1073741824,
                          'compressionPercent': 100,
                          'deDuplicationPercent': 100,
                          'thinProvisioningPercent': 100,
                          'maxUsedSpace': 53687091200}}}
              elif version == '8.0':
                  data = {'result': {'clusterCapacity': {
                          'usedMetadataSpaceInSnapshots': 16476454912,
                          'maxUsedMetadataSpace': 432103337164,
                          'activeBlockSpace': 616690857535,
                          'uniqueBlocksUsedSpace': 628629229316,
                          'totalOps': 7092186135,
                          'peakActiveSessions': 0,
                          'uniqueBlocks': 519489473,
                          'maxOverProvisionableSpace': 276546135777280,
                          'zeroBlocks': 8719571984,
                          'provisionedSpace': 19938551005184,
                          'maxUsedSpace': 8402009333760,
                          'peakIOPS': 0,
                          'timestamp': '2019-04-24T12:08:22Z',
                          'currentIOPS': 0,
                          'usedSpace': 628629229316,
                          'activeSessions': 0,
                          'nonZeroBlocks': 1016048624,
                          'maxProvisionedSpace': 55309227155456,
                          'usedMetadataSpace': 16476946432,
                          'averageIOPS': 0,
                          'snapshotNonZeroBlocks': 1606,
                          'maxIOPS': 200000,
                          'clusterRecentIOSize': 0}}}
              return data
  
          elif method is 'GetClusterInfo':
              results = {
                  'result':
                      {'clusterInfo':
                          {'name': 'fake-cluster',
                           'mvip': '1.1.1.1',
                           'svip': '1.1.1.1',
                           'uniqueID': 'unqid',
                           'repCount': 2,
                           'uuid': '53c8be1e-89e2-4f7f-a2e3-7cb84c47e0ec',
                           'attributes': {}}}}
              return results
  
          elif method is 'GetClusterVersionInfo':
              return {'id': None, 'result': {'softwareVersionInfo':
                                             {'pendingVersion': '8.2.1.4',
                                              'packageName': '',
                                              'currentVersion': '8.2.1.4',
                                              'nodeID': 0, 'startTime': ''},
                                             'clusterVersion': '8.2.1.4',
                                             'clusterAPIVersion': '8.2'}}
  
          elif method is 'AddAccount' and version == '1.0':
              return {'result': {'accountID': 25}, 'id': 1}
  
          elif method is 'GetAccountByName' and version == '1.0':
              results = {'result': {'account':
                                    {'accountID': 25,
                                     'username': params['username'],
                                     'status': 'active',
                                     'initiatorSecret': '123456789012',
                                     'targetSecret': '123456789012',
                                     'attributes': {},
                                     'volumes': [6, 7, 20]}},
                         "id": 1}
              return results
  
          elif method is 'CreateVolume' and version == '1.0':
              return {'result': {'volumeID': 5}, 'id': 1}
  
          elif method is 'CreateSnapshot' and version == '6.0':
              return {'result': {'snapshotID': 5}, 'id': 1}
  
          elif method is 'DeleteVolume' and version == '1.0':
              return {'result': {}, 'id': 1}
  
          elif method is 'ModifyVolume' and version == '5.0':
              return {'result': {}, 'id': 1}
  
          elif method is 'CloneVolume':
              return {'result': {'volumeID': 6}, 'id': 2}
  
          elif method is 'ModifyVolume':
              return {'result': {}, 'id': 1}
  
          elif method is 'ListVolumesForAccount' and version == '1.0':
              test_name = 'OS-VOLID-a720b3c0-d1f0-11e1-9b23-0800200c9a66'
              result = {'result': {
                  'volumes': [{'volumeID': 5,
                               'name': test_name,
                               'accountID': 25,
                               'sliceCount': 1,
                               'totalSize': 1 * units.Gi,
                               'enable512e': True,
                               'access': "readWrite",
                               'status': "active",
                               'attributes': {'uuid': f_uuid[0]},
                               'qos': None,
                               'iqn': test_name}]}}
              return result
  
          elif method is 'ListActiveVolumes':
              test_name = "existing_volume"
              result = {'result': {
                  'volumes': [{'volumeID': 5,
                               'name': test_name,
                               'accountID': 8,
                               'sliceCount': 1,
                               'totalSize': int(1.75 * units.Gi),
                               'enable512e': True,
                               'access': "readWrite",
                               'status': "active",
                               'attributes': {},
                               'qos': None,
                               'iqn': test_name}]}}
              return result
          elif method is 'ListVolumes':
              test_name = "get_sfvol_by_cinder"
              result = {'result': {
                  'volumes': [{'volumeID': 5,
                               'name': test_name,
                               'accountID': 8,
                               'sliceCount': 1,
                               'totalSize': int(1.75 * units.Gi),
                               'enable512e': True,
                               'access': "readWrite",
                               'status': "active",
                               'attributes': {'uuid': f_uuid[0]},
                               'qos': None,
                               'iqn': test_name},
                              {'volumeID': 15,
                               'name': test_name,
                               'accountID': 8,
                               'sliceCount': 1,
                               'totalSize': int(1.75 * units.Gi),
                               'enable512e': True,
                               'access': "readWrite",
                               'status': "active",
                               'attributes': {'uuid': f_uuid[1]},
                               'qos': None,
                               'iqn': test_name}]}}
              if params and params.get('startVolumeID', None):
                  volumes = result['result']['volumes']
                  selected_volumes = [v for v in volumes if v.get('volumeID') !=
                                      params['startVolumeID']]
                  result['result']['volumes'] = selected_volumes
              else:
                  result = {'result': {'volumes': []}}
  
              return result
          elif method is 'DeleteSnapshot':
              return {'result': {}}
          elif method is 'GetClusterVersionInfo':
              return {'result': {'clusterAPIVersion': '8.0'}}
          elif method is 'StartVolumePairing':
              return {'result': {'volumePairingKey': 'fake-pairing-key'}}
          elif method is 'RollbackToSnapshot':
              return {
                  "id": 1,
                  "result": {
                      "checksum": "0x0",
                      "snapshot": {
                          "attributes": {},
                          "checksum": "0x0",
                          "createTime": "2016-04-04T17:27:32Z",
                          "enableRemoteReplication": "false",
                          "expirationReason": "None",
                          "expirationTime": "null",
                          "groupID": 0,
                          "groupSnapshotUUID": f_uuid[0],
                          "name": "test1-copy",
                          "snapshotID": 1,
                          "snapshotUUID": f_uuid[1],
                          "status": "done",
                          "totalSize": 5000658944,
                          "virtualVolumeID": "null",
                          "volumeID": 1
                      },
                      "snapshotID": 1
                  }
              }
          elif method is 'ListAccounts':
              return {
                  'result': {
                      'accounts': [{
                          'accountID': 5,
                          'targetSecret': 'shhhh',
                          'username': 'prefix-testprjid'
                      }]
                  }
              }
          elif method == 'ListSnapshots':
              raise exception.VolumeNotFound('test clone unconfigured image')
          else:
              # Crap, unimplemented API call in Fake
              return None
  
      def fake_issue_api_request_fails(self, method,
                                       params, version='1.0',
                                       endpoint=None):
          response = {'error': {'code': 000,
                                'name': 'DummyError',
                                'message': 'This is a fake error response'},
                      'id': 1}
          msg = ('Error (%s) encountered during '
                 'SolidFire API call.' % response['error']['name'])
          raise solidfire.SolidFireAPIException(message=msg)
  
      def fake_set_qos_by_volume_type(self, type_id, ctxt):
          return {'minIOPS': 500,
                  'maxIOPS': 1000,
                  'burstIOPS': 1000}
  
      def fake_volume_get(self, key, default=None):
          return {'qos': 'fast'}
  
      def fake_update_cluster_status(self):
          return
  
      def fake_get_cluster_version_info(self):
          return
  
      def fake_get_model_info(self, account, vid, endpoint=None):
          return {'fake': 'fake-model'}
  
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      def test_create_volume_with_qos_type(self,
                                           _mock_issue_api_request):
          _mock_issue_api_request.side_effect = self.fake_issue_api_request
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'volume_type_id': 'fast',
                     'created_at': timeutils.utcnow()}
  
          fake_sfaccounts = [{'accountID': 5,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid'}]
  
          test_type = {'name': 'sf-1',
                       'qos_specs_id': 'fb0576d7-b4b5-4cad-85dc-ca92e6a497d1',
                       'deleted': False,
                       'created_at': '2014-02-06 04:58:11',
                       'updated_at': None,
                       'extra_specs': {},
                       'deleted_at': None,
                       'id': 'e730e97b-bc7d-4af3-934a-32e59b218e81'}
  
          test_qos_spec = {'id': 'asdfafdasdf',
                           'specs': {'minIOPS': '1000',
                                     'maxIOPS': '2000',
                                     'burstIOPS': '3000'}}
  
          ctx = context.get_admin_context()
          testvol = fake_volume.fake_volume_obj(ctx, **testvol)
  
          def _fake_get_volume_type(ctxt, type_id):
              return test_type
  
          def _fake_get_qos_spec(ctxt, spec_id):
              return test_qos_spec
  
          def _fake_do_volume_create(account, params):
              params['provider_location'] = '1.1.1.1 iqn 0'
              return params
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
                  mock.patch.object(sfv,
                                    '_get_account_create_availability',
                                    return_value=fake_sfaccounts[0]), \
                  mock.patch.object(sfv,
                                    '_do_volume_create',
                                    side_effect=_fake_do_volume_create), \
                  mock.patch.object(volume_types,
                                    'get_volume_type',
                                    side_effect=_fake_get_volume_type), \
                  mock.patch.object(qos_specs,
                                    'get_qos_specs',
                                    side_effect=_fake_get_qos_spec):
  
              self.assertEqual({'burstIOPS': 3000,
                                'minIOPS': 1000,
                                'maxIOPS': 2000},
                               sfv.create_volume(testvol)['qos'])
  
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      def test_create_volume(self,
                             _mock_issue_api_request):
          _mock_issue_api_request.side_effect = self.fake_issue_api_request
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'volume_type_id': None,
                     'created_at': timeutils.utcnow()}
          fake_sfaccounts = [{'accountID': 5,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid'}]
  
          ctx = context.get_admin_context()
          testvol = fake_volume.fake_volume_obj(ctx, **testvol)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
              mock.patch.object(sfv,
                                '_get_account_create_availability',
                                return_value=fake_sfaccounts[0]):
  
              model_update = sfv.create_volume(testvol)
              self.assertIsNotNone(model_update)
              self.assertNotIn('provider_geometry', model_update)
  
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      def test_create_volume_non_512e(self,
                                      _mock_issue_api_request):
          _mock_issue_api_request.side_effect = self.fake_issue_api_request
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'volume_type_id': None,
                     'created_at': timeutils.utcnow()}
  
          ctx = context.get_admin_context()
          testvol = fake_volume.fake_volume_obj(ctx, **testvol)
  
          fake_sfaccounts = [{'accountID': 5,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid'}]
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
              mock.patch.object(sfv,
                                '_issue_api_request',
                                side_effect=self.fake_issue_api_request), \
              mock.patch.object(sfv,
                                '_get_account_create_availability',
                                return_value=fake_sfaccounts[0]):
  
              self.configuration.sf_emulate_512 = False
              model_update = sfv.create_volume(testvol)
              self.configuration.sf_emulate_512 = True
              self.assertEqual('4096 4096',
                               model_update.get('provider_geometry', None))
  
      def test_create_delete_snapshot(self):
          ctx = context.get_admin_context()
          testvol = fake_volume.fake_volume_obj(ctx)
  
          testsnap_dict = {'project_id': 'testprjid',
                           'name': testvol.name,
                           'volume_size': testvol.size,
                           'id': 'b831c4d1-d1f0-11e1-9b23-0800200c9a66',
                           'volume_id': testvol.id,
                           'volume_type_id': None,
                           'created_at': timeutils.utcnow(),
                           'provider_id': '8 99 None',
                           'volume': testvol}
          testsnap = fake_snapshot.fake_snapshot_obj(ctx, **testsnap_dict)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          fake_uuid = 'UUID-b831c4d1-d1f0-11e1-9b23-0800200c9a66'
          with mock.patch.object(
                  solidfire.SolidFireDriver,
                  '_get_sf_snapshots',
                  return_value=[{'snapshotID': '5',
                                 'name': fake_uuid,
                                 'volumeID': 5}]), \
                  mock.patch.object(sfv,
                                    '_get_sfaccounts_for_tenant',
                                    return_value=[{'accountID': 5,
                                                   'username':
                                                   'prefix-testprjid'}]),\
                  mock.patch.object(sfv, '_retrieve_replication_settings',
                                    return_value=["Async", {}]),\
                  mock.patch.object(sfv, '_get_sf_volume',
                                    return_value={'volumeID': 33}):
              sfv.create_snapshot(testsnap)
              sfv.delete_snapshot(testsnap)
  
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      def test_create_clone(self,
                            _mock_issue_api_request):
          _mock_issue_api_request.side_effect = self.fake_issue_api_request
          _fake_get_snaps = [{'snapshotID': 5, 'name': 'testvol'}]
          _fake_get_volume = (
              {'volumeID': 99,
               'name': 'UUID-a720b3c0-d1f0-11e1-9b23-0800200c9a66',
               'attributes': {}})
  
          updates_vol_a = {'project_id': 'testprjid',
                           'name': 'testvol',
                           'size': 1,
                           'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                           'volume_type_id': None,
                           'created_at': timeutils.utcnow()}
  
          updates_vol_b = {'project_id': 'testprjid',
                           'name': 'testvol',
                           'size': 1,
                           'id': 'b831c4d1-d1f0-11e1-9b23-0800200c9a66',
                           'volume_type_id': None,
                           'created_at': timeutils.utcnow()}
  
          fake_model_info = {
              'provider_id': '%s %s cluster-id-01' % (
                  self.fake_sfvol['volumeID'],
                  self.fake_sfaccount['accountID'])
          }
  
          ctx = context.get_admin_context()
          testvol = fake_volume.fake_volume_obj(ctx, **updates_vol_a)
          testvol_b = fake_volume.fake_volume_obj(ctx, **updates_vol_b)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_sf_snapshots',
                                 return_value=_fake_get_snaps), \
                  mock.patch.object(sfv,
                                    '_get_sf_volume',
                                    return_value=_fake_get_volume), \
                  mock.patch.object(sfv,
                                    '_issue_api_request',
                                    side_effect=self.fake_issue_api_request), \
                  mock.patch.object(sfv,
                                    '_get_sfaccounts_for_tenant',
                                    return_value=[]), \
                  mock.patch.object(sfv,
                                    '_get_model_info',
                                    return_value=fake_model_info):
              sfv.create_cloned_volume(testvol_b, testvol)
  
      def test_initialize_connector_with_blocksizes(self):
          connector = {'initiator': 'iqn.2012-07.org.fake:01'}
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'volume_type_id': None,
                     'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
                                          'solidfire:87hg.uuid-2cc06226-cc'
                                          '74-4cb7-bd55-14aed659a0cc.4060 0',
                     'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
                                      'c76370d66b 2FE0CQ8J196R',
                     'provider_geometry': '4096 4096',
                     'created_at': timeutils.utcnow(),
                     }
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          properties = sfv.initialize_connection(testvol, connector)
          self.assertEqual('4096', properties['data']['physical_block_size'])
          self.assertEqual('4096', properties['data']['logical_block_size'])
          self.assertTrue(properties['data']['discard'])
  
      def test_create_volume_fails(self):
          # NOTE(JDG) This test just fakes update_cluster_status
          # this is inentional for this test
          self.mock_object(solidfire.SolidFireDriver,
                           '_update_cluster_status',
                           self.fake_update_cluster_status)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'created_at': timeutils.utcnow()}
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request_fails)
          try:
              sfv.create_volume(testvol)
              self.fail("Should have thrown Error")
          except Exception:
              pass
  
      def test_create_sfaccount(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          account = sfv._create_sfaccount('some-name')
          self.assertIsNotNone(account)
  
      def test_create_sfaccount_fails(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request_fails)
          self.assertRaises(solidfire.SolidFireAPIException,
                            sfv._create_sfaccount, 'project-id')
  
      def test_get_sfaccounts_for_tenant(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          accounts = sfv._get_sfaccounts_for_tenant('some-name')
          self.assertIsNotNone(accounts)
  
      def test_get_sfaccounts_for_tenant_fails(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request_fails)
          self.assertRaises(solidfire.SolidFireAPIException,
                            sfv._get_sfaccounts_for_tenant, 'some-name')
  
      def test_get_sfaccount_by_name(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          account = sfv._get_sfaccount_by_name('some-name')
          self.assertIsNotNone(account)
  
      def test_get_account_create_availability_no_account(self):
          fake_sfaccounts = []
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfaccount = sfv._get_account_create_availability(fake_sfaccounts)
          self.assertIsNone(sfaccount)
  
      def test_get_account_create_availability(self):
          fake_sfaccounts = [{'accountID': 29,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid',
                              'volumes': [6, 7, 20]}]
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfaccount = sfv._get_account_create_availability(fake_sfaccounts)
          self.assertIsNotNone(sfaccount)
          self.assertEqual(sfaccount['accountID'],
                           fake_sfaccounts[0]['accountID'])
  
      def test_get_account_create_availability_primary_full(self):
          fake_sfaccounts = [{'accountID': 30,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid'}]
          get_sfaccount_result = {'accountID': 31,
                                  'targetSecret': 'shhhh',
                                  'username': 'prefix-testprjid_'}
          get_vol_result = list(range(1, 2001))
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
                  mock.patch.object(sfv,
                                    '_get_volumes_for_account',
                                    return_value=get_vol_result):
              sfaccount = sfv._get_account_create_availability(fake_sfaccounts)
              self.assertIsNotNone(sfaccount)
              self.assertEqual(sfaccount['username'],
                               get_sfaccount_result['username'])
  
      def test_get_account_create_availability_both_full(self):
          fake_sfaccounts = [{'accountID': 32,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid'},
                             {'accountID': 33,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid_'}]
          get_vol_result = list(range(1, 2001))
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
                  mock.patch.object(sfv,
                                    '_get_volumes_for_account',
                                    return_value=get_vol_result):
              sfaccount = sfv._get_account_create_availability(fake_sfaccounts)
              self.assertIsNone(sfaccount)
  
      def test_get_create_account(self):
          fake_sfaccounts = [{'accountID': 34,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid'},
                             {'accountID': 35,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid_'}]
          get_vol_result = list(range(1, 2001))
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
                  mock.patch.object(sfv,
                                    '_get_volumes_for_account',
                                    return_value=get_vol_result):
              sfaccount = sfv._get_account_create_availability(fake_sfaccounts)
              self.assertRaises(solidfire.SolidFireDriverException,
                                sfv._get_create_account, sfaccount)
  
      def test_get_sfaccount_by_name_fails(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request_fails)
          self.assertRaises(solidfire.SolidFireAPIException,
                            sfv._get_sfaccount_by_name, 'some-name')
  
      def test_get_sfvol_by_cinder_vref_no_provider_id(self):
          fake_sfaccounts = [{'accountID': 25,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid',
                              'volumes': [6, 7, 20]}]
          self.mock_vref = mock_vref()
  
          vol_result = {'volumeID': 5,
                        'name': 'test_volume',
                        'accountID': 25,
                        'sliceCount': 1,
                        'totalSize': 1 * units.Gi,
                        'enable512e': True,
                        'access': "readWrite",
                        'status': "active",
                        'attributes': {'uuid': f_uuid[0]},
                        'qos': None,
                        'iqn': 'super_fake_iqn'}
  
          mod_conf = self.configuration
          mod_conf.sf_enable_vag = True
          sfv = solidfire.SolidFireDriver(configuration=mod_conf)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value = fake_sfaccounts), \
                  mock.patch.object(sfv, '_issue_api_request',
                                    side_effect = self.fake_issue_api_request):
              self.mock_vref['provider_id'] = None
              sfvol = sfv._get_sfvol_by_cinder_vref(self.mock_vref)
              self.assertIsNotNone(sfvol)
              self.assertEqual(sfvol['attributes']['uuid'],
                               vol_result['attributes']['uuid'])
              self.assertEqual(sfvol['volumeID'], vol_result['volumeID'])
  
      def test_get_sfvol_by_cinder_vref_no_provider_id_nomatch(self):
          fake_sfaccounts = [{'accountID': 5,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid',
                              'volumes': [5, 6, 7, 8]}]
  
          self.mock_vref = mock_vref()
          mod_conf = self.configuration
          mod_conf.sf_enable_vag = True
  
          sfv = solidfire.SolidFireDriver(configuration=mod_conf)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value = fake_sfaccounts), \
                  mock.patch.object(sfv, '_issue_api_request',
                                    side_effect = self.fake_issue_api_request):
              self.mock_vref['provider_id'] = None
              self.mock_vref['id'] = '142b9c32-a71A-4fbe-830c-c20c5596caea'
              sfvol = sfv._get_sfvol_by_cinder_vref(self.mock_vref)
              self.assertIsNone(sfvol)
  
      def test_get_sfvol_by_cinder_vref_nomatch(self):
          fake_sfaccounts = [{'accountID': 5,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid',
                              'volumes': [5, 6, 7, 8]}]
  
          self.mock_vref = mock_vref()
          mod_conf = self.configuration
          mod_conf.sf_enable_vag = True
          sfv = solidfire.SolidFireDriver(configuration=mod_conf)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value = fake_sfaccounts), \
                  mock.patch.object(sfv, '_issue_api_request',
                                    side_effect = self.fake_issue_api_request):
              p_i = '324 8 6ecebf5d-5521-4ce1-80f3-358ebc1b9cdc'
              self.mock_vref['provider_id'] = p_i
              self.mock_vref['id'] = '142b9c32-a71A-4fbe-830c-c20c5596caea'
              sfvol = sfv._get_sfvol_by_cinder_vref(self.mock_vref)
              self.assertIsNone(sfvol)
  
      def test_get_sfvol_by_cinder_vref(self):
          fake_sfaccounts = [{'accountID': 5,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid',
                              'volumes': [5, 6, 7, 8]}]
  
          self.mock_vref = mock_vref()
  
          get_vol_result = {'volumeID': 5,
                            'name': 'test_volume',
                            'accountID': 25,
                            'sliceCount': 1,
                            'totalSize': 1 * units.Gi,
                            'enable512e': True,
                            'access': "readWrite",
                            'status': "active",
                            'attributes': {'uuid': f_uuid[0]},
                            'qos': None,
                            'iqn': 'super_fake_iqn'}
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv, '_get_sfaccounts_for_tenant',
                                 return_value = fake_sfaccounts), \
                  mock.patch.object(sfv, '_issue_api_request',
                                    side_effect = self.fake_issue_api_request):
  
              sfvol = sfv._get_sfvol_by_cinder_vref(self.mock_vref)
              self.assertIsNotNone(sfvol)
              self.assertEqual(get_vol_result['volumeID'], sfvol['volumeID'])
  
      def test_delete_volume(self):
          vol_id = 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'
          testvol = test_utils.create_volume(
              self.ctxt,
              id=vol_id,
              display_name='test_volume',
              provider_id='1 5 None',
              multiattach=False)
  
          fake_sfaccounts = [{'accountID': 5,
                              'name': 'testprjid',
                              'targetSecret': 'shhhh',
                              'username': 'john-wayne'}]
  
          get_vol_result = {'volumeID': 5,
                            'name': 'test_volume',
                            'accountID': 25,
                            'sliceCount': 1,
                            'totalSize': 1 * units.Gi,
                            'enable512e': True,
                            'access': "readWrite",
                            'status': "active",
                            'attributes': {},
                            'qos': None,
                            'iqn': 'super_fake_iqn'}
  
          mod_conf = self.configuration
          mod_conf.sf_enable_vag = True
          sfv = solidfire.SolidFireDriver(configuration=mod_conf)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
              mock.patch.object(sfv,
                                '_get_sfvol_by_cinder_vref',
                                return_value=get_vol_result), \
              mock.patch.object(sfv,
                                '_issue_api_request'), \
              mock.patch.object(sfv,
                                '_remove_volume_from_vags') as rem_vol:
  
              sfv.delete_volume(testvol)
              rem_vol.not_called(get_vol_result['volumeID'])
  
      def test_delete_multiattach_volume(self):
          vol_id = 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'
          testvol = test_utils.create_volume(
              self.ctxt,
              id=vol_id,
              display_name='test_volume',
              provider_id='1 5 None',
              multiattach=True)
  
          fake_sfaccounts = [{'accountID': 5,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid'}]
  
          get_vol_result = {'volumeID': 5,
                            'name': 'test_volume',
                            'accountID': 25,
                            'sliceCount': 1,
                            'totalSize': 1 * units.Gi,
                            'enable512e': True,
                            'access': "readWrite",
                            'status': "active",
                            'attributes': {},
                            'qos': None,
                            'iqn': 'super_fake_iqn'}
  
          mod_conf = self.configuration
          mod_conf.sf_enable_vag = True
          sfv = solidfire.SolidFireDriver(configuration=mod_conf)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
              mock.patch.object(sfv,
                                '_get_sfvol_by_cinder_vref',
                                return_value=get_vol_result), \
              mock.patch.object(sfv,
                                '_issue_api_request'), \
              mock.patch.object(sfv,
                                '_remove_volume_from_vags') as rem_vol:
  
              sfv.delete_volume(testvol)
              rem_vol.assert_called_with(get_vol_result['volumeID'])
  
      def test_delete_volume_no_volume_on_backend(self):
          fake_sfaccounts = [{'accountID': 5,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid'}]
          fake_no_volumes = []
          testvol = test_utils.create_volume(self.ctxt)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
              mock.patch.object(sfv,
                                '_get_volumes_for_account',
                                return_value=fake_no_volumes):
              sfv.delete_volume(testvol)
  
      def test_delete_snapshot_no_snapshot_on_backend(self):
          fake_sfaccounts = [{'accountID': 5,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid'}]
          fake_no_volumes = []
          testvol = test_utils.create_volume(
              self.ctxt,
              volume_id='b831c4d1-d1f0-11e1-9b23-0800200c9a66')
          testsnap = test_utils.create_snapshot(
              self.ctxt,
              volume_id=testvol.id)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
              mock.patch.object(sfv,
                                '_get_volumes_for_account',
                                return_value=fake_no_volumes):
              sfv.delete_snapshot(testsnap)
  
      def fake_ext_qos_issue_api_request(self, method, params, version='1.0',
                                         endpoint=None):
          EXPECTED_SIZE = 2 << 30  # 2147483648 size + increase
  
          if method == 'ModifyVolume':
              response = {'error': {'code': 0,
                                    'name': 'Extend Volume',
                                    'message': 'extend fail, size/scale-iops'},
                          'id': 1}
              if params.get('totalSize', None) != EXPECTED_SIZE:
                  msg = ('Error (%s) encountered during '
                         'SolidFire API call.' % response['error']['name'])
                  raise solidfire.SolidFireAPIException(message=msg)
  
              if params.get('qos', None) != SolidFireVolumeTestCase.EXPECTED_QOS:
                  msg = ('Error (%s) encountered during '
                         'SolidFire API call.' % response['error']['name'])
                  raise solidfire.SolidFireAPIException(message=msg)
  
              return {'result': {}, 'id': 1}
  
          elif method == 'GetAccountByName' and version == '1.0':
              results = {'result': {'account':
                                    {'accountID': 25,
                                     'username': params['username'],
                                     'status': 'active',
                                     'initiatorSecret': '123456789012',
                                     'targetSecret': '123456789012',
                                     'attributes': {},
                                     'volumes': [6, 7, 20]}},
                         "id": 1}
              return results
  
          elif method == 'ListVolumesForAccount' and version == '1.0':
              test_name = 'OS-VOLID-a720b3c0-d1f0-11e1-9b23-0800200c9a66'
              result = {'result': {
                  'volumes': [{'volumeID': 5,
                               'name': test_name,
                               'accountID': 25,
                               'sliceCount': 1,
                               'totalSize': 1 * units.Gi,
                               'enable512e': True,
                               'access': "readWrite",
                               'status': "active",
                               'attributes': {},
                               'qos': None,
                               'iqn': test_name}]}}
              return result
  
          else:
              return None
  
      def test_extend_volume(self):
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          testvol = {'project_id': 'testprjid',
                     'name': 'test_volume',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'created_at': timeutils.utcnow()}
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.extend_volume(testvol, 2)
  
      def test_extend_volume_with_scaled_qos(self):
          size = 1
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          qos_ref = qos_specs.create(self.ctxt,
                                     'qos-specs-1', {'minIOPS': '100',
                                                     'maxIOPS': '1000',
                                                     'burstIOPS': '1500',
                                                     'scaledIOPS': 'True',
                                                     'scaleMin': '10',
                                                     'scaleMax': '20',
                                                     'scaleBurst': '30'})
          type_ref = volume_types.create(self.ctxt, "type1",
                                         {'qos:minIOPS': '1000',
                                          'qos:maxIOPS': '10000',
                                          'qos:burstIOPS': '20000'})
          qos_specs.associate_qos_with_type(self.ctxt,
                                            qos_ref['id'],
                                            type_ref['id'])
          qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size + 1)
          self.assertEqual(SolidFireVolumeTestCase.EXPECTED_QOS, qos)
  
      def test_extend_volume_fails_no_volume(self):
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          testvol = {'project_id': 'testprjid',
                     'name': 'no-name',
                     'size': 1,
                     'id': 'not-found'}
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.assertRaises(exception.VolumeNotFound,
                            sfv.extend_volume,
                            testvol, 2)
  
      def test_extend_volume_fails_account_lookup(self):
          # NOTE(JDG) This test just fakes update_cluster_status
          # this is intentional for this test
          self.mock_object(solidfire.SolidFireDriver,
                           '_update_cluster_status',
                           self.fake_update_cluster_status)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          testvol = {'project_id': 'testprjid',
                     'name': 'no-name',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'created_at': timeutils.utcnow()}
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request_fails)
          self.assertRaises(solidfire.SolidFireAPIException,
                            sfv.extend_volume,
                            testvol, 2)
  
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_retrieve_qos_setting')
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      @mock.patch.object(solidfire.SolidFireDriver,
                         '_retrieve_replication_settings')
      @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
      def test_extend_replicated_volume(self, mock_create_cluster_reference,
                                        mock_retrieve_replication_settings,
                                        mock_issue_api_request,
                                        mock_retrieve_qos_setting,
                                        mock_get_sf_volume,
                                        mock_get_sfaccount):
  
          mock_create_cluster_reference.return_value = {
              'mvip': self.mvip,
              'svip': self.svip}
  
          mock_retrieve_replication_settings.return_value = "Async"
          mock_retrieve_qos_setting.return_value = None
          self.fake_sfvol['volumePairs'] = [{'remoteVolumeID': 26}]
          mock_get_sf_volume.return_value = self.fake_sfvol
          mock_get_sfaccount.return_value = self.fake_sfaccount
  
          ctx = context.get_admin_context()
          utc_now = timeutils.utcnow().isoformat()
          vol_fields = {
              'id': f_uuid,
              'created_at': utc_now
          }
          vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.replication_enabled = True
          sfv.cluster_pairs = self.cluster_pairs
          sfv.active_cluster['mvip'] = self.mvip
          sfv.active_cluster['svip'] = self.svip
  
          mock_issue_api_request.reset_mock()
          # pylint: disable=assignment-from-no-return
          updates = sfv.extend_volume(vol, vol.size + 10)
          # pylint: enable=assignment-from-no-return
          self.assertIsNone(updates)
  
          modify_params = {
              'volumeID': self.fake_sfvol['volumeID'],
              'totalSize': int((vol.size + 10) * units.Gi),
              'qos': None
          }
          modify_params2 = modify_params.copy()
          modify_params2['volumeID'] = 26
  
          expected_calls = [
              mock.call("ModifyVolume", modify_params, version='5.0'),
              mock.call("ModifyVolume", modify_params2, version='5.0',
                        endpoint=self.cluster_pairs[0]['endpoint'])
          ]
  
          mock_issue_api_request.assert_has_calls(expected_calls)
          mock_create_cluster_reference.assert_called()
          mock_retrieve_replication_settings.assert_called_with(vol)
          mock_retrieve_qos_setting.assert_called_with(vol, vol.size + 10)
          mock_get_sf_volume.assert_called_with(
              vol.id, {'accountID': self.fake_sfaccount['accountID']})
          mock_get_sfaccount.assert_called_with(vol.project_id)
  
      def test_set_by_qos_spec_with_scoping(self):
          size = 1
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          qos_ref = qos_specs.create(self.ctxt,
                                     'qos-specs-1', {'qos:minIOPS': '1000',
                                                     'qos:maxIOPS': '10000',
                                                     'qos:burstIOPS': '20000'})
          type_ref = volume_types.create(self.ctxt,
                                         "type1", {"qos:minIOPS": "100",
                                                   "qos:burstIOPS": "300",
                                                   "qos:maxIOPS": "200"})
          qos_specs.associate_qos_with_type(self.ctxt,
                                            qos_ref['id'],
                                            type_ref['id'])
          qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size)
          self.assertEqual(self.expected_qos_results, qos)
  
      def test_set_by_qos_spec(self):
          size = 1
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          qos_ref = qos_specs.create(self.ctxt,
                                     'qos-specs-1', {'minIOPS': '1000',
                                                     'maxIOPS': '10000',
                                                     'burstIOPS': '20000'})
          type_ref = volume_types.create(self.ctxt,
                                         "type1", {"qos:minIOPS": "100",
                                                   "qos:burstIOPS": "300",
                                                   "qos:maxIOPS": "200"})
          qos_specs.associate_qos_with_type(self.ctxt,
                                            qos_ref['id'],
                                            type_ref['id'])
          qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size)
          self.assertEqual(self.expected_qos_results, qos)
  
      @file_data("scaled_iops_test_data.json")
      @unpack
      def test_scaled_qos_spec_by_type(self, argument):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          size = argument[0].pop('size')
          type_ref = volume_types.create(self.ctxt, "type1", argument[0])
          qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size)
          self.assertEqual(argument[1], qos)
  
      @file_data("scaled_iops_invalid_data.json")
      @unpack
      def test_set_scaled_qos_by_type_invalid(self, inputs):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          size = inputs[0].pop('size')
          type_ref = volume_types.create(self.ctxt, "type1", inputs[0])
          self.assertRaises(exception.InvalidQoSSpecs,
                            sfv._set_qos_by_volume_type,
                            self.ctxt,
                            type_ref['id'],
                            size)
  
      def test_accept_transfer(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          testvol = {'project_id': 'testprjid',
                     'name': 'test_volume',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'created_at': timeutils.utcnow()}
          expected = {'provider_auth': 'CHAP cinder-new_project 123456789012'}
          self.assertEqual(expected,
                           sfv.accept_transfer(self.ctxt,
                                               testvol,
                                               'new_user', 'new_project'))
  
      def test_accept_transfer_volume_not_found_raises(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          testvol = {'project_id': 'testprjid',
                     'name': 'test_volume',
                     'size': 1,
                     'id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
                     'created_at': timeutils.utcnow()}
          self.assertRaises(exception.VolumeNotFound,
                            sfv.accept_transfer,
                            self.ctxt,
                            testvol,
                            'new_user',
                            'new_project')
  
      def test_retype(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          type_ref = volume_types.create(self.ctxt,
                                         "type1", {"qos:minIOPS": "500",
                                                   "qos:burstIOPS": "2000",
                                                   "qos:maxIOPS": "1000"})
          diff = {'encryption': {}, 'qos_specs': {},
                  'extra_specs': {'qos:burstIOPS': ('10000', u'2000'),
                                  'qos:minIOPS': ('1000', u'500'),
                                  'qos:maxIOPS': ('10000', u'1000')}}
          host = None
          updates = {'project_id': 'testprjid',
                     'name': 'test_volume',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'created_at': timeutils.utcnow()}
  
          ctx = context.get_admin_context()
          testvol = fake_volume.fake_volume_obj(ctx, **updates)
  
          migrated, updates = sfv.retype(self.ctxt, testvol, type_ref,
                                         diff, host)
          self.assertTrue(migrated)
          self.assertEqual({}, updates)
  
      @data(None, 'Success', 'Error', 'target:{}'.format(f_uuid[0]))
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
      def test_attach_volume(self, mig_status, mock_get_sfaccount,
                             mock_get_sf_volume):
  
          mock_get_sfaccount.return_value = self.fake_sfaccount
          i_uuid = 'fake_instance_uuid'
          ctx = context.get_admin_context()
          type_fields = {}
          vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
          utc_now = timeutils.utcnow().isoformat()
          vol_fields = {
              'id': f_uuid[0],
              'created_at': utc_now,
              'volume_type': vol_type,
              'volume_type_id': vol_type.id,
              'migration_status': mig_status,
          }
          vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
          sf_vol = self.fake_sfvol
          mock_get_sf_volume.return_value = sf_vol
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.attach_volume(ctx, vol, i_uuid, 'fake_host', '/dev/sdf')
          self.assertEqual(sf_vol['attributes']['attached_to'],
                           i_uuid)
          mock_get_sfaccount.assert_called()
          mock_get_sf_volume.assert_called()
  
      def test_retype_with_qos_spec(self):
          test_type = {'name': 'sf-1',
                       'qos_specs_id': 'fb0576d7-b4b5-4cad-85dc-ca92e6a497d1',
                       'deleted': False,
                       'created_at': '2014-02-06 04:58:11',
                       'updated_at': None,
                       'extra_specs': {},
                       'deleted_at': None,
                       'id': 'e730e97b-bc7d-4af3-934a-32e59b218e81'}
  
          test_qos_spec = {'id': 'asdfafdasdf',
                           'specs': {'minIOPS': '1000',
                                     'maxIOPS': '2000',
                                     'burstIOPS': '3000'}}
  
          def _fake_get_volume_type(ctxt, type_id):
              return test_type
  
          def _fake_get_qos_spec(ctxt, spec_id):
              return test_qos_spec
  
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          self.mock_object(volume_types, 'get_volume_type',
                           _fake_get_volume_type)
          self.mock_object(qos_specs, 'get_qos_specs',
                           _fake_get_qos_spec)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  
          diff = {'encryption': {}, 'extra_specs': {},
                  'qos_specs': {'burstIOPS': ('10000', '2000'),
                                'minIOPS': ('1000', '500'),
                                'maxIOPS': ('10000', '1000')}}
          host = None
          updates = {'project_id': 'testprjid',
                     'name': 'test_volume',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'created_at': timeutils.utcnow()}
          ctx = context.get_admin_context()
          testvol = fake_volume.fake_volume_obj(ctx, **updates)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          migrated, updates = sfv.retype(self.ctxt, testvol, test_type,
                                         diff, host)
          self.assertTrue(migrated)
          self.assertEqual({}, updates)
  
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_set_rep_by_volume_type')
      @mock.patch.object(solidfire.SolidFireDriver,
                         '_retrieve_replication_settings')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_default_volume_params')
      @mock.patch.object(solidfire.SolidFireDriver, '_replicate_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_disable_replication')
      @mock.patch.object(solidfire.SolidFireDriver, '_set_qos_by_volume_type')
      def test_retype_replicated(self,
                                 mock_set_qos_by_volume_type,
                                 mock_disable_replication,
                                 mock_replicate_volume,
                                 mock_get_default_volume_params,
                                 mock_retrieve_replication_settings,
                                 mock_set_rep_by_volume_type,
                                 mock_get_sf_volume,
                                 mock_get_sfaccount):
  
          all_mocks = locals()
          mock_get_sf_volume.return_value = None
          mock_get_sfaccount.return_value = self.fake_sfaccount
          mock_retrieve_replication_settings.return_value = 'Async'
  
          ctx = context.get_admin_context()
          type_fields = {'extra_specs': {'replication_enabled': '<is> True'},
                         'id': fakes.get_fake_uuid()}
          src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
  
          fake_provider_id = "%s %s %s" % (
              self.fake_sfvol['volumeID'],
              fakes.FAKE_UUID,
              self.cluster_pairs[0]['uuid'])
          utc_now = timeutils.utcnow().isoformat()
          vol_fields = {
              'id': fakes.FAKE_UUID,
              'created_at': utc_now,
              'volume_type': src_vol_type,
              'volume_type_id': src_vol_type.id,
              'provider_id': fake_provider_id
          }
  
          vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
          dst_vol_type = fake_volume.fake_volume_type_obj(ctx)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.replication_enabled = True
          sfv.cluster_pairs = self.cluster_pairs
          sfv.active_cluster['mvip'] = self.mvip
          sfv.active_cluster['svip'] = self.svip
  
          self.assertRaises(exception.VolumeNotFound,
                            sfv.retype, ctx, vol, dst_vol_type, None, None)
          mock_get_sfaccount.assert_called_once_with(vol.project_id)
          mock_get_sf_volume.assert_called_once_with(
              vol.id, {'accountID': self.fake_sfaccount['accountID']})
  
          mock_get_sfaccount.reset_mock()
          mock_get_sf_volume.reset_mock()
          expected = {"key": "value"}
          mock_get_sf_volume.return_value = self.fake_sfvol
          mock_replicate_volume.return_value = expected
          mock_set_rep_by_volume_type.side_effect = [src_vol_type, dst_vol_type]
  
          retyped, updates = sfv.retype(ctx, vol, dst_vol_type, None, None)
          self.assertDictEqual(expected, updates)
  
          mock_get_sfaccount.assert_called_once_with(vol.project_id)
          mock_get_sf_volume.assert_called_once_with(
              vol.id, {'accountID': self.fake_sfaccount['accountID']})
          mock_get_default_volume_params.assert_called()
          mock_disable_replication.assert_not_called()
          mock_replicate_volume.assert_called_once()
          mock_retrieve_replication_settings.assert_called_once()
          mock_set_qos_by_volume_type.assert_called_once()
  
          expected = {}
          for mk in all_mocks.values():
              if isinstance(mk, mock.MagicMock):
                  mk.reset_mock()
  
          mock_set_rep_by_volume_type.side_effect = [src_vol_type, None]
          retyped, updates = sfv.retype(ctx, vol, dst_vol_type, None, None)
          self.assertDictEqual(expected, updates)
          mock_get_sfaccount.assert_called_once_with(vol.project_id)
          mock_get_sf_volume.assert_called_once_with(
              vol.id, {'accountID': self.fake_sfaccount['accountID']})
          mock_get_default_volume_params.assert_not_called()
          mock_disable_replication.assert_called_with(vol)
          mock_replicate_volume.assert_not_called()
          mock_retrieve_replication_settings.assert_not_called()
          mock_set_qos_by_volume_type.assert_called_once()
  
      def test_update_cluster_status(self):
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
  
          driver_defined_stats = ['volume_backend_name', 'vendor_name',
                                  'driver_version', 'storage_protocol',
                                  'consistencygroup_support',
                                  'consistent_group_snapshot_enabled',
                                  'replication_enabled', 'active_cluster_mvip',
                                  'reserved_percentage', 'QoS_support',
                                  'multiattach', 'total_capacity_gb',
                                  'free_capacity_gb', 'compression_percent',
                                  'deduplicaton_percent',
                                  'thin_provision_percent', 'provisioned_iops',
                                  'current_iops', 'average_iops', 'max_iops',
                                  'peak_iops']
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv._update_cluster_status()
  
          for key in driver_defined_stats:
              if sfv.cluster_stats.get(key, None) is None:
                  msg = 'Key %s should be present at driver stats.' % key
                  raise exception.CinderException(message=msg)
  
          sfv.configuration.sf_provisioning_calc = 'usedSpace'
          sfv._update_cluster_status()
          driver_defined_stats += ['thin_provisioning_support',
                                   'provisioned_capacity_gb',
                                   'max_over_subscription_ratio']
  
          for key in driver_defined_stats:
              self.assertIn(key, driver_defined_stats)
  
      def test_update_cluster_status_mvip_unreachable(self):
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 side_effect=self.fake_issue_api_request_fails):
              sfv._update_cluster_status()
              self.assertEqual(0, sfv.cluster_stats['free_capacity_gb'])
              self.assertEqual(0, sfv.cluster_stats['total_capacity_gb'])
  
      def test_manage_existing_volume(self):
          external_ref = {'name': 'existing volume', 'source-id': 5}
          updates = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'created_at': timeutils.utcnow()}
          ctx = context.get_admin_context()
          testvol = fake_volume.fake_volume_obj(ctx, **updates)
  
          self.mock_object(solidfire.SolidFireDriver,
                           '_issue_api_request',
                           self.fake_issue_api_request)
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          model_update = sfv.manage_existing(testvol, external_ref)
          self.assertIsNotNone(model_update)
          self.assertNotIn('provider_geometry', model_update)
  
      def test_manage_existing_get_size(self):
          external_ref = {'name': 'existing volume', 'source-id': 5}
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'created_at': timeutils.utcnow()}
          mock_issue_api_request = self.mock_object(solidfire.SolidFireDriver,
                                                    '_issue_api_request')
          mock_issue_api_request.side_effect = self.fake_issue_api_request
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          size = sfv.manage_existing_get_size(testvol, external_ref)
          self.assertEqual(2, size)
  
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_create_account')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_default_volume_params')
      @mock.patch.object(solidfire.SolidFireDriver,
                         '_retrieve_replication_settings')
      @mock.patch.object(solidfire.SolidFireDriver, '_replicate_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_model_info')
      @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
      @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
      def test_manage_existing_replicated_fail(
              self,
              mock_create_cluster_reference,
              mock_update_cluster_status,
              mock_get_model_info,
              mock_replicate_volume,
              mock_retrieve_replication_settings,
              mock_get_default_volume_params,
              mock_get_create_account,
              mock_issue_api_request):
  
          mock_retrieve_replication_settings.return_value = 'Async'
          mock_get_default_volume_params.return_value = {'totalSize': 50}
          mock_get_create_account.return_value = self.fake_sfaccount
          mock_replicate_volume.side_effect = solidfire.SolidFireAPIException
  
          ctx = context.get_admin_context()
          type_fields = {'extra_specs': {'replication_enabled': '<is> True'},
                         'id': fakes.get_fake_uuid()}
          vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
  
          fake_provider_id = "%s %s %s" % (
              self.fake_sfvol['volumeID'],
              fakes.FAKE_UUID,
              self.cluster_pairs[0]['uuid'])
          utc_now = timeutils.utcnow().isoformat()
          vol_fields = {
              'id': fakes.FAKE_UUID,
              'created_at': utc_now,
              'volume_type': vol_type,
              'volume_type_id': vol_type.id,
              'provider_id': fake_provider_id
          }
  
          vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.replication_enabled = True
          sfv.active_cluster['mvip'] = self.mvip
          sfv.active_cluster['svip'] = self.svip
  
          external_ref = {}
          self.assertRaises(solidfire.SolidFireAPIException,
                            sfv.manage_existing, vol, external_ref)
  
          self.fake_sfvol['volumePairs'] = [{'remoteVolumeID': 26}]
          mock_issue_api_request.return_value = {
              'result': {'volumes': [self.fake_sfvol]}}
          external_ref = {'source-id': 6, 'name': 'new-being-managed'}
          self.assertRaises(solidfire.SolidFireDriverException,
                            sfv.manage_existing, vol, external_ref)
  
          mock_get_default_volume_params.return_value = {'totalSize': 50}
          self.fake_sfvol['volumePairs'] = []
          mock_issue_api_request.return_value = {
              'result': {'volumes': [self.fake_sfvol]}}
          self.assertRaises(solidfire.SolidFireAPIException,
                            sfv.manage_existing, vol, external_ref)
  
          modify_attributes = {'uuid': vol.id,
                               'is_clone': 'False',
                               'os_imported_at': utc_now + "+00:00",
                               'old_name': 'new-being-managed'}
          modify_params1 = {'volumeID': self.fake_sfvol['volumeID'],
                            'attributes': modify_attributes}
          modify_params2 = {'volumeID': self.fake_sfvol['volumeID'],
                            'attributes': self.fake_sfvol['attributes']}
          calls = [mock.call('ListActiveVolumes',
                             {'startVolumeID': self.fake_sfvol['volumeID'],
                              'limit': 1}),
                   mock.call('ModifyVolume', modify_params1, version='5.0'),
                   mock.call('ModifyVolume', modify_params2, version='5.0')]
  
          mock_issue_api_request.assert_has_calls(calls)
          mock_get_model_info.assert_not_called()
          mock_create_cluster_reference.assert_called_once()
          mock_update_cluster_status.assert_called_once()
          mock_replicate_volume.assert_called()
          mock_retrieve_replication_settings.assert_called_with(vol)
          mock_get_default_volume_params.assert_called_with(vol)
          mock_get_create_account.assert_called_with(vol.project_id)
  
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_set_rep_by_volume_type')
      @mock.patch.object(solidfire.SolidFireDriver,
                         '_retrieve_replication_settings')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_default_volume_params')
      @mock.patch.object(solidfire.SolidFireDriver, '_replicate_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_disable_replication')
      @mock.patch.object(solidfire.SolidFireDriver, '_set_qos_by_volume_type')
      def test_manage_existing_replicated(
              self,
              mock_set_qos_by_volume_type,
              mock_disable_replication,
              mock_replicate_volume,
              mock_get_default_volume_params,
              mock_retrieve_replication_settings,
              mock_set_rep_by_volume_type,
              mock_get_sf_volume,
              mock_get_sfaccount):
  
          mock_get_sf_volume.return_value = None
          mock_get_sfaccount.return_value = self.fake_sfaccount
          mock_retrieve_replication_settings.return_value = 'Async'
  
          ctx = context.get_admin_context()
          type_fields = {'extra_specs': {'replication_enabled': '<is> True'},
                         'id': fakes.get_fake_uuid()}
          src_vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
  
          fake_provider_id = "%s %s %s" % (
              self.fake_sfvol['volumeID'],
              fakes.FAKE_UUID,
              self.cluster_pairs[0]['uuid'])
          utc_now = timeutils.utcnow().isoformat()
          vol_fields = {
              'id': fakes.FAKE_UUID,
              'created_at': utc_now,
              'volume_type': src_vol_type,
              'volume_type_id': src_vol_type.id,
              'provider_id': fake_provider_id
          }
  
          vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
          dst_vol_type = fake_volume.fake_volume_type_obj(ctx)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.replication_enabled = True
          sfv.cluster_pairs = self.cluster_pairs
          sfv.active_cluster['mvip'] = self.mvip
          sfv.active_cluster['svip'] = self.svip
  
          self.assertRaises(exception.VolumeNotFound,
                            sfv.retype, ctx, vol, dst_vol_type, None, None)
          mock_get_sfaccount.assert_called_once_with(vol.project_id)
          mock_get_sf_volume.assert_called_once_with(
              vol.id, {'accountID': self.fake_sfaccount['accountID']})
  
          mock_get_sfaccount.reset_mock()
          mock_get_sf_volume.reset_mock()
          expected = {"key": "value"}
          mock_get_sf_volume.return_value = self.fake_sfvol
          mock_replicate_volume.return_value = expected
          mock_set_rep_by_volume_type.side_effect = [src_vol_type, dst_vol_type]
  
          retyped, updates = sfv.retype(ctx, vol, dst_vol_type, None, None)
          self.assertDictEqual(expected, updates)
  
          mock_get_sfaccount.assert_called_once_with(vol.project_id)
          mock_get_sf_volume.assert_called_once_with(
              vol.id, {'accountID': self.fake_sfaccount['accountID']})
          mock_get_default_volume_params.assert_called()
          mock_disable_replication.assert_not_called()
          mock_replicate_volume.assert_called_once()
          mock_retrieve_replication_settings.assert_called_once()
          mock_set_qos_by_volume_type.assert_called_once()
          mock_set_rep_by_volume_type.assert_called()
  
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      def test_create_volume_for_migration(self,
                                           _mock_issue_api_request):
          _mock_issue_api_request.side_effect = self.fake_issue_api_request
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'b830b3c0-d1f0-11e1-9b23-1900200c9a77',
                     'volume_type_id': None,
                     'created_at': timeutils.utcnow(),
                     'migration_status': 'target:'
                                         'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
          ctx = context.get_admin_context()
          testvol = fake_volume.fake_volume_obj(ctx, **testvol)
          fake_sfaccounts = [{'accountID': 5,
                              'targetSecret': 'shhhh',
                              'username': 'prefix-testprjid'}]
  
          def _fake_do_v_create(project_id, params):
              cvol = {
                  'name': 'UUID-a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                  'attributes': {
                      'uuid': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                      'migration_uuid': 'b830b3c0-d1f0-11e1-9b23-1900200c9a77'
                  }
              }
              return cvol
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_sfaccounts_for_tenant',
                                 return_value=fake_sfaccounts), \
                  mock.patch.object(sfv,
                                    '_get_account_create_availability',
                                    return_value=fake_sfaccounts[0]), \
                  mock.patch.object(sfv,
                                    '_do_volume_create',
                                    side_effect=_fake_do_v_create):
  
              sf_vol_object = sfv.create_volume(testvol)
              self.assertEqual('a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                               sf_vol_object['attributes']['uuid'])
              self.assertEqual('b830b3c0-d1f0-11e1-9b23-1900200c9a77',
                               sf_vol_object['attributes']['migration_uuid'])
              self.assertEqual('UUID-a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                               sf_vol_object['name'])
  
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      def test_clone_image_not_configured(self, _mock_issue_api_request):
          _mock_issue_api_request.side_effect = self.fake_issue_api_request
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          self.assertEqual((None, False),
                           sfv.clone_image(self.ctxt,
                                           self.mock_volume,
                                           'fake',
                                           self.fake_image_meta,
                                           'fake'))
  
      def test_init_volume_mappings(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  
          vid_1 = 'c9125d6d-22ff-4cc3-974d-d4e350df9c91'
          vid_2 = '79883868-6933-47a1-a362-edfbf8d55a18'
          sid_1 = 'e3caa4fa-485e-45ca-970e-1d3e693a2520'
          project_1 = 'e6fb073c-11f0-4f4c-897c-90e7c7c4bcf8'
          project_2 = '4ff32607-305c-4a6b-a51a-0dd33124eecf'
  
          vrefs = [{'id': vid_1,
                    'project_id': project_1,
                    'provider_id': None},
                   {'id': vid_2,
                    'project_id': project_2,
                    'provider_id': 22}]
          snaprefs = [{'id': sid_1,
                       'project_id': project_1,
                       'provider_id': None,
                       'volume_id': vid_1}]
          sf_vols = [{'volumeID': 99,
                      'name': 'UUID-' + vid_1,
                      'accountID': 100},
                     {'volumeID': 22,
                      'name': 'UUID-' + vid_2,
                      'accountID': 200}]
          sf_snaps = [{'snapshotID': 1,
                       'name': 'UUID-' + sid_1,
                       'volumeID': 99}]
  
          def _fake_issue_api_req(method, params, version=0):
              if 'ListActiveVolumes' in method:
                  return {'result': {'volumes': sf_vols}}
              if 'ListSnapshots'in method:
                  return {'result': {'snapshots': sf_snaps}}
  
          with mock.patch.object(sfv, '_issue_api_request',
                                 side_effect=_fake_issue_api_req):
              volume_updates, snapshot_updates = sfv.update_provider_info(
                  vrefs, snaprefs)
              self.assertEqual('99 100 53c8be1e-89e2-4f7f-a2e3-7cb84c47e0ec',
                               volume_updates[0]['provider_id'])
              self.assertEqual(1, len(volume_updates))
  
              self.assertEqual('1 99 53c8be1e-89e2-4f7f-a2e3-7cb84c47e0ec',
                               snapshot_updates[0]['provider_id'])
              self.assertEqual(1, len(snapshot_updates))
  
      def test_get_sf_volume_missing_attributes(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          test_name = "existing_volume"
          fake_response = {'result': {
              'volumes': [{'volumeID': 5,
                           'name': test_name,
                           'accountID': 8,
                           'sliceCount': 1,
                           'totalSize': 1 * units.Gi,
                           'enable512e': True,
                           'access': "readWrite",
                           'status': "active",
                           'qos': None,
                           'iqn': test_name}]}}
  
          def _fake_issue_api_req(method, params, version=0, endpoint=None):
              return fake_response
  
          with mock.patch.object(
                  sfv, '_issue_api_request', side_effect=_fake_issue_api_req):
              self.assertEqual(5, sfv._get_sf_volume(test_name, 8)['volumeID'])
  
      def test_sf_init_conn_with_vag(self):
          # Verify with the _enable_vag conf set that we correctly create a VAG.
          mod_conf = self.configuration
          mod_conf.sf_enable_vag = True
          sfv = solidfire.SolidFireDriver(configuration=mod_conf)
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'volume_type_id': None,
                     'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
                                          'solidfire:87hg.uuid-2cc06226-cc'
                                          '74-4cb7-bd55-14aed659a0cc.4060 0',
                     'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
                                      'c76370d66b 2FE0CQ8J196R',
                     'provider_geometry': '4096 4096',
                     'created_at': timeutils.utcnow(),
                     'provider_id': "1 1 1"
                     }
          connector = {'initiator': 'iqn.2012-07.org.fake:01'}
          provider_id = testvol['provider_id']
          vol_id = int(provider_id.split()[0])
          vag_id = 1
  
          with mock.patch.object(sfv,
                                 '_safe_create_vag',
                                 return_value=vag_id) as create_vag, \
              mock.patch.object(sfv,
                                '_add_volume_to_vag') as add_vol:
              sfv._sf_initialize_connection(testvol, connector)
              create_vag.assert_called_with(connector['initiator'],
                                            vol_id)
              add_vol.assert_called_with(vol_id,
                                         connector['initiator'],
                                         vag_id)
  
      def test_sf_term_conn_with_vag_rem_vag(self):
          # Verify we correctly remove an empty VAG on detach.
          mod_conf = self.configuration
          mod_conf.sf_enable_vag = True
          sfv = solidfire.SolidFireDriver(configuration=mod_conf)
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'volume_type_id': None,
                     'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
                                          'solidfire:87hg.uuid-2cc06226-cc'
                                          '74-4cb7-bd55-14aed659a0cc.4060 0',
                     'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
                                      'c76370d66b 2FE0CQ8J196R',
                     'provider_geometry': '4096 4096',
                     'created_at': timeutils.utcnow(),
                     'provider_id': "1 1 1",
                     'multiattach': False
                     }
          connector = {'initiator': 'iqn.2012-07.org.fake:01'}
          vag_id = 1
          vags = [{'attributes': {},
                   'deletedVolumes': [],
                   'initiators': [connector['initiator']],
                   'name': 'fakeiqn',
                   'volumeAccessGroupID': vag_id,
                   'volumes': [1],
                   'virtualNetworkIDs': []}]
  
          with mock.patch.object(sfv,
                                 '_get_vags_by_name',
                                 return_value=vags), \
              mock.patch.object(sfv,
                                '_remove_vag') as rem_vag:
              sfv._sf_terminate_connection(testvol, connector, False)
              rem_vag.assert_called_with(vag_id)
  
      def test_sf_term_conn_with_vag_rem_vol(self):
          # Verify we correctly remove a the volume from a non-empty VAG.
          mod_conf = self.configuration
          mod_conf.sf_enable_vag = True
          sfv = solidfire.SolidFireDriver(configuration=mod_conf)
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'volume_type_id': None,
                     'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
                                          'solidfire:87hg.uuid-2cc06226-cc'
                                          '74-4cb7-bd55-14aed659a0cc.4060 0',
                     'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
                                      'c76370d66b 2FE0CQ8J196R',
                     'provider_geometry': '4096 4096',
                     'created_at': timeutils.utcnow(),
                     'provider_id': "1 1 1",
                     'multiattach': False
                     }
          provider_id = testvol['provider_id']
          vol_id = int(provider_id.split()[0])
          connector = {'initiator': 'iqn.2012-07.org.fake:01'}
          vag_id = 1
          vags = [{'attributes': {},
                   'deletedVolumes': [],
                   'initiators': [connector['initiator']],
                   'name': 'fakeiqn',
                   'volumeAccessGroupID': vag_id,
                   'volumes': [1, 2],
                   'virtualNetworkIDs': []}]
  
          with mock.patch.object(sfv,
                                 '_get_vags_by_name',
                                 return_value=vags), \
              mock.patch.object(sfv,
                                '_remove_volume_from_vag') as rem_vag:
              sfv._sf_terminate_connection(testvol, connector, False)
              rem_vag.assert_called_with(vol_id, vag_id)
  
      def test_sf_term_conn_without_connector(self):
          # Verify we correctly force the deletion of a volume.
          mod_conf = self.configuration
          mod_conf.sf_enable_vag = True
          sfv = solidfire.SolidFireDriver(configuration=mod_conf)
          testvol = {'project_id': 'testprjid',
                     'name': 'testvol',
                     'size': 1,
                     'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
                     'volume_type_id': None,
                     'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
                                          'solidfire:87hg.uuid-2cc06226-cc'
                                          '74-4cb7-bd55-14aed659a0cc.4060 0',
                     'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
                                      'c76370d66b 2FE0CQ8J196R',
                     'provider_geometry': '4096 4096',
                     'created_at': timeutils.utcnow(),
                     'provider_id': "1 1 1",
                     'multiattach': False
                     }
          provider_id = testvol['provider_id']
          vol_id = int(provider_id.split()[0])
          vag_id = 1
          vags = [{'attributes': {},
                   'deletedVolumes': [],
                   'initiators': ['iqn.2012-07.org.fake:01'],
                   'name': 'fakeiqn',
                   'volumeAccessGroupID': vag_id,
                   'volumes': [1, 2],
                   'virtualNetworkIDs': []}]
  
          with mock.patch.object(sfv,
                                 '_get_vags_by_volume',
                                 return_value=vags), \
              mock.patch.object(sfv,
                                '_remove_volume_from_vags') as rem_vags:
              sfv._sf_terminate_connection(testvol, None, False)
              rem_vags.assert_called_with(vol_id)
  
      def test_safe_create_vag_simple(self):
          # Test the sunny day call straight into _create_vag.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          iqn = 'fake_iqn'
          vol_id = 1
  
          with mock.patch.object(sfv,
                                 '_get_vags_by_name',
                                 return_value=[]), \
              mock.patch.object(sfv,
                                '_create_vag') as mock_create_vag:
              sfv._safe_create_vag(iqn, vol_id)
              mock_create_vag.assert_called_with(iqn, vol_id)
  
      def test_safe_create_vag_matching_vag(self):
          # Vag exists, resuse.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          iqn = 'TESTIQN'
          vags = [{'attributes': {},
                   'deletedVolumes': [],
                   'initiators': [iqn],
                   'name': iqn,
                   'volumeAccessGroupID': 1,
                   'volumes': [1, 2],
                   'virtualNetworkIDs': []}]
  
          with mock.patch.object(sfv,
                                 '_get_vags_by_name',
                                 return_value=vags), \
              mock.patch.object(sfv,
                                '_create_vag') as create_vag, \
              mock.patch.object(sfv,
                                '_add_initiator_to_vag') as add_iqn:
              vag_id = sfv._safe_create_vag(iqn, None)
              self.assertEqual(vag_id, vags[0]['volumeAccessGroupID'])
              create_vag.assert_not_called()
              add_iqn.assert_not_called()
  
      def test_safe_create_vag_reuse_vag(self):
          # Reuse a matching vag.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          iqn = 'TESTIQN'
          vags = [{'attributes': {},
                   'deletedVolumes': [],
                   'initiators': [],
                   'name': iqn,
                   'volumeAccessGroupID': 1,
                   'volumes': [1, 2],
                   'virtualNetworkIDs': []}]
          vag_id = vags[0]['volumeAccessGroupID']
  
          with mock.patch.object(sfv,
                                 '_get_vags_by_name',
                                 return_value=vags), \
              mock.patch.object(sfv,
                                '_add_initiator_to_vag',
                                return_value=vag_id) as add_init:
              res_vag_id = sfv._safe_create_vag(iqn, None)
              self.assertEqual(res_vag_id, vag_id)
              add_init.assert_called_with(iqn, vag_id)
  
      def test_create_vag_iqn_fail(self):
          # Attempt to create a VAG with an already in-use initiator.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          iqn = 'TESTIQN'
          vag_id = 1
          vol_id = 42
  
          def throw_request(method, params, version):
              msg = 'xExceededLimit: {}'.format(params['initiators'][0])
              raise solidfire.SolidFireAPIException(message=msg)
  
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 side_effect=throw_request), \
              mock.patch.object(sfv,
                                '_safe_create_vag',
                                return_value=vag_id) as create_vag, \
              mock.patch.object(sfv,
                                '_purge_vags') as purge_vags:
              res_vag_id = sfv._create_vag(iqn, vol_id)
              self.assertEqual(res_vag_id, vag_id)
              create_vag.assert_called_with(iqn, vol_id)
              purge_vags.assert_not_called()
  
      def test_create_vag_limit_fail(self):
          # Attempt to create a VAG with VAG limit reached.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          iqn = 'TESTIQN'
          vag_id = 1
          vol_id = 42
  
          def throw_request(method, params, version):
              msg = 'xExceededLimit'
              raise solidfire.SolidFireAPIException(message=msg)
  
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 side_effect=throw_request), \
              mock.patch.object(sfv,
                                '_safe_create_vag',
                                return_value=vag_id) as create_vag, \
              mock.patch.object(sfv,
                                '_purge_vags') as purge_vags:
              res_vag_id = sfv._create_vag(iqn, vol_id)
              self.assertEqual(res_vag_id, vag_id)
              create_vag.assert_called_with(iqn, vol_id)
              purge_vags.assert_called_with()
  
      def test_add_initiator_duplicate(self):
          # Thrown exception should yield vag_id.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          iqn = 'TESTIQN'
          vag_id = 1
  
          def throw_request(method, params, version):
              msg = 'xAlreadyInVolumeAccessGroup'
              raise solidfire.SolidFireAPIException(message=msg)
  
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 side_effect=throw_request):
              res_vag_id = sfv._add_initiator_to_vag(iqn, vag_id)
              self.assertEqual(vag_id, res_vag_id)
  
      def test_add_initiator_missing_vag(self):
          # Thrown exception should result in create_vag call.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          iqn = 'TESTIQN'
          vag_id = 1
  
          def throw_request(method, params, version):
              msg = 'xVolumeAccessGroupIDDoesNotExist'
              raise solidfire.SolidFireAPIException(message=msg)
  
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 side_effect=throw_request), \
              mock.patch.object(sfv,
                                '_safe_create_vag',
                                return_value=vag_id) as mock_create_vag:
              res_vag_id = sfv._add_initiator_to_vag(iqn, vag_id)
              self.assertEqual(vag_id, res_vag_id)
              mock_create_vag.assert_called_with(iqn)
  
      def test_add_volume_to_vag_duplicate(self):
          # Thrown exception should yield vag_id
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          iqn = 'TESTIQN'
          vag_id = 1
          vol_id = 42
  
          def throw_request(method, params, version):
              msg = 'xAlreadyInVolumeAccessGroup'
              raise solidfire.SolidFireAPIException(message=msg)
  
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 side_effect=throw_request):
              res_vag_id = sfv._add_volume_to_vag(vol_id, iqn, vag_id)
              self.assertEqual(res_vag_id, vag_id)
  
      def test_add_volume_to_vag_missing_vag(self):
          # Thrown exception should yield vag_id
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          iqn = 'TESTIQN'
          vag_id = 1
          vol_id = 42
  
          def throw_request(method, params, version):
              msg = 'xVolumeAccessGroupIDDoesNotExist'
              raise solidfire.SolidFireAPIException(message=msg)
  
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 side_effect=throw_request), \
              mock.patch.object(sfv,
                                '_safe_create_vag',
                                return_value=vag_id) as mock_create_vag:
              res_vag_id = sfv._add_volume_to_vag(vol_id, iqn, vag_id)
              self.assertEqual(res_vag_id, vag_id)
              mock_create_vag.assert_called_with(iqn, vol_id)
  
      def test_remove_volume_from_vag_missing_volume(self):
          # Volume not in VAG, throws.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          vag_id = 1
          vol_id = 42
  
          def throw_request(method, params, version):
              msg = 'xNotInVolumeAccessGroup'
              raise solidfire.SolidFireAPIException(message=msg)
  
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 side_effect=throw_request):
              sfv._remove_volume_from_vag(vol_id, vag_id)
  
      def test_remove_volume_from_vag_missing_vag(self):
          # Volume not in VAG, throws.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          vag_id = 1
          vol_id = 42
  
          def throw_request(method, params, version):
              msg = 'xVolumeAccessGroupIDDoesNotExist'
              raise solidfire.SolidFireAPIException(message=msg)
  
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 side_effect=throw_request):
              sfv._remove_volume_from_vag(vol_id, vag_id)
  
      def test_remove_volume_from_vag_unknown_exception(self):
          # Volume not in VAG, throws.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          vag_id = 1
          vol_id = 42
  
          def throw_request(method, params, version):
              msg = 'xUnknownException'
              raise solidfire.SolidFireAPIException(message=msg)
  
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 side_effect=throw_request):
              self.assertRaises(solidfire.SolidFireAPIException,
                                sfv._remove_volume_from_vag,
                                vol_id,
                                vag_id)
  
      def test_remove_volume_from_vags(self):
          # Remove volume from several VAGs.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          vol_id = 42
          vags = [{'volumeAccessGroupID': 1,
                   'volumes': [vol_id]},
                  {'volumeAccessGroupID': 2,
                   'volumes': [vol_id, 43]}]
  
          with mock.patch.object(sfv,
                                 '_get_vags_by_volume',
                                 return_value=vags), \
              mock.patch.object(sfv,
                                '_remove_volume_from_vag') as rem_vol:
              sfv._remove_volume_from_vags(vol_id)
              self.assertEqual(len(vags), rem_vol.call_count)
  
      def test_purge_vags(self):
          # Remove subset of VAGs.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          vags = [{'initiators': [],
                   'volumeAccessGroupID': 1,
                   'deletedVolumes': [],
                   'volumes': [],
                   'attributes': {'openstack': True}},
                  {'initiators': [],
                   'volumeAccessGroupID': 2,
                   'deletedVolumes': [],
                   'volumes': [],
                   'attributes': {'openstack': False}},
                  {'initiators': [],
                   'volumeAccessGroupID': 3,
                   'deletedVolumes': [1],
                   'volumes': [],
                   'attributes': {'openstack': True}},
                  {'initiators': [],
                   'volumeAccessGroupID': 4,
                   'deletedVolumes': [],
                   'volumes': [1],
                   'attributes': {'openstack': True}},
                  {'initiators': ['fakeiqn'],
                   'volumeAccessGroupID': 5,
                   'deletedVolumes': [],
                   'volumes': [],
                   'attributes': {'openstack': True}}]
          with mock.patch.object(sfv,
                                 '_base_get_vags',
                                 return_value=vags), \
              mock.patch.object(sfv,
                                '_remove_vag') as rem_vag:
              sfv._purge_vags()
              # Of the vags provided there is only one that is valid for purge
              # based on the limits of no initiators, volumes, deleted volumes,
              # and features the openstack attribute.
              self.assertEqual(1, rem_vag.call_count)
              rem_vag.assert_called_with(1)
  
      def test_sf_create_group_snapshot(self):
          # Sunny day group snapshot creation.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          name = 'great_gsnap_name'
          sf_volumes = [{'volumeID': 1}, {'volumeID': 42}]
          expected_params = {'name': name,
                             'volumes': [1, 42]}
          fake_result = {'result': 'contrived_test'}
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 return_value=fake_result) as fake_api:
              res = sfv._sf_create_group_snapshot(name, sf_volumes)
              self.assertEqual('contrived_test', res)
              fake_api.assert_called_with('CreateGroupSnapshot',
                                          expected_params,
                                          version='7.0')
  
      def test_group_snapshot_creator_sunny(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          gsnap_name = 'great_gsnap_name'
          prefix = sfv.configuration.sf_volume_prefix
          vol_uuids = ['one', 'two', 'three']
          active_vols = [{'name': prefix + 'one'},
                         {'name': prefix + 'two'},
                         {'name': prefix + 'three'}]
          with mock.patch.object(sfv,
                                 '_get_all_active_volumes',
                                 return_value=active_vols),\
              mock.patch.object(sfv,
                                '_sf_create_group_snapshot',
                                return_value=None) as create:
              sfv._group_snapshot_creator(gsnap_name, vol_uuids)
              create.assert_called_with(gsnap_name,
                                        active_vols)
  
      def test_group_snapshot_creator_rainy(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          gsnap_name = 'great_gsnap_name'
          prefix = sfv.configuration.sf_volume_prefix
          vol_uuids = ['one', 'two', 'three']
          active_vols = [{'name': prefix + 'one'},
                         {'name': prefix + 'two'}]
          with mock.patch.object(sfv,
                                 '_get_all_active_volumes',
                                 return_value=active_vols):
              self.assertRaises(solidfire.SolidFireDriverException,
                                sfv._group_snapshot_creator,
                                gsnap_name,
                                vol_uuids)
  
      def test_create_temp_group_snapshot(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          cg = {'id': 'great_gsnap_name'}
          prefix = sfv.configuration.sf_volume_prefix
          tmp_name = prefix + cg['id'] + '-tmp'
          vols = [{'id': 'one'},
                  {'id': 'two'},
                  {'id': 'three'}]
          with mock.patch.object(sfv,
                                 '_group_snapshot_creator',
                                 return_value=None) as create:
              sfv._create_temp_group_snapshot(cg, vols)
              create.assert_called_with(tmp_name, ['one', 'two', 'three'])
  
      def test_list_group_snapshots(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          res = {'result': {'groupSnapshots': 'a_thing'}}
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 return_value=res):
              result = sfv._list_group_snapshots()
              self.assertEqual('a_thing', result)
  
      def test_get_group_snapshot_by_name(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          fake_snaps = [{'name': 'a_fantastic_name'}]
          with mock.patch.object(sfv,
                                 '_list_group_snapshots',
                                 return_value=fake_snaps):
              result = sfv._get_group_snapshot_by_name('a_fantastic_name')
              self.assertEqual(fake_snaps[0], result)
  
      def test_delete_group_snapshot(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          gsnap_id = 1
          with mock.patch.object(sfv,
                                 '_issue_api_request') as api_req:
              sfv._delete_group_snapshot(gsnap_id)
              api_req.assert_called_with('DeleteGroupSnapshot',
                                         {'groupSnapshotID': gsnap_id},
                                         version='7.0')
  
      def test_delete_cgsnapshot_by_name(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          fake_gsnap = {'groupSnapshotID': 42}
          with mock.patch.object(sfv,
                                 '_get_group_snapshot_by_name',
                                 return_value=fake_gsnap),\
              mock.patch.object(sfv,
                                '_delete_group_snapshot') as del_stuff:
              sfv._delete_cgsnapshot_by_name('does not matter')
              del_stuff.assert_called_with(fake_gsnap['groupSnapshotID'])
  
      def test_delete_cgsnapshot_by_name_rainy(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv, '_get_group_snapshot_by_name',
                                 return_value=None):
              self.assertRaises(solidfire.SolidFireDriverException,
                                sfv._delete_cgsnapshot_by_name,
                                'does not matter')
  
      def test_find_linked_snapshot(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_snap = {'members': [{'volumeID': 1}, {'volumeID': 2}]}
          source_vol = {'volumeID': 1}
          with mock.patch.object(sfv,
                                 '_get_sf_volume',
                                 return_value=source_vol) as get_vol:
              res = sfv._find_linked_snapshot('fake_uuid', group_snap)
              self.assertEqual(source_vol, res)
              get_vol.assert_called_with('fake_uuid')
  
      def test_create_consisgroup_from_src_cgsnapshot(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          ctxt = None
          group = {}
          volumes = [{'id': 'one'}, {'id': 'two'}, {'id': 'three'}]
          cgsnapshot = {'id': 'great_uuid'}
          snapshots = [{'id': 'snap_id_1', 'volume_id': 'one'},
                       {'id': 'snap_id_2', 'volume_id': 'two'},
                       {'id': 'snap_id_3', 'volume_id': 'three'}]
          source_cg = None
          source_vols = None
          group_snap = {}
          name = sfv.configuration.sf_volume_prefix + cgsnapshot['id']
          kek = (None, None, {})
          with mock.patch.object(sfv,
                                 '_get_group_snapshot_by_name',
                                 return_value=group_snap) as get_snap,\
              mock.patch.object(sfv,
                                '_find_linked_snapshot'),\
              mock.patch.object(sfv,
                                '_do_clone_volume',
                                return_value=kek):
              model, vol_models = sfv._create_consistencygroup_from_src(
                  ctxt, group, volumes,
                  cgsnapshot, snapshots,
                  source_cg, source_vols)
              get_snap.assert_called_with(name)
              self.assertEqual(
                  {'status': fields.GroupStatus.AVAILABLE}, model)
  
      def test_create_consisgroup_from_src_source_cg(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          ctxt = None
          group = {}
          volumes = [{'id': 'one', 'source_volid': 'source_one'},
                     {'id': 'two', 'source_volid': 'source_two'},
                     {'id': 'three', 'source_volid': 'source_three'}]
          cgsnapshot = {'id': 'great_uuid'}
          snapshots = None
          source_cg = {'id': 'fantastic_cg'}
          source_vols = [1, 2, 3]
          source_snap = None
          group_snap = {}
          kek = (None, None, {})
          with mock.patch.object(sfv,
                                 '_create_temp_group_snapshot',
                                 return_value=source_cg['id']),\
              mock.patch.object(sfv,
                                '_get_group_snapshot_by_name',
                                return_value=group_snap) as get_snap,\
              mock.patch.object(sfv,
                                '_find_linked_snapshot',
                                return_value=source_snap),\
              mock.patch.object(sfv,
                                '_do_clone_volume',
                                return_value=kek),\
              mock.patch.object(sfv,
                                '_delete_cgsnapshot_by_name'):
              model, vol_models = sfv._create_consistencygroup_from_src(
                  ctxt, group, volumes,
                  cgsnapshot, snapshots,
                  source_cg,
                  source_vols)
              get_snap.assert_called_with(source_cg['id'])
              self.assertEqual(
                  {'status': fields.GroupStatus.AVAILABLE}, model)
  
      def test_create_cgsnapshot(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          ctxt = None
          cgsnapshot = {'id': 'acceptable_cgsnap_id'}
          snapshots = [{'volume_id': 'one'},
                       {'volume_id': 'two'}]
          pfx = sfv.configuration.sf_volume_prefix
          active_vols = [{'name': pfx + 'one'},
                         {'name': pfx + 'two'}]
          with mock.patch.object(sfv,
                                 '_get_all_active_volumes',
                                 return_value=active_vols),\
              mock.patch.object(sfv,
                                '_sf_create_group_snapshot') as create_gsnap:
              sfv._create_cgsnapshot(ctxt, cgsnapshot, snapshots)
              create_gsnap.assert_called_with(pfx + cgsnapshot['id'],
                                              active_vols)
  
      def test_create_cgsnapshot_rainy(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          ctxt = None
          cgsnapshot = {'id': 'acceptable_cgsnap_id'}
          snapshots = [{'volume_id': 'one'},
                       {'volume_id': 'two'}]
          pfx = sfv.configuration.sf_volume_prefix
          active_vols = [{'name': pfx + 'one'}]
          with mock.patch.object(sfv,
                                 '_get_all_active_volumes',
                                 return_value=active_vols),\
              mock.patch.object(sfv,
                                '_sf_create_group_snapshot'):
              self.assertRaises(solidfire.SolidFireDriverException,
                                sfv._create_cgsnapshot,
                                ctxt,
                                cgsnapshot,
                                snapshots)
  
      def test_create_vol_from_cgsnap(self):
          # cgsnaps on the backend yield numerous identically named snapshots.
          # create_volume_from_snapshot now searches for the correct snapshot.
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          source = {'group_snapshot_id': 'typical_cgsnap_id',
                    'volume_id': 'typical_vol_id',
                    'id': 'no_id_4_u'}
          name = (self.configuration.sf_volume_prefix +
                  source.get('group_snapshot_id'))
          with mock.patch.object(sfv,
                                 '_get_group_snapshot_by_name',
                                 return_value={}) as get,\
              mock.patch.object(sfv,
                                '_create_clone_from_sf_snapshot',
                                return_value='model'):
              result = sfv.create_volume_from_snapshot({}, source)
              get.assert_called_once_with(name)
              self.assertEqual('model', result)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_create_group_cg(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = True
          group = mock.MagicMock()
          result = sfv.create_group(self.ctxt, group)
          self.assertEqual(result,
                           {'status': fields.GroupStatus.AVAILABLE})
          group_cg_test.assert_called_once_with(group)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_delete_group_snap_cg(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = True
          cgsnapshot = fake_group_snapshot.fake_group_snapshot_obj(
              mock.MagicMock())
          snapshots = fake_snapshot.fake_snapshot_obj(mock.MagicMock())
  
          with mock.patch.object(sfv, '_delete_cgsnapshot',
                                 return_value={}) as _del_mock:
              model_update = sfv.delete_group_snapshot(self.ctxt,
                                                       cgsnapshot, snapshots)
              _del_mock.assert_called_once_with(self.ctxt, cgsnapshot, snapshots)
              self.assertEqual({}, model_update)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_delete_group_snap(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = False
          cgsnapshot = fake_group_snapshot.fake_group_snapshot_obj(
              mock.MagicMock())
          snapshots = fake_snapshot.fake_snapshot_obj(mock.MagicMock())
  
          with mock.patch.object(sfv, '_delete_cgsnapshot',
                                 return_value={}) as _del_mock:
  
              self.assertRaises(NotImplementedError, sfv.delete_group_snapshot,
                                self.ctxt, cgsnapshot, snapshots)
              _del_mock.assert_not_called()
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_create_group_rainy(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = False
          group = mock.MagicMock()
          self.assertRaises(NotImplementedError,
                            sfv.create_group,
                            self.ctxt, group)
          group_cg_test.assert_called_once_with(group)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_create_group_from_src_rainy(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = False
          group = mock.MagicMock()
          volumes = [mock.MagicMock()]
          self.assertRaises(NotImplementedError,
                            sfv.create_group_from_src,
                            self.ctxt, group, volumes)
          group_cg_test.assert_called_once_with(group)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_create_group_from_src_cg(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = True
          group = mock.MagicMock()
          volumes = [mock.MagicMock()]
          ret = 'things'
          with mock.patch.object(sfv,
                                 '_create_consistencygroup_from_src',
                                 return_value=ret):
              result = sfv.create_group_from_src(self.ctxt,
                                                 group,
                                                 volumes)
              self.assertEqual(ret, result)
              group_cg_test.assert_called_once_with(group)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_create_group_snapshot_rainy(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = False
          group_snapshot = mock.MagicMock()
          snapshots = [mock.MagicMock()]
          self.assertRaises(NotImplementedError,
                            sfv.create_group_snapshot,
                            self.ctxt,
                            group_snapshot,
                            snapshots)
          group_cg_test.assert_called_once_with(group_snapshot)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_create_group_snapshot(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = True
          group_snapshot = mock.MagicMock()
          snapshots = [mock.MagicMock()]
          ret = 'things'
          with mock.patch.object(sfv,
                                 '_create_cgsnapshot',
                                 return_value=ret):
              result = sfv.create_group_snapshot(self.ctxt,
                                                 group_snapshot,
                                                 snapshots)
              self.assertEqual(ret, result)
          group_cg_test.assert_called_once_with(group_snapshot)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_delete_group_rainy(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = False
          group = mock.MagicMock()
          volumes = [mock.MagicMock()]
          self.assertRaises(NotImplementedError,
                            sfv.delete_group,
                            self.ctxt,
                            group,
                            volumes)
          group_cg_test.assert_called_once_with(group)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_delete_group(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = True
          group = mock.MagicMock()
          volumes = [mock.MagicMock()]
          ret = 'things'
          with mock.patch.object(sfv,
                                 '_delete_consistencygroup',
                                 return_value=ret):
              result = sfv.delete_group(self.ctxt,
                                        group,
                                        volumes)
              self.assertEqual(ret, result)
          group_cg_test.assert_called_once_with(group)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_update_group_rainy(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = False
          group = mock.MagicMock()
          self.assertRaises(NotImplementedError,
                            sfv.update_group,
                            self.ctxt,
                            group)
          group_cg_test.assert_called_once_with(group)
  
      @mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
      def test_update_group(self, group_cg_test):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          group_cg_test.return_value = True
          group = mock.MagicMock()
          ret = 'things'
          with mock.patch.object(sfv,
                                 '_update_consistencygroup',
                                 return_value=ret):
              result = sfv.update_group(self.ctxt,
                                        group)
              self.assertEqual(ret, result)
          group_cg_test.assert_called_once_with(group)
  
      def test_getattr_failure(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          try:
              sfv.foo()
              self.fail("Should have thrown Error")
          except Exception:
              pass
  
      @data('Async', 'Sync', 'SnapshotsOnly')
      @mock.patch.object(volume_types, 'get_volume_type')
      def test_set_rep_by_volume_type(self, mode, mock_get_volume_type):
          mock_get_volume_type.return_value = {
              'name': 'sf-1', 'deleted': False,
              'created_at': '2014-02-06 04:58:11',
              'updated_at': None, 'extra_specs':
                  {'replication_enabled': '<is> True',
                   'solidfire:replication_mode': mode},
              'deleted_at': None,
              'id': '290edb2a-f5ea-11e5-9ce9-5e5517507c66'}
          rep_opts = {}
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.cluster_pairs = self.cluster_pairs
          ctxt = None
          type_id = '290edb2a-f5ea-11e5-9ce9-5e5517507c66'
          rep_opts['rep_type'] = mode
          self.assertEqual(rep_opts, sfv._set_rep_by_volume_type(ctxt, type_id))
          mock_get_volume_type.assert_called()
  
      def test_replicate_volume(self):
          replication_status = fields.ReplicationStatus.ENABLED
          fake_vol = {'project_id': 1, 'volumeID': 1, 'size': 1}
          params = {'attributes': {}}
          rep_info = {'rep_type': 'Async'}
          sf_account = {'initiatorSecret': 'shhh', 'targetSecret': 'dont-tell'}
          model_update = {'provider_id': '1 2 xxxx'}
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.cluster_pairs = self.cluster_pairs
  
          with mock.patch.object(sfv,
                                 '_issue_api_request',
                                 self.fake_issue_api_request),\
                  mock.patch.object(sfv,
                                    '_get_sfaccount_by_name',
                                    return_value={'accountID': 1}),\
                  mock.patch.object(sfv,
                                    '_do_volume_create',
                                    return_value=model_update):
              self.assertEqual({'replication_status': replication_status},
                               sfv._replicate_volume(fake_vol, params,
                                                     sf_account, rep_info))
  
      def test_pythons_try_except(self):
          def _fake_retrieve_rep(vol):
              raise solidfire.SolidFireAPIException
  
          fake_type = {'extra_specs': {}}
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(sfv,
                                 '_get_create_account',
                                 return_value={'accountID': 5}),\
                  mock.patch.object(sfv,
                                    '_retrieve_qos_setting',
                                    return_value=None), \
                  mock.patch.object(sfv,
                                    '_do_volume_create',
                                    return_value={'provider_id': '1 2 xxxx'}),\
                  mock.patch.object(volume_types,
                                    'get_volume_type',
                                    return_value=fake_type), \
                  mock.patch.object(sfv,
                                    '_retrieve_replication_settings',
                                    side_effect=_fake_retrieve_rep):
              self.assertRaises(solidfire.SolidFireAPIException,
                                sfv.create_volume,
                                self.mock_volume)
  
      def test_extract_sf_attributes_from_extra_specs(self):
          type_id = '290edb2a-f5ea-11e5-9ce9-5e5517507c66'
          fake_type = {'extra_specs': {'SFAttribute:foo': 'bar',
                                       'SFAttribute:biz': 'baz'}}
          expected = [{'foo': 'bar'}, {'biz': 'baz'}]
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          with mock.patch.object(volume_types, 'get_volume_type',
                                 return_value=fake_type):
              res = sfv._extract_sf_attributes_from_extra_specs(type_id)
              six.assertCountEqual(self, expected, res)
  
      def test_build_endpoint_with_kwargs(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          expected_ep = {'passwd': 'nunyabiz',
                         'port': 888,
                         'url': 'https://1.2.3.4:888',
                         'svip': None,
                         'mvip': '1.2.3.4',
                         'login': 'JohnWayne'}
          ep = sfv._build_endpoint_info(mvip='1.2.3.4', login='JohnWayne',
                                        password='nunyabiz', port=888)
          self.assertEqual(expected_ep, ep)
  
          # Make sure we pick up defaults for those not specified
          expected_ep = {'passwd': 'nunyabiz',
                         'url': 'https://1.2.3.4:443',
                         'svip': None,
                         'mvip': '1.2.3.4',
                         'login': 'admin',
                         'port': 443}
          ep = sfv._build_endpoint_info(mvip='1.2.3.4', password='nunyabiz')
          self.assertEqual(expected_ep, ep)
  
      def test_generate_random_string(self):
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          a = sfv._generate_random_string(12)
          self.assertEqual(len(a), 12)
          self.assertIsNotNone(re.match(r'[A-Z0-9]{12}', a), a)
  
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_snapshots')
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      def test_revert_to_snapshot_success(self, mock_issue_api_request,
                                          mock_get_sf_snapshots,
                                          mock_get_sf_volume,
                                          mock_get_sfaccount):
          mock_issue_api_request.side_effect = self.fake_issue_api_request
  
          mock_get_sfaccount.return_value = self.fake_sfaccount
          mock_get_sf_volume.return_value = self.fake_sfvol
          mock_get_sf_snapshots.return_value = self.fake_sfsnaps
  
          expected_params = {'accountID': 25,
                             'volumeID': 6,
                             'snapshotID': '5',
                             'saveCurrentState': 'false'}
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  
          # Success path
          sfv.revert_to_snapshot(self.ctxt, self.vol, self.snap)
          mock_issue_api_request.assert_called_with(
              'RollbackToSnapshot', expected_params, version='6.0')
  
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_snapshots')
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      def test_revert_to_snapshot_fail_vol_not_found(
              self, mock_issue_api_request, mock_get_sf_snapshots,
              mock_get_sf_volume, mock_get_sfaccount):
          mock_issue_api_request.side_effect = self.fake_issue_api_request
  
          mock_get_sfaccount.return_value = self.fake_sfaccount
          mock_get_sf_volume.return_value = None
          mock_get_sf_snapshots.return_value = []
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  
          # Volume not found
          mock_get_sf_volume.return_value = None
          self.assertRaises(exception.VolumeNotFound,
                            sfv.revert_to_snapshot,
                            self.ctxt, self.vol, self.snap)
  
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sf_snapshots')
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      def test_revert_to_snapshot_fail_snap_not_found(
              self, mock_issue_api_request, mock_get_sf_snapshots,
              mock_get_sf_volume, mock_get_sfaccount):
          mock_issue_api_request.side_effect = self.fake_issue_api_request
  
          mock_get_sfaccount.return_value = self.fake_sfaccount
          mock_get_sf_volume.return_value = self.fake_sfvol
          mock_get_sf_snapshots.return_value = []
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
  
          # Snapshot not found
          mock_get_sf_snapshots.return_value = []
          self.assertRaises(exception.VolumeSnapshotNotFound,
                            sfv.revert_to_snapshot,
                            self.ctxt, self.vol, self.snap)
  
      @mock.patch.object(solidfire.SolidFireDriver, '_get_create_account')
      @mock.patch.object(solidfire.SolidFireDriver, '_set_cluster_pairs')
      @mock.patch.object(solidfire.SolidFireDriver, '_snapshot_discovery')
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_model_info')
      @mock.patch.object(solidfire.SolidFireDriver, '_update_attributes')
      @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
      @mock.patch.object(solidfire.SolidFireDriver, '_set_cluster_pairs')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_default_volume_params')
      @mock.patch.object(solidfire.SolidFireDriver,
                         '_retrieve_replication_settings')
      @mock.patch.object(solidfire.SolidFireDriver, '_replicate_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
      def test_do_clone_volume_rep_disabled(self,
                                            mock_create_cluster_reference,
                                            mock_replicate_volume,
                                            mock_retrieve_replication_settings,
                                            mock_get_default_volume_params,
                                            mock_set_cluster_pairs,
                                            mock_update_cluster_status,
                                            mock_update_attributes,
                                            mock_get_model_info,
                                            mock_issue_api_request,
                                            mock_snapshot_discovery,
                                            mock_test_set_cluster_pairs,
                                            mock_get_create_account):
  
          all_mocks = locals()
  
          def reset_mocks():
              for mk in all_mocks.values():
                  if isinstance(mk, mock.MagicMock):
                      mk.reset_mock()
  
          sf_volume_params = {'volumeID': 1, 'snapshotID': 2, 'newSize': 3}
          mock_snapshot_discovery.return_value = (sf_volume_params, True,
                                                  self.fake_sfvol)
          mock_get_create_account.return_value = self.fake_sfaccount
  
          ctx = context.get_admin_context()
          vol_fields = {'updated_at': timeutils.utcnow(),
                        'created_at': timeutils.utcnow()}
          src_vol = fake_volume.fake_volume_obj(ctx)
          dst_vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
  
          mock_create_cluster_reference.return_value = {
              'mvip': self.mvip,
              'svip': self.svip}
  
          self.configuration.sf_volume_clone_timeout = 1
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.replication_enabled = False
  
          reset_mocks()
          mock_issue_api_request.return_value = {
              'error': {'code': 000, 'name': 'DummyError',
                        'message': 'This is a fake error response'},
              'id': 1}
  
          self.assertRaises(solidfire.SolidFireAPIException,
                            sfv._do_clone_volume, src_vol.id,
                            dst_vol, sf_src_snap=self.fake_sfsnaps[0])
  
          clone_vol_params = {
              'snapshotID': self.fake_sfsnaps[0]['snapshotID'],
              'volumeID': self.fake_sfsnaps[0]['volumeID'],
              'newSize': dst_vol.size * units.Gi,
              'name': '%(prefix)s%(id)s' % {
                  'prefix': self.configuration.sf_volume_prefix,
                      'id': dst_vol.id},
              'newAccountID': self.fake_sfaccount['accountID']}
  
          mock_get_create_account.assert_called_with(dst_vol.project_id)
          mock_issue_api_request.assert_called_once_with(
              'CloneVolume', clone_vol_params, version='6.0')
          mock_test_set_cluster_pairs.assert_not_called()
          mock_update_attributes.assert_not_called()
          mock_get_model_info.assert_not_called()
          mock_snapshot_discovery.assert_not_called()
  
          reset_mocks()
          mock_issue_api_request.side_effect = self.fake_issue_api_request
          mock_get_default_volume_params.return_value = {}
          mock_get_model_info.return_value = None
          self.assertRaises(solidfire.SolidFireAPIException,
                            sfv._do_clone_volume, src_vol.id,
                            dst_vol, sf_src_snap=self.fake_sfsnaps[0])
  
          mock_get_create_account.assert_called_with(dst_vol.project_id)
          calls = [mock.call('CloneVolume', clone_vol_params, version='6.0'),
                   mock.call('ModifyVolume', {'volumeID': 6})]
          mock_issue_api_request.assert_has_calls(calls)
          mock_test_set_cluster_pairs.assert_not_called()
          mock_update_attributes.assert_not_called()
          mock_get_model_info.assert_called()
          mock_snapshot_discovery.assert_not_called()
  
          reset_mocks()
          mock_retrieve_replication_settings.return_value = 'Async'
          update = {'replication_status': fields.ReplicationStatus.ENABLED}
          mock_replicate_volume.side_effect = solidfire.SolidFireDriverException
          mock_update_attributes.return_value = {'result': {}, 'id': 1}
          mock_get_model_info.return_value = {
              'provider_location': '1.1.1.1 iqn 0',
              'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2c76370d66b '
                               '2FE0CQ8J196R',
              'provider_id': '%s %s cluster-id-01' % (
                  self.fake_sfvol['volumeID'],
                  self.fake_sfaccount['accountID'])
          }
  
          data, account, updates = sfv._do_clone_volume(
              src_vol.id, dst_vol, sf_src_snap=self.fake_sfsnaps[0])
  
          self.assertEqual({'result': {}, 'id': 1}, data)
          self.assertEqual(25, account['accountID'])
          self.assertEqual(self.fake_sfvol['volumeID'],
                           int(updates['provider_id'].split()[0]))
  
          mock_get_create_account.assert_called_with(dst_vol.project_id)
          calls = [mock.call('CloneVolume', clone_vol_params, version='6.0'),
                   mock.call('ModifyVolume', {'volumeID': 6})]
  
          mock_issue_api_request.assert_has_calls(calls)
          mock_test_set_cluster_pairs.assert_not_called()
          mock_update_attributes.assert_not_called()
          mock_get_model_info.assert_called_once()
          mock_snapshot_discovery.assert_not_called()
  
      @mock.patch.object(solidfire.SolidFireDriver, '_get_create_account')
      @mock.patch.object(solidfire.SolidFireDriver, '_retrieve_qos_setting')
      @mock.patch.object(solidfire.SolidFireDriver,
                         '_extract_sf_attributes_from_extra_specs')
      def test_get_default_volume_params(
              self, mock_extract_sf_attributes_from_extra_specs,
              mock_retrieve_qos_setting, mock_get_create_account):
  
          mock_extract_sf_attributes_from_extra_specs.return_value = [{
              'key1': 'value1',
              'key2': 'value2'
          }]
          mock_retrieve_qos_setting.return_value = None
          mock_get_create_account.return_value = self.fake_sfaccount
  
          ctx = context.get_admin_context()
          type_fields = {'extra_specs': {'replication_enabled': '<is> True'}}
          vol_type = fake_volume.fake_volume_type_obj(ctx, **type_fields)
          utc_now = timeutils.utcnow().isoformat()
          vol_fields = {
              'id': fakes.FAKE_UUID,
              'created_at': utc_now,
              'volume_type': vol_type,
              'volume_type_id': vol_type.id
          }
  
          vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
  
          vol_name = '%s%s' % (self.configuration.sf_volume_prefix, vol.id)
          expected_attr = {
              'uuid': vol.id,
              'is_clone': False,
              'created_at': utc_now + "+00:00",
              'cinder-name': vol.get('display_name', ""),
              'key1': 'value1',
              'key2': 'value2',
          }
  
          expected_params = {
              'name': vol_name,
              'accountID': self.fake_sfaccount['accountID'],
              'sliceCount': 1,
              'totalSize': int(vol.size * units.Gi),
              'enable512e': self.configuration.sf_emulate_512,
              'attributes': expected_attr,
              'qos': None
          }
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.replication_enabled = True
  
          params = sfv._get_default_volume_params(vol, False)
  
          self.assertDictEqual(expected_params, params)
          mock_extract_sf_attributes_from_extra_specs.assert_called()
          mock_retrieve_qos_setting.assert_called()
          mock_get_create_account.assert_called()
  
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sfvol_by_cinder_vref')
      def test_disable_replication_fail(self, mock_get_sfvol_by_cinder_vref):
  
          self.fake_sfvol['volumePairs'] = []
          mock_get_sfvol_by_cinder_vref.return_value = self.fake_sfvol
  
          ctx = context.get_admin_context()
          utc_now = timeutils.utcnow().isoformat()
          vol_fields = {
              'id': f_uuid,
              'created_at': utc_now
          }
          vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.replication_enabled = True
          sfv.cluster_pairs = self.cluster_pairs
  
          expected = {'replication_status': fields.ReplicationStatus.DISABLED}
          updates = sfv._disable_replication(vol)
  
          self.assertDictEqual(expected, updates)
  
      @mock.patch.object(solidfire.SolidFireDriver, '_get_sfvol_by_cinder_vref')
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
      def test_disable_replication(self, mock_create_cluster_reference,
                                   mock_issue_api_request,
                                   mock_get_sfvol_by_cinder_vref):
  
          mock_create_cluster_reference.return_value = {
              'mvip': self.mvip,
              'svip': self.svip}
  
          self.fake_sfvol['volumePairs'] = [{"remoteVolumeID": 26}]
          mock_get_sfvol_by_cinder_vref.return_value = self.fake_sfvol
  
          ctx = context.get_admin_context()
          utc_now = timeutils.utcnow().isoformat()
          vol_fields = {
              'id': f_uuid,
              'created_at': utc_now
          }
          vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.replication_enabled = True
          sfv.cluster_pairs = self.cluster_pairs
          sfv.active_cluster['mvip'] = self.mvip
          sfv.active_cluster['svip'] = self.svip
  
          expected = {'replication_status': fields.ReplicationStatus.DISABLED}
          mock_issue_api_request.reset_mock()
          updates = sfv._disable_replication(vol)
  
          self.assertDictEqual(expected, updates)
  
          expected = [
              mock.call("RemoveVolumePair",
                        {'volumeID': self.fake_sfvol['volumeID']}, '8.0'),
              mock.call("RemoveVolumePair", {'volumeID': 26}, '8.0',
                        endpoint=sfv.cluster_pairs[0]['endpoint']),
              mock.call("DeleteVolume", {'volumeID': 26},
                        endpoint=sfv.cluster_pairs[0]['endpoint']),
              mock.call("PurgeDeletedVolume", {'volumeID': 26},
                        endpoint=sfv.cluster_pairs[0]['endpoint'])
          ]
  
          mock_issue_api_request.assert_has_calls(expected)
          mock_create_cluster_reference.assert_called()
          mock_get_sfvol_by_cinder_vref.assert_called()
  
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
      @mock.patch.object(solidfire.SolidFireDriver, '_set_cluster_pairs')
      @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_cluster_info')
      @mock.patch.object(solidfire.SolidFireDriver, '_map_sf_volumes')
      @mock.patch.object(solidfire.SolidFireDriver, '_failover_volume')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_create_account')
      @mock.patch.object(solidfire.SolidFireDriver, '_get_remote_info_by_id')
      def test_failover_host(self, mock_get_remote_info_by_id,
                             mock_get_create_account,
                             mock_failover_volume,
                             mock_map_sf_volumes,
                             mock_get_cluster_info,
                             mock_update_cluster_status,
                             mock_set_cluster_pairs,
                             mock_create_cluster_reference,
                             mock_issue_api_request):
  
          all_mocks = locals()
  
          def reset_mocks():
              for mk in all_mocks.values():
                  if isinstance(mk, mock.MagicMock):
                      mk.reset_mock()
  
          ctx = context.get_admin_context()
          vol_fields = {'updated_at': timeutils.utcnow(),
                        'created_at': timeutils.utcnow()}
  
          cinder_vols = []
          sf_vols = []
          for i in range(1, 6):
              vol = fake_volume.fake_volume_obj(ctx, **vol_fields)
              sf_vol = self.fake_sfvol.copy()
              sf_vol['volumeID'] = i
              sf_vol['name'] = '%s%s' % (self.configuration.sf_volume_prefix,
                                         vol.id)
              sf_vol['access'] = 'replicationTarget'
              sf_vol['attributes'] = {'uuid': vol.id}
              sf_vol['cinder_id'] = vol.id
  
              sf_vols.append(sf_vol)
              cinder_vols.append(vol)
  
          mock_map_sf_volumes.return_value = sf_vols
  
          self.configuration.replication_device = []
  
          reset_mocks()
          drv_args = {'active_backend_id': None}
          sfv = solidfire.SolidFireDriver(configuration=self.configuration,
                                          **drv_args)
  
          self.assertRaises(exception.UnableToFailOver,
                            sfv.failover_host, ctx, cinder_vols, 'fake', None)
          mock_map_sf_volumes.assert_not_called()
  
          fake_replication_device = {'backend_id': 'fake',
                                     'mvip': '0.0.0.0',
                                     'login': 'fake_login',
                                     'password': 'fake_pwd'}
  
          self.configuration.replication_device = [fake_replication_device]
  
          reset_mocks()
          drv_args = {'active_backend_id': None}
          sfv = solidfire.SolidFireDriver(configuration=self.configuration,
                                          **drv_args)
          self.assertRaises(exception.InvalidReplicationTarget,
                            sfv.failover_host, ctx, cinder_vols, 'default', None)
          mock_map_sf_volumes.assert_not_called()
  
          reset_mocks()
          drv_args = {'active_backend_id': None}
          sfv = solidfire.SolidFireDriver(configuration=self.configuration,
                                          **drv_args)
          self.assertRaises(exception.InvalidReplicationTarget,
                            sfv.failover_host, ctx, cinder_vols,
                            secondary_id='not_fake_id', groups=None)
          mock_map_sf_volumes.assert_not_called()
  
          mock_create_cluster_reference.return_value = self.cluster_pairs[0]
  
          reset_mocks()
          drv_args = {'active_backend_id': 'secondary'}
          sfv = solidfire.SolidFireDriver(configuration=self.configuration,
                                          **drv_args)
          sfv.cluster_pairs = self.cluster_pairs
          sfv.cluster_pairs[0]['backend_id'] = 'fake'
          sfv.replication_enabled = True
          cluster_id, updates, _ = sfv.failover_host(
              ctx, cinder_vols, secondary_id='default', groups=None)
          self.assertEqual(5, len(updates))
          for update in updates:
              self.assertEqual(fields.ReplicationStatus.ENABLED,
                               update['updates']['replication_status'])
          self.assertEqual('', cluster_id)
          mock_get_create_account.assert_called()
          mock_failover_volume.assert_called()
          mock_map_sf_volumes.assert_called()
          mock_update_cluster_status.assert_called()
          mock_set_cluster_pairs.assert_called()
          mock_create_cluster_reference.assert_called()
  
          reset_mocks()
          drv_args = {'active_backend_id': None}
          sfv = solidfire.SolidFireDriver(configuration=self.configuration,
                                          **drv_args)
          sfv.cluster_pairs = self.cluster_pairs
          sfv.cluster_pairs[0]['backend_id'] = 'fake'
          sfv.replication_enabled = True
          cluster_id, updates, _ = sfv.failover_host(
              ctx, cinder_vols, secondary_id='fake', groups=None)
          self.assertEqual(5, len(updates))
          for update in updates:
              self.assertEqual(fields.ReplicationStatus.FAILED_OVER,
                               update['updates']['replication_status'])
  
          self.assertEqual('fake', cluster_id)
          mock_get_create_account.assert_called()
          mock_failover_volume.assert_called()
          mock_map_sf_volumes.assert_called()
          mock_update_cluster_status.assert_called()
          mock_set_cluster_pairs.assert_called()
          mock_create_cluster_reference.assert_called()
  
      @mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
      @mock.patch.object(solidfire.SolidFireDriver, '_create_cluster_reference')
      @mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
      def test_failover_volume(self, mock_update_cluster_status,
                               mock_create_cluster_reference,
                               mock_issue_api_request):
  
          all_mocks = locals()
  
          def reset_mocks():
              for mk in all_mocks.values():
                  if isinstance(mk, mock.MagicMock):
                      mk.reset_mock()
  
          mock_issue_api_request.return_value = self.fake_sfaccount
  
          sfv = solidfire.SolidFireDriver(configuration=self.configuration)
          sfv.replication_enabled = True
  
          fake_src_sfvol = {'volumeID': 600,
                            'name': 'test_volume',
                            'accountID': 25,
                            'sliceCount': 1,
                            'totalSize': 1 * units.Gi,
                            'enable512e': True,
                            'access': "replicationTarget",
                            'status': "active",
                            'attributes': {'uuid': f_uuid[0]},
                            'qos': None,
                            'iqn': 'super_fake_iqn'}
  
          expected_src_params = {'volumeID': fake_src_sfvol['volumeID'],
                                 'access': 'replicationTarget'}
  
          expected_tgt_params = {'volumeID': self.fake_sfvol['volumeID'],
                                 'access': 'readWrite'}
  
          sfv._failover_volume(self.fake_sfvol, self.cluster_pairs[0],
                               fake_src_sfvol)
  
          mock_issue_api_request.assert_has_calls(
              [mock.call("ModifyVolume", expected_src_params),
               mock.call("ModifyVolume", expected_tgt_params,
                         endpoint=self.cluster_pairs[0]['endpoint'])]
          )
          reset_mocks()
  
          sfv._failover_volume(self.fake_sfvol, self.cluster_pairs[0])
  
          mock_issue_api_request.assert_called_with(
              "ModifyVolume",
              expected_tgt_params,
              endpoint=self.cluster_pairs[0]['endpoint']
          )
  