#  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.
#
from unittest import mock
from xml.etree import ElementTree

from cinder import context
from cinder import exception
from cinder import objects
from cinder.objects import fields
from cinder.tests.unit import fake_constants as fake
from cinder.tests.unit import test
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)
        self.assertCountEqual(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)
        self.assertCountEqual(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)
        self.assertCountEqual(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))
        self.assertCountEqual(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)

        self.mock_object(xiv_replication, 'VolumeReplication')
        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'})
