#  Copyright (c) 2016 IBM Corporation
#  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 mock
import six
from xml.etree import ElementTree

from cinder import context
from cinder import exception
from cinder import objects
from cinder.objects import fields
from cinder import test
from cinder.tests.unit import fake_constants as fake
from cinder.tests.unit import utils as testutils
from cinder.tests.unit.volume.drivers.ibm import fake_pyxcli
import cinder.volume.drivers.ibm.ibm_storage as storage
from cinder.volume.drivers.ibm.ibm_storage import cryptish
from cinder.volume.drivers.ibm.ibm_storage.xiv_proxy import XIVProxy
from cinder.volume.drivers.ibm.ibm_storage import xiv_replication
from cinder.volume import group_types

errors = fake_pyxcli.pyxcli_client.errors
mirroring = fake_pyxcli.pyxcli_client.mirroring
mirrored_entities = fake_pyxcli.pyxcli_client.mirroring.mirrored_entities

test_mock = mock.MagicMock()
module_patcher = mock.MagicMock()

test_mock.cinder.exception = exception


TEST_LOG_PREFIX = storage.XIV_LOG_PREFIX
TEST_VOLUME = {
    'name': 'BLA',
    'id': 23,
    'size': 17,
    'group_id': fake.CONSISTENCY_GROUP_ID,
}

TEST_GROUP_SPECS = {
    'group_replication_enabled': '<is> True',
    'replication_type': 'sync',
}

TEST_EXTRA_SPECS = {
    'replication_enabled': '<is> False',
}
TEST_EXTRA_SPECS_REPL = {
    'replication_enabled': '<is> True',
    'replication_type': 'sync',
}

TEST_WWPNS = ["50017380FE020160", "50017380FE020161", "50017380FE020162"]
TEST_INITIATOR = 'c5507606d5680e05'
TEST_CONNECTOR = {
    'ip': '129.123.123.123',
    'initiator': TEST_INITIATOR,
    'wwpns': [TEST_INITIATOR],
}
TEST_TARGET_MAP = {TEST_INITIATOR: TEST_WWPNS}

TEST_HOST_ID = 11
TEST_HOST_NAME = 'WTF32'
TEST_CHAP_NAME = 'WTF64'
TEST_CHAP_SECRET = 'V1RGNjRfXw=='

FC_TARGETS_OPTIMIZED = [
    "50017380FE020160", "50017380FE020190", "50017380FE020192"]
FC_TARGETS_OPTIMIZED_WITH_HOST = [
    "50017380FE020160", "50017380FE020192"]
FC_TARGETS_BEFORE_SORTING = [
    "50017380FE020160", "50017380FE020161", "50017380FE020162",
    "50017380FE020190", "50017380FE020191", "50017380FE020192"]
FC_TARGETS_AFTER_SORTING = [
    "50017380FE020190", "50017380FE020160", "50017380FE020191",
    "50017380FE020161", "50017380FE020162", "50017380FE020192"]

FC_PORT_LIST_OUTPUT = [
    {'component_id': '1:FC_Port:4:1', 'port_state': 'Online', 'role': 'Target',
     'wwpn': '50017380FE020160'},
    {'component_id': '1:FC_Port:5:1', 'port_state': 'Link Problem',
     'role': 'Target', 'wwpn': '50017380FE020161'},
    {'component_id': '1:FC_Port:6:1', 'port_state': 'Online',
     'role': 'Initiator', 'wwpn': '50017380FE020162'},
    {'component_id': '1:FC_Port:7:1', 'port_state': 'Link Problem',
     'role': 'Initiator', 'wwpn': '50017380FE020163'},
    {'component_id': '1:FC_Port:8:1', 'port_state': 'Online', 'role': 'Target',
     'wwpn': '50017380FE020190'},
    {'component_id': '1:FC_Port:9:1', 'port_state': 'Link Problem',
     'role': 'Target', 'wwpn': '50017380FE020191'},
    {'component_id': '1:FC_Port:4:1', 'port_state': 'Online', 'role': 'Target',
     'wwpn': '50017380FE020192'},
    {'component_id': '1:FC_Port:5:1', 'port_state': 'Link Problem',
     'role': 'Initiator', 'wwpn': '50017380FE020193'}]

HOST_CONNECTIVITY_LIST = [
    {'host': 'nova-compute-c5507606d5680e05', 'host_port': '10000000C97D26DB',
     'local_fc_port': '1:FC_Port:4:1', 'local_iscsi_port': '',
     'module': '1:Module:4', 'type': 'FC'}]

HOST_CONNECTIVITY_LIST_UNKNOWN_HOST = [
    {'host': 'nova-compute-c5507606d5680f115', 'host_port': '10000000C97D26DE',
     'local_fc_port': '1:FC_Port:3:1', 'local_iscsi_port': '',
     'module': '1:Module:3', 'type': 'FC'}]

REPLICA_ID = 'WTF32'
REPLICA_IP = '1.2.3.4'
REPLICA_USER = 'WTF64'
REPLICA_PASSWORD = 'WTFWTF'
REPLICA_POOL = 'WTF64'
REPLICA_PARAMS = {
    'san_ip': REPLICA_IP,
    'san_login': REPLICA_USER,
    'san_password': cryptish.encrypt(REPLICA_PASSWORD),
    'san_clustername': REPLICA_POOL
}
TEST_POOL = [
    {'name': 'WTF32', 'size': 10026, 'empty_space': 6925}]


class XIVProxyTest(test.TestCase):

    """Tests the main Proxy driver"""

    def setUp(self):
        """import at setup to ensure module patchers are in place"""
        super(XIVProxyTest, self).setUp()

        self.proxy = XIVProxy
        self.version = "cinder"
        self.proxy.configuration = {}
        self.ctxt = context.get_admin_context()

        self.default_storage_info = {
            'user': "WTF32",
            'password': cryptish.encrypt("WTF32"),
            'address': "WTF32",
            'vol_pool': "WTF32",
            'management_ips': "WTF32",
            'system_id': "WTF32"
        }
        self.proxy.configuration['replication_device'] = {
            'backend_id': REPLICA_ID,
            'san_ip': REPLICA_IP,
            'san_user': REPLICA_USER,
            'san_password': REPLICA_PASSWORD,
        }

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.pyxcli")
    def test_wrong_pyxcli(self, mock_pyxcli):

        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        mock_pyxcli.version = '1.1.4'
        self.assertRaises(test_mock.cinder.exception.CinderException,
                          p.setup, {})

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage"
                ".xiv_proxy.socket.getfqdn", new=mock.MagicMock(
                    return_value='test_hostname'))
    def test_setup_should_fail_if_password_is_not_encrypted(self):
        """Passing an unencrypted password should raise an error"""

        storage_info = self.default_storage_info.copy()

        storage_info['password'] = "WTF32"

        p = self.proxy(storage_info, mock.MagicMock(),
                       test_mock.cinder.exception)

        self.assertRaises(test_mock.cinder.exception.InvalidParameterValue,
                          p.setup, {})

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy.client."
                "XCLIClient")
    def test_setup_should_fail_if_pool_is_invalid(self, mock_xcli):
        """Setup should raise exception if pool is invalid"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        cmd = mock_xcli.connect_multiendpoint_ssl.return_value.cmd
        cmd.pool_list.return_value.as_list = []

        self.assertRaises(test_mock.cinder.exception.VolumeBackendAPIException,
                          p.setup, {})

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy.client."
                "XCLIClient")
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy.socket."
                "getfqdn", new=mock.MagicMock(
                    return_value='test_hostname'))
    def test_setup_should_fail_if_credentials_are_invalid(self, mock_xcli):
        """Passing invalid credentials should raise an error"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        mock_xcli.connect_multiendpoint_ssl = mock.MagicMock(
            side_effect=errors.CredentialsError(
                'bla', 'bla', ElementTree.Element("bla")))

        self.assertRaises(test_mock.cinder.exception.NotAuthorized,
                          p.setup, {})

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.client.XCLIClient")
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.socket.getfqdn", new=mock.MagicMock(
                    return_value='test_hostname'))
    def test_setup_should_fail_if_connection_is_invalid(self, mock_xcli):
        """Passing an invalid host to the setup should raise an error"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        mock_xcli.connect_multiendpoint_ssl = mock.MagicMock(
            side_effect=errors.ConnectionError(
                'bla', 'bla', ElementTree.Element("bla")))

        self.assertRaises(test_mock.cinder.exception.HostNotFound,
                          p.setup, {})

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy."
                "client.XCLIClient")
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.storage.get_online_iscsi_ports",
                mock.MagicMock(return_value=['WTF32']))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.socket.getfqdn", new=mock.MagicMock(
                    return_value='test_hostname'))
    def test_setup_should_set_iqn_and_portal(self, mock_xcli):
        """Test setup

        Setup should retrieve values from xcli
        and set the IQN and Portal
        """

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception)

        cmd = mock_xcli.connect_multiendpoint_ssl.return_value.cmd
        item = cmd.config_get.return_value.as_dict.return_value.__getitem__
        item.return_value.value = "BLA"

        p.setup({})

        self.assertEqual("BLA", p.meta.get('ibm_storage_iqn'))
        self.assertEqual("WTF32:3260", p.meta.get('ibm_storage_portal'))

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy."
                "client.XCLIClient")
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.storage.get_online_iscsi_ports",
                mock.MagicMock(return_value=['WTF32']))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.socket.getfqdn", new=mock.MagicMock(
                    return_value='test_hostname'))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target_params",
                mock.MagicMock(return_value=REPLICA_PARAMS))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target",
                mock.MagicMock(return_value="BLABLA"))
    def test_setup_should_succeed_if_replica_is_set(self, mock_xcli):
        """Test setup

        Setup should succeed if replica is set
        """
        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception)

        cmd = mock_xcli.connect_multiendpoint_ssl.return_value.cmd
        item = cmd.config_get.return_value.as_dict.return_value.__getitem__
        item.return_value.value = "BLA"

        SCHEDULE_LIST_RESPONSE = {
            '00:01:00': {'interval': 120},
            '00:02:00': {'interval': 300},
            '00:05:00': {'interval': 600},
            '00:10:00': {'interval': 1200},
        }
        cmd = mock_xcli.connect_multiendpoint_ssl.return_value.cmd
        cmd.schedule_list.return_value\
            .as_dict.return_value = SCHEDULE_LIST_RESPONSE

        p.setup({})

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy."
                "client.XCLIClient")
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.storage.get_online_iscsi_ports",
                mock.MagicMock(return_value=['WTF32']))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.socket.getfqdn", new=mock.MagicMock(
                    return_value='test_hostname'))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target_params",
                mock.MagicMock(return_value=REPLICA_PARAMS))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target",
                mock.MagicMock(return_value="BLABLA"))
    def test_setup_should_fail_if_schedule_create_fails(self, mock_xcli):
        """Test setup

        Setup should fail if replica is set and schedule_create fails
        """

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception)

        cmd = mock_xcli.connect_multiendpoint_ssl.return_value.cmd
        item = cmd.config_get.return_value.as_dict.return_value.__getitem__
        item.return_value.value = "BLA"
        cmd.schedule_list.return_value.as_dict.return_value = {}
        cmd.schedule_create.side_effect = (
            errors.XCLIError('bla'))

        self.assertRaises(exception.VolumeBackendAPIException, p.setup, {})

    def test_get_volume_stats(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.pool_list.return_value.as_list = TEST_POOL
        stats = p.get_volume_stats()
        self.assertEqual("up", stats['backend_state'])

        p.ibm_storage_cli.cmd.pool_list.return_value.as_list = None
        stats = p.get_volume_stats(refresh=True)
        self.assertEqual("down", stats['backend_state'])

    def test_create_volume_should_call_xcli(self):
        """Create volume should call xcli with the correct parameters"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        volume = testutils.create_volume(
            self.ctxt, size=16, display_name='WTF32',
            volume_type_id=self.vt['id'])
        p.create_volume(volume)

        p.ibm_storage_cli.cmd.vol_create.assert_called_once_with(
            vol=volume.name,
            size_blocks=storage.gigabytes_to_blocks(16),
            pool='WTF32')

    def test_create_volume_from_snapshot(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        volume = testutils.create_volume(
            self.ctxt, size=16, display_name='WTF32',
            volume_type_id=self.vt['id'])
        snapshot = testutils.create_snapshot(self.ctxt, volume.id)

        p.create_volume_from_snapshot(volume, snapshot)

        p.ibm_storage_cli.cmd.vol_copy.assert_called_once_with(
            vol_src=snapshot.name,
            vol_trg=volume.name)

    def test_create_volume_should_fail_if_no_pool_space(self):
        """Test create volume

        Create volume should raise an error
        if there's no pool space left
        """
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.vol_create.side_effect = (
            errors.PoolOutOfSpaceError(
                'bla', 'bla', ElementTree.Element('bla')))

        volume = testutils.create_volume(
            self.ctxt, size=16, display_name='WTF32',
            volume_type_id=self.vt['id'])

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_volume, volume)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.VolumeReplication.create_replication",
                mock.MagicMock())
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.GroupReplication.create_replication",
                mock.MagicMock())
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target_params",
                mock.MagicMock(return_value=REPLICA_PARAMS))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target",
                mock.MagicMock(return_value="BLABLA"))
    def test_enable_replication(self):
        """Test enable_replication"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)
        p.ibm_storage_cli = mock.MagicMock()
        p._call_remote_xiv_xcli = mock.MagicMock()
        p._update_consistencygroup = mock.MagicMock()
        p.targets = {'tgt1': 'info1'}

        group = self._create_test_group('WTF')
        vol = testutils.create_volume(self.ctxt,
                                      volume_type_id=self.vt['id'])
        ret = p.enable_replication(self.ctxt, group, [vol])

        self.assertEqual((
            {'replication_status': fields.ReplicationStatus.ENABLED},
            [{'id': vol['id'],
              'replication_status': fields.ReplicationStatus.ENABLED}]), ret)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.VolumeReplication.create_replication",
                mock.MagicMock())
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.GroupReplication.create_replication",
                mock.MagicMock())
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target_params",
                mock.MagicMock(return_value=REPLICA_PARAMS))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target",
                mock.MagicMock(return_value="BLABLA"))
    @mock.patch("cinder.volume.group_types.get_group_type_specs",
                mock.MagicMock(return_value=TEST_GROUP_SPECS))
    def test_enable_replication_remote_cg_exists(self):
        """Test enable_replication"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)
        p.ibm_storage_cli = mock.MagicMock()
        p._call_remote_xiv_xcli = mock.MagicMock()
        p._update_consistencygroup = mock.MagicMock()
        p.targets = {'tgt1': 'info1'}
        error = errors.CgNameExistsError('bla', 'bla',
                                         ElementTree.Element('bla'))
        p._call_remote_xiv_xcli.cmd.cg_create.side_effect = error

        group = self._create_test_group('WTF')
        vol = testutils.create_volume(self.ctxt,
                                      volume_type_id=self.vt['id'])
        ret = p.enable_replication(self.ctxt, group, [vol])

        self.assertEqual((
            {'replication_status': fields.ReplicationStatus.ENABLED},
            [{'id': vol['id'],
              'replication_status': fields.ReplicationStatus.ENABLED}]), ret)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.VolumeReplication.delete_replication",
                mock.MagicMock())
    @mock.patch("cinder.volume.group_types.get_group_type_specs",
                mock.MagicMock(return_value=TEST_GROUP_SPECS))
    def test_disable_replication(self):
        """Test disable_replication"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)
        p.ibm_storage_cli = mock.MagicMock()
        p._call_remote_xiv_xcli = mock.MagicMock()
        p._update_consistencygroup = mock.MagicMock()

        group = self._create_test_group('WTF')
        ret = p.disable_replication(self.ctxt, group, [])

        self.assertEqual((
            {'replication_status': fields.ReplicationStatus.DISABLED}, []),
            ret)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._using_default_backend",
                mock.MagicMock(return_value=False))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target_params",
                mock.MagicMock(return_value={'san_clustername': "master"}))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._init_xcli",
                mock.MagicMock())
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._init_xcli",
                mock.MagicMock())
    @mock.patch("cinder.volume.group_types.get_group_type_specs",
                mock.MagicMock(return_value=TEST_GROUP_SPECS))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.GroupReplication.failover",
                mock.MagicMock(return_value=(True, 'good')))
    def test_failover_replication_with_default(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)
        group = self._create_test_group('WTF')
        group.replication_status = fields.ReplicationStatus.FAILED_OVER
        vol = testutils.create_volume(self.ctxt,
                                      volume_type_id=self.vt['id'])
        group_update, vol_update = p.failover_replication(self.ctxt, group,
                                                          [vol], 'default')
        updates = {'status': 'available'}
        self.assertEqual(({'replication_status': 'enabled'},
                          [{'id': vol['id'],
                            'updates': updates}]), (group_update, vol_update))

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._using_default_backend",
                mock.MagicMock(return_value=True))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target_params",
                mock.MagicMock(return_value={'san_clustername': "master"}))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._init_xcli",
                mock.MagicMock())
    @mock.patch("cinder.volume.group_types.get_group_type_specs",
                mock.MagicMock(return_value=TEST_GROUP_SPECS))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.GroupReplication.failover",
                mock.MagicMock(return_value=(True, 'good')))
    def test_failover_replication(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)
        group = self._create_test_group('WTF')
        failed_over = fields.ReplicationStatus.FAILED_OVER
        group.replication_status = failed_over
        vol = testutils.create_volume(self.ctxt,
                                      volume_type_id=self.vt['id'])
        group_update, vol_update = p.failover_replication(self.ctxt, group,
                                                          [vol],
                                                          'secondary_id')
        failed_over = fields.ReplicationStatus.FAILED_OVER
        updates = {'status': failed_over}
        self.assertEqual(({'replication_status': failed_over},
                          [{'id': vol['id'],
                            'updates': updates}]), (group_update, vol_update))

    def test_failover_resource_no_mirror(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        recovery_mgr = mock.MagicMock()
        recovery_mgr.is_mirror_active = mock.MagicMock()
        recovery_mgr.is_mirror_active.return_value = False

        group = self._create_test_group('WTF')
        ret = xiv_replication.Replication(p)._failover_resource(
            group, recovery_mgr, mock.MagicMock, 'cg', True)
        msg = ("%(rep_type)s %(res)s: no active mirroring and can not "
               "failback" % {'rep_type': 'cg',
                             'res': group['name']})
        self.assertEqual((False, msg), ret)

    def test_failover_resource_mirror(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)
        recovery_mgr = mock.MagicMock()
        recovery_mgr.is_mirror_active = mock.MagicMock()
        recovery_mgr.is_mirror_active.return_value = True

        group = self._create_test_group('WTF')
        ret = xiv_replication.Replication(p)._failover_resource(
            group, recovery_mgr, mock.MagicMock, 'cg', True)

        self.assertEqual((True, None), ret)

    def test_failover_resource_change_role(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)
        recovery_mgr = mock.MagicMock()
        recovery_mgr.is_mirror_active = mock.MagicMock()
        recovery_mgr.is_mirror_active.return_value = True
        recovery_mgr.switch_roles.side_effect = (
            errors.XCLIError(''))
        failover_rep_mgr = mock.MagicMock()
        failover_rep_mgr.change_role = mock.MagicMock()
        group = self._create_test_group('WTF')

        xiv_replication.Replication(p)._failover_resource(
            group, recovery_mgr, failover_rep_mgr, 'cg', True)

        failover_rep_mgr.change_role.assert_called_once_with(
            resource_id=group['name'],
            new_role='Slave')

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target_params",
                mock.MagicMock(return_value=REPLICA_PARAMS))
    def test_pool_with_replication_failover_back(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        pool_name = p._get_backend_pool()
        self.assertEqual(self.default_storage_info['vol_pool'], pool_name)

        p_failback = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver,
            REPLICA_ID)

        pool_name = p_failback._get_backend_pool()
        self.assertEqual(REPLICA_POOL, pool_name)

    @mock.patch("cinder.volume.volume_utils.is_group_a_cg_snapshot_type",
                mock.MagicMock(return_value=True))
    def test_create_volume_with_consistency_group(self):
        """Test Create volume with consistency_group"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p._cg_name_from_volume = mock.MagicMock(return_value="cg")

        vol_type = testutils.create_volume_type(self.ctxt, name='WTF')
        volume = testutils.create_volume(
            self.ctxt, size=16, volume_type_id=vol_type.id)

        grp = self._create_test_group('WTF')
        volume.group = grp
        p.create_volume(volume)

        p.ibm_storage_cli.cmd.vol_create.assert_called_once_with(
            vol=volume['name'],
            size_blocks=storage.gigabytes_to_blocks(16),
            pool='WTF32')
        p.ibm_storage_cli.cmd.cg_add_vol.assert_called_once_with(
            vol=volume['name'],
            cg='cg')

    @mock.patch('pyxcli.mirroring.mirrored_entities.'
                'MirroredEntities', mock.MagicMock())
    @mock.patch('cinder.volume.volume_utils.is_group_a_type',
                mock.MagicMock(return_value=True))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_extra_specs",
                mock.MagicMock(return_value=TEST_EXTRA_SPECS_REPL))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.VolumeReplication.create_replication",
                mock.MagicMock())
    def test_create_volume_with_consistency_group_diff_state(self):
        """Test Create volume with consistency_group but diff state"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p._cg_name_from_volume = mock.MagicMock(return_value="cg")

        vol_type = testutils.create_volume_type(self.ctxt, name='WTF')
        volume = testutils.create_volume(
            self.ctxt, size=16, volume_type_id=vol_type.id,
            host=self._get_test_host()['name'])

        grp = self._create_test_group('WTF')
        grp['replication_status'] = 'enabled'
        volume.group = grp
        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_volume, volume)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.VolumeReplication.create_replication",
                mock.MagicMock())
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_qos_specs",
                mock.MagicMock(return_value=None))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_extra_specs",
                mock.MagicMock(return_value=TEST_EXTRA_SPECS_REPL))
    def test_create_volume_with_replication(self):
        """Test Create volume with replication"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"
        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        volume = testutils.create_volume(
            self.ctxt, size=16, display_name='WTF32',
            volume_type_id=self.vt['id'])
        volume.group = None
        p.create_volume(volume)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.VolumeReplication.create_replication",
                mock.MagicMock())
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_qos_specs",
                mock.MagicMock(return_value=None))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_extra_specs",
                mock.MagicMock(return_value=TEST_EXTRA_SPECS_REPL))
    def test_create_volume_with_replication_and_cg(self):
        """Test Create volume with replication and CG"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        volume = testutils.create_volume(
            self.ctxt, size=16, display_name='WTF32',
            volume_type_id=self.vt['id'])
        grp = testutils.create_group(self.ctxt, name='bla', group_type_id='1')
        volume.group = grp
        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_volume, volume)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_qos_specs",
                mock.MagicMock(return_value=None))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_extra_specs",
                mock.MagicMock(return_value=TEST_EXTRA_SPECS_REPL))
    def test_create_volume_with_replication_multiple_targets(self):
        """Test Create volume with replication and multiple targets"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        volume = testutils.create_volume(
            self.ctxt, size=16, display_name='WTF32',
            volume_type_id=self.vt['id'])
        volume.group = None
        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_volume, volume)

    def test_delete_volume_should_pass_the_correct_parameters(self):
        """Delete volume should call xcli with the correct parameters"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.vol_list.return_value.as_list = ['aa']

        p.delete_volume({'name': 'WTF32'})

        p.ibm_storage_cli.cmd.vol_delete.assert_called_once_with(vol='WTF32')

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_replication.VolumeReplication.delete_replication",
                mock.MagicMock())
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_extra_specs",
                mock.MagicMock(return_value=TEST_EXTRA_SPECS_REPL))
    def test_delete_volume_with_replication(self):
        """Test Delete volume with replication"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        volume = {'size': 16, 'name': 'WTF32', 'volume_type_id': 'WTF'}
        p.delete_volume(volume)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_extra_specs",
                mock.MagicMock(return_value=TEST_EXTRA_SPECS_REPL))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.client.XCLIClient")
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target_params",
                mock.MagicMock(return_value=REPLICA_PARAMS))
    def test_failover_host(self, mock_xcli):
        """Test failover_host with valid target"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock_xcli
        p.ibm_storage_cli.connect_multiendpoint_ssl.return_value
        mock_xcli.connect_multiendpoint_ssl.return_value = mock_xcli

        volume = {'id': 'WTF64', 'size': 16,
                  'name': 'WTF32', 'volume_type_id': 'WTF'}
        target = REPLICA_ID
        p.failover_host({}, [volume], target, [])

    def test_failover_host_invalid_target(self):
        """Test failover_host with invalid target"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        volume = {'id': 'WTF64', 'size': 16,
                  'name': 'WTF32', 'volume_type_id': 'WTF'}
        target = 'Invalid'
        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.failover_host, {}, [volume], target, [])

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.client.XCLIClient")
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target_params",
                mock.MagicMock(return_value=REPLICA_PARAMS))
    def test_failover_host_no_connection_to_target(self, mock_xcli):
        """Test failover_host that fails to connect to target"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock_xcli
        p.ibm_storage_cli.connect_multiendpoint_ssl.return_value
        mock_xcli.connect_multiendpoint_ssl.side_effect = errors.XCLIError('')

        volume = {'id': 'WTF64', 'size': 16,
                  'name': 'WTF32', 'volume_type_id': 'WTF'}
        target = REPLICA_ID
        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.failover_host, {}, [volume], target, [])

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.client.XCLIClient")
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_target_params",
                mock.MagicMock(return_value=REPLICA_PARAMS))
    def test_failback_host(self, mock_xcli):
        """Test failing back after DR"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        volume = {'id': 'WTF64', 'size': 16,
                  'name': 'WTF32', 'volume_type_id': 'WTF'}
        target = 'default'
        p.failover_host(None, [volume], target, [])

    def qos_test_empty_name_if_no_specs(self):
        """Test empty name in case no specs are specified"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        perf_name = p._check_perf_class_on_backend({})
        self.assertEqual('', perf_name)

    def test_qos_class_name_contains_qos_type(self):
        """Test backend naming

        Test if the naming convention is correct
        when getting the right specs with qos type
        """
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.perf_class_list.return_value.as_list = []
        perf_name = p._check_perf_class_on_backend({'bw': '100',
                                                    'type': 'independent'})

        self.assertEqual('cinder-qos_bw_100_type_independent', perf_name)

    def test_qos_called_with_type_parameter(self):
        """Test xcli call for qos creation with type"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.perf_class_list.return_value.as_list = []
        perf_name = p._check_perf_class_on_backend({'bw': '100',
                                                    'type': 'independent'})
        p.ibm_storage_cli.cmd.perf_class_create.assert_called_once_with(
            perf_class=perf_name,
            type='independent')

    def test_qos_called_with_wrong_type_parameter(self):
        """Test xcli call for qos creation with wrong type"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.perf_class_list.return_value.as_list = []
        p.ibm_storage_cli.cmd.perf_class_create.side_effect = (
            errors.XCLIError('llegal value'))

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p._check_perf_class_on_backend,
                          {'bw': '100', 'type': 'BAD'})

    def test_qos_class_on_backend_name_correct(self):
        """Test backend naming

        Test if the naming convention is correct
        when getting the right specs
        """
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.perf_class_list.return_value.as_list = []
        perf_name = p._check_perf_class_on_backend({'bw': '100'})

        self.assertEqual('cinder-qos_bw_100', perf_name)

    def test_qos_xcli_exception(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.perf_class_list.side_effect = (
            errors.XCLIError(''))

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p._check_perf_class_on_backend, {'bw': '100'})

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._qos_create_kwargs_for_xcli",
                mock.MagicMock(return_value={}))
    def test_regex_from_perf_class_name(self):
        """Test type extraction from perf_class with Regex"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        perf_class_names_list = [
            {'class_name': 'cinder-qos_iops_1000_type_independent_bw_1000',
             'type': 'independent'},
            {'class_name': 'cinder-qos_iops_1000_bw_1000_type_shared',
             'type': 'shared'},
            {'class_name': 'cinder-qos_type_badtype_bw_1000',
             'type': None}]

        for element in perf_class_names_list:
            _type = p._get_type_from_perf_class_name(
                perf_class_name=element['class_name'])
            self.assertEqual(element['type'], _type)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._qos_create_kwargs_for_xcli",
                mock.MagicMock(return_value={}))
    def test_create_qos_class_with_type(self):
        """Test performance class creation with type"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.perf_class_set_rate.return_value = None
        p.ibm_storage_cli.cmd.perf_class_create.return_value = None

        perf_class_name = 'cinder-qos_iops_1000_type_independent_bw_1000'
        p_class_name = p._create_qos_class(perf_class_name=perf_class_name,
                                           specs=None)

        p.ibm_storage_cli.cmd.perf_class_create.assert_called_once_with(
            perf_class=perf_class_name,
            type='independent')
        self.assertEqual('cinder-qos_iops_1000_type_independent_bw_1000',
                         p_class_name)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._check_storage_version_for_qos_support",
                mock.MagicMock(return_value=True))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_qos_specs",
                mock.MagicMock(return_value='specs'))
    def test_qos_specs_exist_if_type_exists(self):
        """Test a case where type was found and qos were found"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        volume = {'name': 'bla', 'volume_type_id': '7'}
        specs = p._qos_specs_from_volume(volume)
        self.assertEqual('specs', specs)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._check_storage_version_for_qos_support",
                mock.MagicMock(return_value=True))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_qos_specs",
                mock.MagicMock(return_value=None))
    def test_no_qos_but_type_exists(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        volume = {'name': 'bla', 'volume_type_id': '7'}
        specs = p._qos_specs_from_volume(volume)
        self.assertIsNone(specs)

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._check_storage_version_for_qos_support",
                mock.MagicMock(return_value=True))
    @mock.patch("cinder.volume.drivers.ibm.ibm_storage."
                "xiv_proxy.XIVProxy._get_qos_specs",
                mock.MagicMock(return_value=None))
    def test_qos_specs_doesnt_exist_if_no_type(self):
        """Test _qos_specs_from_volume

        Test a case where no type was defined
        and therefore no specs exist
        """
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        volume = {'name': 'bla'}
        specs = p._qos_specs_from_volume(volume)
        self.assertIsNone(specs)

    def test_manage_volume_should_call_xcli(self):
        """Manage volume should call xcli with the correct parameters"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.vol_list.return_value.as_list = [
            {'name': 'WTF64', 'size': 34}]
        p.manage_volume(volume={'name': 'WTF32'},
                        reference={'source-name': 'WTF64'})

        p.ibm_storage_cli.cmd.vol_list.assert_called_once_with(
            vol='WTF64')

    def test_manage_volume_should_return_volume_if_exists(self):
        """Manage volume should return with no errors"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.vol_list.return_value.as_list = [
            {'name': 'WTF64', 'size': 34}]
        volume = {'name': 'WTF32'}
        p.manage_volume(volume=volume,
                        reference={'source-name': 'WTF64'})

        self.assertEqual(34, volume['size'])

    def test_manage_volume_should_raise_exception_if_not_exists(self):
        """Test manage_volume

        Manage volume should return with exception
        if volume does not exist
        """
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.vol_list.return_value.as_list = []

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.manage_volume, volume={'name': 'WTF32'},
                          reference={'source-name': 'WTF64'})

    def test_manage_volume_get_size_if_volume_exists(self):
        """Manage volume get size should return size"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.vol_list.return_value.as_list = [
            {'name': 'WTF64', 'size': 34}]
        volume = {'name': 'WTF32'}
        size = p.manage_volume_get_size(volume=volume,
                                        reference={'source-name': 'WTF64'})

        self.assertEqual(34, size)

    def test_retype_false_if_no_location(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        volume = {'display_name': 'vol'}
        new_type = {}
        new_type['name'] = "type1"
        host = {'capabilities': ''}
        diff = {}
        ret = p.retype({}, volume, new_type, diff, host)
        self.assertFalse(ret)

    def test_retype_false_if_dest_not_xiv_backend(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        host = {'capabilities': {'location_info': "IBM-XIV:host:pool"}}
        volume = {'display_name': 'vol', 'host': "origdest_orighost_origpool"}
        new_type = {'name': "type1"}
        diff = {}
        ret = p.retype({}, volume, new_type, diff, host)
        self.assertFalse(ret)

    def test_retype_true_if_dest_is_xiv_backend(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.migrate_volume = mock.MagicMock()
        p.migrate_volume.return_value = (True, None)
        p._qos_specs_from_volume = mock.MagicMock()
        p._get_qos_specs = mock.MagicMock()
        p._qos_specs_from_volume.return_value = {}
        p._get_qos_specs.return_value = {}

        host = {'capabilities': {'location_info': "IBM-XIV:host:pool"}}
        volume = {'display_name': 'vol', 'host': "IBM-XIV_host_pool"}
        new_type = {'name': "type1"}
        diff = {}
        ret = p.retype({}, volume, new_type, diff, host)
        self.assertTrue(ret)

    def test_manage_volume_get_size_should_raise_exception_if_not_exists(self):
        """Test manage_volume

        Manage volume get size should raise exception
        if volume does not exist
        """
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.vol_list.return_value.as_list = []

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.manage_volume_get_size,
                          volume={'name': 'WTF32'},
                          reference={'source-name': 'WTF64'})

    def test_initialize_connection(self):
        """Test initialize_connection

        Ensure that initialize connection returns,
        all the correct connection values
        """

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception)

        p.ibm_storage_iqn = "BLAIQN"
        p.ibm_storage_portal = "BLAPORTAL"

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.vol_list.return_value.as_list = ['aa']
        host = self._get_test_host()
        setattr(
            p, '_get_host_and_fc_targets', mock.MagicMock(return_value=(
                [], host)))
        setattr(
            p, '_vol_map_and_get_lun_id', mock.MagicMock(return_value=100))
        p.volume_exists = mock.MagicMock(return_value=True)

        info = p.initialize_connection(TEST_VOLUME, {})

        self.assertEqual(
            p.meta.get('ibm_storage_portal'),
            info['data']['target_portal'])
        self.assertEqual(
            p.meta.get('ibm_storage_iqn'),
            info['data']['target_iqn'])
        self.assertEqual(100, info['data']['target_lun'])

    def test_initialize_connection_no_initiator(self):
        """Initialize connection raises exception on missing initiator"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        connector = TEST_CONNECTOR.copy()
        connector['initiator'] = None

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.initialize_connection, TEST_VOLUME,
                          connector)

    def test_initialize_connection_bad_iqn(self):
        """Initialize connection raises exception on bad formatted IQN"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        connector = TEST_CONNECTOR.copy()
        # any string would pass for initiator
        connector['initiator'] = 5555

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.initialize_connection, TEST_VOLUME,
                          connector)

    def test_get_fc_targets_returns_optimized_wwpns_list(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.fc_port_list.return_value = FC_PORT_LIST_OUTPUT
        fc_targets = p._get_fc_targets(None)
        six.assertCountEqual(self, FC_TARGETS_OPTIMIZED, fc_targets)

    def test_get_fc_targets_returns_host_optimized_wwpns_list(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        hostname = storage.get_host_or_create_from_iqn(TEST_CONNECTOR)
        host = {'name': hostname}
        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.fc_port_list.return_value = FC_PORT_LIST_OUTPUT
        p.ibm_storage_cli.cmd.host_connectivity_list.return_value = (
            HOST_CONNECTIVITY_LIST)
        fc_targets = p._get_fc_targets(host)
        six.assertCountEqual(self,
                             FC_TARGETS_OPTIMIZED_WITH_HOST, fc_targets,
                             "FC targets are different from the expected")

    def test_get_fc_targets_returns_host_all_wwpns_list(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        hostname = storage.get_host_or_create_from_iqn(TEST_CONNECTOR)
        host = {'name': hostname}
        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.fc_port_list.return_value = FC_PORT_LIST_OUTPUT
        p.ibm_storage_cli.cmd.host_connectivity_list.return_value = (
            HOST_CONNECTIVITY_LIST_UNKNOWN_HOST)
        fc_targets = p._get_fc_targets(host)
        six.assertCountEqual(self,
                             FC_TARGETS_OPTIMIZED, fc_targets,
                             "FC targets are different from the expected")

    def test_define_fc_returns_all_wwpns_list(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.fc_port_list.return_value = FC_PORT_LIST_OUTPUT
        p.ibm_storage_cli.fc_connectivity_list.return_value = ()
        fc_targets = p._define_fc(p._define_host(TEST_CONNECTOR))
        six.assertCountEqual(self,
                             FC_TARGETS_OPTIMIZED, fc_targets,
                             "FC targets are different from the expected")

    def test_define_ports_returns_sorted_wwpns_list(self):
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p._get_connection_type = mock.MagicMock(
            return_value=storage.XIV_CONNECTION_TYPE_FC)
        p._define_fc = mock.MagicMock(return_value=FC_TARGETS_BEFORE_SORTING)
        fc_targets = p._define_ports(self._get_test_host())
        fc_result = list(map(lambda x: x[-1:], fc_targets))
        expected_result = list(map(lambda x: x[-1:], FC_TARGETS_AFTER_SORTING))
        self.assertEqual(expected_result, fc_result,
                         "FC targets are different from the expected")

    def test_get_host_and_fc_targets_if_host_not_defined(self):
        """Test host and FC targets

        Tests that host and fc targets are provided
        if the host is not defined
        """

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception)

        p.meta = mock.MagicMock()
        p.meta.ibm_storage_iqn = "BLAIQN"
        p.meta.ibm_storage_portal = "BLAPORTAL"
        p.meta.openstack_version = "cinder-2013.2"

        pool = {'name': "WTF32", 'domain': 'pool_domain_bla'}

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.host_list.return_value.as_list = []
        p.ibm_storage_cli.cmd.host_list_ports.return_value = []
        p.ibm_storage_cli.cmd.pool_list.return_value.as_list = [pool]
        p._get_bunch_from_host = mock.MagicMock()
        p._get_bunch_from_host.return_value = {
            'name': "nova-compute-%s" % TEST_INITIATOR,
            'initiator': TEST_INITIATOR,
            'id': 123, 'wwpns': 111, 'chap': 'chap', }

        fc_targets, host = getattr(p, '_get_host_and_fc_targets')(
            TEST_VOLUME, TEST_CONNECTOR)

        hostname = storage.get_host_or_create_from_iqn(TEST_CONNECTOR)
        p.ibm_storage_cli.cmd.host_define.assert_called_once_with(
            host=hostname, domain=pool.get('domain'))
        p.ibm_storage_cli.cmd.host_add_port.assert_called_once_with(
            host=hostname, iscsi_name=TEST_CONNECTOR['initiator'])

    def test_get_lun_id_if_host_already_mapped(self):
        """Test lun id

        Tests that a lun is provided if host is already
        mapped to other volumes
        """
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        vol_mapping_list = p.ibm_storage_cli.cmd.vol_mapping_list
        vol_mapping_list.return_value.as_dict.return_value = {}
        lun1 = {'lun': 1}
        lun2 = {'lun': 2}
        p.ibm_storage_cli.cmd.mapping_list.return_value.as_list = [lun1, lun2]

        host = self._get_test_host()
        self.assertEqual(
            3, getattr(p, '_vol_map_and_get_lun_id')(
                TEST_VOLUME, TEST_CONNECTOR, host))

    def test_terminate_connection_should_call_unmap_vol(self):
        """Terminate connection should call unmap vol"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p._get_connection_type = mock.MagicMock(
            return_value=storage.XIV_CONNECTION_TYPE_FC)
        p._get_fc_targets = mock.MagicMock(return_value=TEST_WWPNS)
        p.ibm_storage_cli = mock.MagicMock()
        vol_mapping_ret = p.ibm_storage_cli.cmd.vol_mapping_list.return_value
        vol_mapping_ret.as_dict.return_value.has_keys.return_value = True

        p.ibm_storage_cli.cmd.vol_list.return_value.as_list = ['aa']

        hostname = storage.get_host_or_create_from_iqn(TEST_CONNECTOR)
        host = {
            'name': hostname,
            'initiator': TEST_CONNECTOR['initiator'],
            'id': 1
        }
        TEST_CONNECTOR['wwpns'] = [TEST_INITIATOR]

        setattr(p, "_get_host", mock.MagicMock(return_value=host))

        meta = p.terminate_connection(TEST_VOLUME, TEST_CONNECTOR)

        self.assertEqual(
            TEST_TARGET_MAP, meta['data']['initiator_target_map'])

        p.ibm_storage_cli.cmd.unmap_vol.assert_called_once_with(
            vol=TEST_VOLUME['name'], host=hostname)

    def test_terminate_connection_multiple_connections(self):
        # Terminate connection should not return meta if host is still
        # connected

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception)

        p.ibm_storage_cli = mock.MagicMock()
        vol_dict = p.ibm_storage_cli.cmd.vol_mapping_list.return_value.as_dict
        vol_dict.return_value.has_keys.return_value = True

        p.ibm_storage_cli.cmd.vol_list.return_value.as_list = ['aa']

        hostname = storage.get_host_or_create_from_iqn(TEST_CONNECTOR)
        host = {
            'name': hostname,
            'initiator': TEST_CONNECTOR['initiator'],
            'id': 1
        }
        TEST_CONNECTOR['wwpns'] = [TEST_INITIATOR]

        map_dict = p.ibm_storage_cli.cmd.mapping_list.return_value.as_dict
        map_dict.return_value.has_keys.return_value = host

        setattr(p, "_get_host", mock.MagicMock(return_value=host))

        meta = p.terminate_connection(TEST_VOLUME, TEST_CONNECTOR)

        self.assertIsNone(meta)

        p.ibm_storage_cli.cmd.unmap_vol.assert_called_once_with(
            vol=TEST_VOLUME['name'], host=hostname)

    def test_attach_deleted_volume_should_fail_with_info_to_log(self):
        """Test attach deleted volume should fail with info to log"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        mock_log = mock.MagicMock()
        setattr(p, "_log", mock_log)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.vol_mapping_list.side_effect = (
            errors.VolumeBadNameError('bla', 'bla',
                                      ElementTree.Element('Bla')))
        p._define_host_according_to_chap = mock.MagicMock()
        p._define_host_according_to_chap.return_value = dict(id=100)
        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.initialize_connection, TEST_VOLUME,
                          TEST_CONNECTOR)

    def _get_test_host(self):
        host = {
            'name': TEST_HOST_NAME,
            'initiator': TEST_INITIATOR,
            'id': TEST_HOST_ID,
            'wwpns': [TEST_INITIATOR],
            'chap': (TEST_CHAP_NAME, TEST_CHAP_SECRET)
        }
        return host

    def _create_test_group(self, g_name='group', is_cg=True):
        extra_specs = {}
        if is_cg:
            extra_specs['consistent_group_snapshot_enabled'] = '<is> True'

        group_type = group_types.create(self.ctxt, g_name, extra_specs)
        return testutils.create_group(self.ctxt,
                                      host=self._get_test_host()['name'],
                                      group_type_id=group_type.id,
                                      volume_type_ids=[])

    def _create_test_cgsnapshot(self, group_id):
        group_type = group_types.create(
            self.ctxt, 'group_snapshot',
            {'consistent_group_snapshot_enabled': '<is> True'})
        return testutils.create_group_snapshot(self.ctxt, group_id=group_id,
                                               group_type_id=group_type.id)

    def test_create_generic_group(self):
        """test create generic group"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        group_obj = self._create_test_group(is_cg=False)

        self.assertRaises(NotImplementedError,
                          p.create_group, {}, group_obj)

    def test_create_consistencygroup(self):
        """test a successful cg create"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        group_obj = self._create_test_group()

        model_update = p.create_group({}, group_obj)

        p.ibm_storage_cli.cmd.cg_create.assert_called_once_with(
            cg=p._cg_name_from_id(group_obj.id),
            pool='WTF32')

        self.assertEqual('available', model_update['status'])

    def test_create_consistencygroup_already_exists(self):
        """test create_consistenygroup when cg already exists"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.cg_create.side_effect = errors.CgNameExistsError(
            'bla', 'bla', ElementTree.Element('bla'))

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group, {}, self._create_test_group())

    def test_create_consistencygroup_reached_limit(self):
        """test create_consistenygroup when reached maximum CGs"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.cg_create.side_effect = (
            errors.CgLimitReachedError(
                'bla', 'bla', ElementTree.Element('bla')))

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group, {}, self._create_test_group())

    @mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy."
                "client.XCLIClient")
    def test_create_consistencygroup_with_replication(self, mock_xcli):
        """test create_consistenygroup when replication is set"""

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception)

        p.ibm_storage_cli = mock.MagicMock()

        group_obj = self._create_test_group()

        vol_type = objects.VolumeType(context=self.ctxt,
                                      name='volume_type_rep',
                                      extra_specs=(
                                          {'replication_enabled': '<is> True',
                                           'replication_type': 'sync'}))
        group_obj.volume_types = objects.VolumeTypeList(context=self.ctxt,
                                                        objects=[vol_type])

        model_update = p.create_group({}, group_obj)
        self.assertEqual('available', model_update['status'])

    def test_create_consistencygroup_from_src_cgsnapshot(self):
        """test a successful cg create from cgsnapshot"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.create_volume_from_snapshot.return_value = []

        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        volume = testutils.create_volume(self.ctxt,
                                         volume_type_id=self.vt['id'])
        snapshot = testutils.create_snapshot(self.ctxt, volume.id)

        model_update, vols_model_update = p.create_group_from_src(
            {}, group_obj, [volume],
            cgsnap_group_obj, [snapshot], None, None)

        p.ibm_storage_cli.cmd.cg_create.assert_called_once_with(
            cg=p._cg_name_from_id(group_obj.id), pool='WTF32')

        self.assertEqual('available', model_update['status'])

    def test_create_consistencygroup_from_src_cg(self):
        """test a successful cg create from consistencygroup"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.create_volume_from_snapshot.return_value = []

        group_obj = self._create_test_group()
        src_group_obj = self._create_test_group(g_name='src_group')

        volume = testutils.create_volume(self.ctxt,
                                         volume_type_id=self.vt['id'])
        src_volume = testutils.create_volume(self.ctxt,
                                             volume_type_id=self.vt['id'])

        model_update, vols_model_update = p.create_group_from_src(
            {}, group_obj, [volume],
            None, None, src_group_obj, [src_volume])

        p.ibm_storage_cli.cmd.cg_create.assert_called_once_with(cg=group_obj,
                                                                pool='WTF32')

        self.assertEqual('available', model_update['status'])

    def test_create_consistencygroup_from_src_fails_cg_create_from_cgsnapshot(
            self):
        """test cg create from cgsnapshot fails on cg_create"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.cg_create.side_effect = errors.XCLIError(
            'bla', 'bla', ElementTree.Element('bla'))

        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        volume = testutils.create_volume(self.ctxt,
                                         volume_type_id=self.vt['id'])
        snapshot = testutils.create_snapshot(self.ctxt, volume.id)

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group_from_src, {},
                          group_obj, [volume], cgsnap_group_obj,
                          [snapshot], None, None)

    def test_create_consistencygroup_from_src_fails_cg_create_from_cg(self):
        """test cg create from cg fails on cg_create"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.cg_create.side_effect = errors.XCLIError(
            'bla', 'bla', ElementTree.Element('bla'))

        group_obj = self._create_test_group()
        src_group_obj = self._create_test_group(g_name='src_group')

        volume = testutils.create_volume(self.ctxt,
                                         volume_type_id=self.vt['id'])
        src_volume = testutils.create_volume(self.ctxt,
                                             volume_type_id=self.vt['id'])

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group_from_src, {},
                          group_obj, [volume], None, None,
                          src_group_obj, [src_volume])

    def test_create_consistencygroup_from_src_fails_vol_create_from_cgsnapshot(
            self):
        """test cg create from cgsnapshot fails on vol_create"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.vol_create.side_effect = errors.XCLIError(
            'bla', 'bla', ElementTree.Element('bla'))

        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        volume = testutils.create_volume(self.ctxt,
                                         volume_type_id=self.vt['id'])
        snapshot = testutils.create_snapshot(self.ctxt, volume.id)

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group_from_src, {},
                          group_obj, [volume], cgsnap_group_obj,
                          [snapshot], None, None)

    def test_create_consistencygroup_from_src_fails_vol_create_from_cg(self):
        """test cg create from cg fails on vol_create"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.vol_create.side_effect = errors.XCLIError(
            'bla', 'bla', ElementTree.Element('bla'))

        group_obj = self._create_test_group()
        src_group_obj = self._create_test_group(g_name='src_group')

        volume = testutils.create_volume(self.ctxt,
                                         volume_type_id=self.vt['id'])
        src_volume = testutils.create_volume(self.ctxt,
                                             volume_type_id=self.vt['id'])

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group_from_src, {},
                          group_obj, [volume], None, None,
                          src_group_obj, [src_volume])

    def test_create_consistencygroup_from_src_fails_vol_copy_from_cgsnapshot(
            self):
        """test cg create from cgsnapshot fails on vol_copy"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.vol_copy.side_effect = errors.XCLIError(
            'bla', 'bla', ElementTree.Element('bla'))

        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        volume = testutils.create_volume(self.ctxt,
                                         volume_type_id=self.vt['id'])
        snapshot = testutils.create_snapshot(self.ctxt, volume.id)

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group_from_src, {}, group_obj,
                          [volume], cgsnap_group_obj, [snapshot],
                          None, None)

    def test_create_consistencygroup_from_src_fails_vol_copy_from_cg(self):
        """test cg create from cg fails on vol_copy"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.vol_copy.side_effect = errors.XCLIError(
            'bla', 'bla', ElementTree.Element('bla'))

        group_obj = self._create_test_group()
        src_group_obj = self._create_test_group(g_name='src_group')

        volume = testutils.create_volume(self.ctxt,
                                         volume_type_id=self.vt['id'])
        src_volume = testutils.create_volume(self.ctxt,
                                             volume_type_id=self.vt['id'])

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group_from_src, {},
                          group_obj, [volume], None, None,
                          src_group_obj, [src_volume])

    def test_delete_consistencygroup_with_no_volumes(self):
        """test a successful cg delete"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        group_obj = self._create_test_group()

        model_update, volumes = p.delete_group({}, group_obj, [])

        p.ibm_storage_cli.cmd.cg_delete.assert_called_once_with(
            cg=p._cg_name_from_id(group_obj.id))

        self.assertEqual('deleted', model_update['status'])

    def test_delete_consistencygroup_not_exists(self):
        """test delete_consistenygroup when CG does not exist"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.cg_delete.side_effect = (
            errors.CgDoesNotExistError(
                'bla', 'bla', ElementTree.Element('bla')))

        group_obj = self._create_test_group()

        model_update, volumes = p.delete_group({}, group_obj, [])

        p.ibm_storage_cli.cmd.cg_delete.assert_called_once_with(
            cg=p._cg_name_from_id(group_obj.id))

        self.assertEqual('deleted', model_update['status'])

    def test_delete_consistencygroup_not_exists_2(self):
        """test delete_consistenygroup when CG does not exist bad name"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.cg_delete.side_effect = (
            errors.CgBadNameError(
                'bla', 'bla', ElementTree.Element('bla')))

        group_obj = self._create_test_group()
        model_update, volumes = p.delete_group({}, group_obj, [])

        p.ibm_storage_cli.cmd.cg_delete.assert_called_once_with(
            cg=p._cg_name_from_id(group_obj.id))

        self.assertEqual('deleted', model_update['status'])

    def test_delete_consistencygroup_not_empty(self):
        """test delete_consistenygroup when CG is not empty"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.cg_delete.side_effect = errors.CgNotEmptyError(
            'bla', 'bla', ElementTree.Element('bla'))

        group_obj = self._create_test_group()

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.delete_group, {}, group_obj, [])

    def test_delete_consistencygroup_replicated(self):
        """test delete cg when CG is not empty and replicated"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        group_obj = self._create_test_group()
        group_obj['replication_status'] = fields.ReplicationStatus.ENABLED
        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.delete_group, {}, group_obj, [])

    def test_delete_consistencygroup_faildover(self):
        """test delete cg when CG is faildover"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        group_obj = self._create_test_group()
        group_obj['replication_status'] = fields.ReplicationStatus.FAILED_OVER
        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.delete_group, {}, group_obj, [])

    def test_delete_consistencygroup_is_mirrored(self):
        """test delete_consistenygroup when CG is mirroring"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.cg_delete.side_effect = errors.CgHasMirrorError(
            'bla', 'bla', ElementTree.Element('bla'))

        group_obj = self._create_test_group()

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.delete_group, {}, group_obj, [])

    def test_update_consistencygroup(self):
        """test update_consistencygroup"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        group_obj = self._create_test_group()
        vol_add = testutils.create_volume(self.ctxt, display_name='WTF32',
                                          volume_type_id=self.vt['id'])
        vol_remove = testutils.create_volume(self.ctxt, display_name='WTF64',
                                             volume_type_id=self.vt['id'])

        model_update, add_model_update, remove_model_update = (
            p.update_group({}, group_obj, [vol_add], [vol_remove]))

        p.ibm_storage_cli.cmd.cg_add_vol.assert_called_once_with(
            vol=vol_add['name'], cg=p._cg_name_from_id(group_obj.id))
        p.ibm_storage_cli.cmd.cg_remove_vol.assert_called_once_with(
            vol=vol_remove['name'])
        self.assertEqual('available', model_update['status'])

    def test_update_consistencygroup_exception_in_add_vol(self):
        """test update_consistencygroup with exception in cg_add_vol"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.cg_add_vol.side_effect = errors.XCLIError(
            'bla', 'bla', ElementTree.Element('bla'))

        group_obj = self._create_test_group()
        vol_add = testutils.create_volume(self.ctxt, display_name='WTF32',
                                          volume_type_id=self.vt['id'])

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.update_group, {}, group_obj, [vol_add], [])

    def test_update_consistencygroup_exception_in_remove_vol(self):
        """test update_consistencygroup with exception in cg_remove_vol"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.cg_remove_vol.side_effect = errors.XCLIError(
            'bla', 'bla', ElementTree.Element('bla'))

        group_obj = self._create_test_group()
        vol_remove = testutils.create_volume(self.ctxt,
                                             volume_type_id=self.vt['id'])

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.update_group, {},
                          group_obj, [], [vol_remove])

    def test_update_consistencygroup_remove_non_exist_vol_(self):
        """test update_group with exception in cg_remove_vol"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        p.ibm_storage_cli.cmd.cg_remove_vol.side_effect = (
            errors.VolumeNotInConsGroup(
                'bla', 'bla', ElementTree.Element('bla')))

        group_obj = self._create_test_group()
        vol_remove = testutils.create_volume(self.ctxt,
                                             volume_type_id=self.vt['id'])

        model_update, add_model_update, remove_model_update = (
            p.update_group({}, group_obj, [], [vol_remove]))

        p.ibm_storage_cli.cmd.cg_remove_vol.assert_called_once_with(
            vol=vol_remove['name'])
        self.assertEqual('available', model_update['status'])

    def test_create_cgsnapshot(self):
        """test a successful cgsnapshot create"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        model_update, snapshots_model_update = (
            p.create_group_snapshot({}, cgsnap_group_obj, []))

        p.ibm_storage_cli.cmd.cg_snapshots_create.assert_called_once_with(
            cg=p._cg_name_from_cgsnapshot(cgsnap_group_obj),
            snap_group=p._group_name_from_cgsnapshot_id(
                cgsnap_group_obj['id']))

        self.assertEqual('available', model_update['status'])

    def test_create_cgsnapshot_is_empty(self):
        """test create_cgsnapshot when CG is empty"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        p.ibm_storage_cli.cmd.cg_snapshots_create.side_effect = (
            errors.CgEmptyError('bla', 'bla', ElementTree.Element('bla')))

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group_snapshot, {},
                          cgsnap_group_obj, [])

    def test_create_cgsnapshot_cg_not_exist(self):
        """test create_cgsnapshot when CG does not exist"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        p.ibm_storage_cli.cmd.cg_snapshots_create.side_effect = (
            errors.CgDoesNotExistError(
                'bla', 'bla', ElementTree.Element('bla')))

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group_snapshot, {},
                          cgsnap_group_obj, [])

    def test_create_cgsnapshot_snapshot_limit(self):
        """test create_cgsnapshot when reached snapshot limit"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        p.ibm_storage_cli.cmd.cg_snapshots_create.side_effect = (
            errors.PoolSnapshotLimitReachedError(
                'bla', 'bla', ElementTree.Element('bla')))

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.create_group_snapshot, {},
                          cgsnap_group_obj, [])

    def test_delete_cgsnapshot(self):
        """test a successful cgsnapshot delete"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        model_update, snapshots_model_update = p.delete_group_snapshot(
            {}, cgsnap_group_obj, [])

        p.ibm_storage_cli.cmd.snap_group_delete.assert_called_once_with(
            snap_group=p._group_name_from_cgsnapshot_id(
                cgsnap_group_obj['id']))

        self.assertEqual('deleted', model_update['status'])

    def test_delete_cgsnapshot_cg_does_not_exist(self):
        """test delete_cgsnapshot with bad CG name"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        p.ibm_storage_cli.cmd.snap_group_delete.side_effect = (
            errors.CgDoesNotExistError(
                'bla', 'bla', ElementTree.Element('bla')))

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.delete_group_snapshot, {},
                          cgsnap_group_obj, [])

    def test_delete_cgsnapshot_no_space_left_for_snapshots(self):
        """test delete_cgsnapshot when no space left for snapshots"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        p.ibm_storage_cli.cmd.snap_group_delete.side_effect = (
            errors.PoolSnapshotLimitReachedError(
                'bla', 'bla', ElementTree.Element('bla')))

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.delete_group_snapshot, {},
                          cgsnap_group_obj, [])

    def test_delete_cgsnapshot_with_empty_consistency_group(self):
        """test delete_cgsnapshot with empty consistency group"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()
        group_obj = self._create_test_group()
        cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)

        p.ibm_storage_cli.cmd.snap_group_delete.side_effect = (
            errors.CgEmptyError('bla', 'bla', ElementTree.Element('bla')))

        ex = getattr(p, "_get_exception")()
        self.assertRaises(ex, p.delete_group_snapshot, {},
                          cgsnap_group_obj, [])

    def test_silent_delete_volume(self):
        """test _silent_delete_volume fails silently without exception"""
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        p.ibm_storage_cli = mock.MagicMock()

        p.ibm_storage_cli.cmd.vol_delete.side_effect = errors.XCLIError(
            'bla', 'bla', ElementTree.Element('bla'))

        # check no assertion occurs
        p._silent_delete_volume(TEST_VOLUME)

    @mock.patch("cinder.volume.volume_utils.group_get_by_id", mock.MagicMock())
    @mock.patch("cinder.volume.volume_utils.is_group_a_cg_snapshot_type",
                mock.MagicMock(return_value=False))
    def test_create_cloned_volume_calls_vol_create_and_copy(self):
        """test create_cloned_volume

        check if calls the appropriate xiv_backend functions
        are being called
        """
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        vol_src = testutils.create_volume(self.ctxt, display_name='bla',
                                          size=17,
                                          volume_type_id=self.vt['id'])
        vol_trg = testutils.create_volume(self.ctxt, display_name='bla',
                                          size=17,
                                          volume_type_id=self.vt['id'])

        p.ibm_storage_cli = mock.MagicMock()
        p._cg_name_from_volume = mock.MagicMock(return_value="cg")

        p.create_cloned_volume(vol_trg, vol_src)
        p._create_volume = test_mock.MagicMock()

        p.ibm_storage_cli.cmd.vol_create.assert_called_once_with(
            pool='WTF32',
            size_blocks=storage.gigabytes_to_blocks(17),
            vol=vol_trg['name'])

        p.ibm_storage_cli.cmd.vol_copy.assert_called_once_with(
            vol_src=vol_src['name'],
            vol_trg=vol_trg['name'])

    @mock.patch("cinder.volume.volume_utils.group_get_by_id", mock.MagicMock())
    @mock.patch("cinder.volume.volume_utils.is_group_a_cg_snapshot_type",
                mock.MagicMock(return_value=False))
    def test_handle_created_vol_properties_returns_vol_update(self):
        """test handle_created_vol_props

        returns replication enables if replication info is True
        """
        driver = mock.MagicMock()
        driver.VERSION = "VERSION"

        p = self.proxy(
            self.default_storage_info,
            mock.MagicMock(),
            test_mock.cinder.exception,
            driver)

        xiv_replication.VolumeReplication = mock.MagicMock()
        grp = testutils.create_group(self.ctxt, name='bla', group_type_id='1')
        volume = testutils.create_volume(self.ctxt, display_name='bla',
                                         volume_type_id=self.vt['id'])
        volume.group = grp
        ret_val = p.handle_created_vol_properties({'enabled': True}, volume)

        self.assertEqual(ret_val, {'replication_status': 'enabled'})
