# Copyright (c) 2019 MacroSAN Technologies Co., Ltd.
# 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.
"""Tests for macrosan drivers."""
from collections import UserDict
import os
import socket
from unittest import mock

from cinder import exception
from cinder.tests.unit import test
from cinder.volume import configuration as conf
from cinder.volume.drivers.macrosan import devop_client
from cinder.volume.drivers.macrosan import driver
from cinder.volume import qos_specs
from cinder.volume import volume_types
from cinder.volume import volume_utils


test_volume = (
    UserDict({'name': 'volume-728ec287-bf30-4d2d-98a8-7f1bed3f59ce',
              'volume_name': 'test',
              'id': '728ec287-bf30-4d2d-98a8-7f1bed3f59ce',
              'provider_auth': None,
              'project_id': 'project',
              'display_name': 'test',
              'display_description': 'test',
              'host': 'controller@macrosan#MacroSAN',
              'size': 10,
              'provider_location':
              'macrosan uuid:0x00b34201-025b0000-46b35ae7-b7deec47'}))

test_volume.size = 10
test_volume.volume_type_id = '36674caf-5314-468a-a8cb-baab4f71fe44'
test_volume.volume_attachment = []

test_migrate_volume = {
    'name': 'volume-d42b436a-54cc-480a-916c-275b0258ef59',
    'size': 10,
    'volume_name': 'test',
    'id': 'd42b436a-54cc-480a-916c-275b0258ef59',
    'volume_id': 'd42b436a-54cc-480a-916c-275b0258ef59',
    'provider_auth': None,
    'project_id': 'project',
    'display_name': 'test',
    'display_description': 'test',
    'volume_type_id': '36674caf-5314-468a-a8cb-baab4f71fe44',
    '_name_id': None,
    'host': 'controller@macrosan#MacroSAN',
    'provider_location':
    'macrosan uuid:0x00b34201-00180000-9ac35425-9e288d9a'}

test_snap = {'name': 'volume-728ec287-bf30-4d2d-98a8-7f1bed3f59ce',
             'size': 10,
             'volume_name': 'test',
             'id': 'aa2419a3-c144-46af-831b-e0d914d3957b',
             'volume_id': '728ec287-bf30-4d2d-98a8-7f1bed3f59ce',
             'provider_auth': None,
             'project_id': 'project',
             'display_name': 'test',
             'display_description': 'test volume',
             'volume_type_id': '36674caf-5314-468a-a8cb-baab4f71fe44',
             'provider_location': 'pointid: 1',
             'volume_size': 10,
             'volume': test_volume}

test_connector = {'initiator': 'iqn.1993-08.org.debian:01:62027e12fbc',
                  'wwpns': ['500b342001001805', '500b342001004605'],
                  'wwnns': ['21000024ff2003ec', '21000024ff2003ed'],
                  'host': 'controller'
                  }

fake_fabric_mapping = {
    'switch1': {
        'target_port_wwn_list': ['500b342001001805', '500b342001004605'],
        'initiator_port_wwn_list': ['21000024ff2003ec', '21000024ff2003ed']
    }
}

expected_iscsi_properties = {'target_discovered': False,
                             'target_portal': '192.168.251.1:3260',
                             'target_iqn':
                             'iqn.2010-05.com.macrosan.target:controller',
                             'target_lun': 0,
                             'target_iqns':
                             ['iqn.2010-05.com.macrosan.target:controller',
                              'iqn.2010-05.com.macrosan.target:controller'],
                             'target_portals':
                             ['192.168.251.1:3260', '192.168.251.2:3260'],
                             'target_luns': [0, 0],
                             'volume_id':
                             '728ec287-bf30-4d2d-98a8-7f1bed3f59ce'
                             }

expected_iscsi_connection_data = {
    'client': 'devstack',
    'ports': [{'ip': '192.168.251.1',
               'port': 'eth-1:0:0',
               'port_name': 'iSCSI-Target-1:0:0',
               'target': 'iqn.2010-05.com.macrosan.target:controller'},
              {'ip': '192.168.251.2',
               'port': 'eth-2:0:0',
               'port_name': 'iSCSI-Target-2:0:0',
               'target': 'iqn.2010-05.com.macrosan.target:controller'}]}

expected_initr_port_map_tgtexist = {
    '21:00:00:24:ff:20:03:ec': [{'port_name': 'FC-Target-1:1:1',
                                 'wwn': '50:0b:34:20:01:00:18:05'},
                                {'port_name': 'FC-Target-2:1:1',
                                 'wwn': '50:0b:34:20:01:00:46:05'}],
    '21:00:00:24:ff:20:03:ed': [{'port_name': 'FC-Target-1:1:1',
                                 'wwn': '50:0b:34:20:01:00:18:05'},
                                {'port_name': 'FC-Target-2:1:1',
                                 'wwn': '50:0b:34:20:01:00:46:05'}]}

expected_initr_port_map_tgtnotexist = {'21:00:00:24:ff:20:03:ec': [],
                                       '21:00:00:24:ff:20:03:ed': []}

expected_fctgtexist_properties = {'target_lun': 0,
                                  'target_discovered': True,
                                  'target_wwn':
                                  ['500b342001001805', '500b342001004605'],
                                  'volume_id':
                                  '728ec287-bf30-4d2d-98a8-7f1bed3f59ce'
                                  }


class FakeMacroSANFCDriver(driver.MacroSANFCDriver):
    """Fake MacroSAN Storage, Rewrite some methods of MacroSANFCDriver."""
    def do_setup(self):
        self.client = FakeClient(self.sp1_ipaddr, self.sp2_ipaddr,
                                 self.username + self.passwd)
        self.fcsan_lookup_service = FCSanLookupService()

    @property
    def _self_node_wwns(self):
        return ['21000024ff2003ec', '21000024ff2003ed']

    def _snapshot_name(self, snapshotid):
        return "aa2419a3c14446af831be0d914d3957"

    def _get_client_name(self, host):
        return 'devstack'


class FCSanLookupService(object):
    def get_device_mapping_from_network(self, initiator_list,
                                        target_list):
        return fake_fabric_mapping


class DummyBrickGetConnector(object):
    def connect_volume(self, fake_con_data):
        return {'path': '/dev/mapper/3600b3429d72e349d93bad6597d0000df'}

    def disconnect_volume(self, fake_con_data, fake_device):
        return None


class FakeMacroSANISCSIDriver(driver.MacroSANISCSIDriver):
    """Fake MacroSAN Storage, Rewrite some methods of MacroSANISCSIDriver."""
    def do_setup(self):
        self.client = FakeClient(self.sp1_ipaddr, self.sp2_ipaddr,
                                 self.username + self.passwd)
        self.device_uuid = '0x00b34201-028100eb-4922a092-1d54b755'

    @property
    def _self_node_wwns(self):
        return ["iqn.1993-08.org.debian:01:62027e12fbc"]

    def _snapshot_name(self, snapshotid):
        return "aa2419a3c14446af831be0d914d3957"

    def _get_iscsi_ports(self, dev_client, host):
        if self.client.cmd_fail:
            raise exception.VolumeBackendAPIException(data='Command failed.')
        else:
            return [{'ip': '192.168.251.1', 'port_name': 'iSCSI-Target-1:0:0',
                     'port': 'eth-1:0:0',
                     'target': 'iqn.2010-05.com.macrosan.target:controller'},
                    {'ip': '192.168.251.2', 'port_name': 'iSCSI-Target-2:0:0',
                     'port': 'eth-2:0:0',
                     'target': 'iqn.2010-05.com.macrosan.target:controller'}]

    def _get_client_name(self, host):
        return 'devstack'

    def _attach_volume(self, context, volume, properties, remote=False):
        return super(FakeMacroSANISCSIDriver, self)._attach_volume(
            context, volume, properties, remote)

    def _detach_volume(self, context, attach_info, volume,
                       properties, force=False, remote=False,
                       ignore_errors=True):
        return super(FakeMacroSANISCSIDriver, self)._detach_volume(
            context, attach_info, volume, properties, force, remote,
            ignore_errors)


class FakeClient(devop_client.Client):
    def __init__(self, sp1_ip, sp2_ip, secret_key):
        self.cmd_fail = False
        self.tgt_notexist = False

    def get_raid_list(self, pool):
        return [{'name': 'RAID-1', 'free_cap': 1749}]

    def get_client(self, name):
        return True

    def create_lun(self, name, owner, pool, raids, lun_mode, size, lun_params):
        return True

    def get_pool_cap(self, pool):
        return 1862, 1749, 0

    def delete_lun(self, name):
        return True

    def setup_snapshot_resource(self, name, res_size, raids):
        pass

    def snapshot_resource_exists(self, name):
        return True

    def create_snapshot_point(self, lun_name, snapshot_name):
        if self.cmd_fail:
            raise exception.VolumeBackendAPIException(data='Command failed')
        else:
            return True

    def disable_snapshot(self, volume_name):
        if self.cmd_fail:
            raise exception.VolumeBackendAPIException(data='Command failed')
        else:
            return True

    def delete_snapshot_resource(self, volume_name):
        if self.cmd_fail:
            raise exception.VolumeBackendAPIException(data='Command failed')
        else:
            return True

    def snapshot_point_exists(self, lun_name, pointid):
        return True

    def lun_exists(self, name):
        return True

    def snapshot_enabled(self, lun_name):
        return True

    def create_snapshot_view(self, view_name, lun_name, pointid):
        if self.cmd_fail:
            raise exception.VolumeBackendAPIException(data='Command failed')
        else:
            return True

    def get_snapshot_pointid(self, lun_name, snapshot_name):
        if self.cmd_fail:
            raise exception.VolumeBackendAPIException(data='Command failed')
        else:
            return 1

    def delete_snapshot_view(self, view_name):
        return True

    def delete_snapshot_point(self, lun_name, pointid):
        return True

    def copy_volume_from_view(self, lun_name, view_name):
        return True

    def snapshot_copy_task_completed(self, lun_name):
        return True

    def extend_lun(self, name, raids, size):
        return True

    def initiator_exists(self, initr_wwn):
        return True

    def get_device_uuid(self):
        return '0x00b34201-025b0000-46b35ae7-b7deec47'

    def is_initiator_mapped_to_client(self, initr_wwn, client_name):
        return True

    def unmap_lun_to_it(self, lun_name, initr_wwn, tgt_port_name):
        if self.cmd_fail:
            raise exception.VolumeBackendAPIException('Command failed.')
        else:
            return None

    def map_lun_to_it(self, lun_name, initr_wwn, tgt_port_name, lun_id=-1):
        if self.cmd_fail:
            raise exception.VolumeBackendAPIException('Command failed.')
        else:
            return None

    def map_target_to_initiator(self, tgt_port_name, initr_wwn):
        return True

    def get_it_unused_id_list(self, it_type, initr_wwn, tgt_port_name):
        if self.cmd_fail:
            raise exception.VolumeBackendAPIException('Command failed.')
        else:
            return [i for i in range(511)]

    def enable_lun_qos(self, name, strategy):
        if self.cmd_fail:
            raise Exception()
        else:
            return None

    def get_fc_initr_mapped_ports(self, initr_wwns):
        return {'21:00:00:24:ff:20:03:ec':
                [{'wwn': '50:0b:34:20:01:00:18:05',
                  'port_name': 'FC-Target-1:1:1'},
                 {'wwn': '50:0b:34:20:01:00:46:05',
                  'port_name': 'FC-Target-2:1:1'}],
                '21:00:00:24:ff:20:03:ed':
                [{'wwn': '50:0b:34:20:01:00:18:05',
                  'port_name': 'FC-Target-1:1:1'},
                 {'wwn': '50:0b:34:20:01:00:46:05',
                  'port_name': 'FC-Target-2:1:1'}]
                }

    def get_fc_ports(self):
        if self.tgt_notexist:
            return [{'sp': 1, 'refcnt': 0,
                     'port_name': 'FC-Target-1:1:1',
                     'initr': '', 'online': 0,
                     'wwn': '50:0b:34:20:01:00:18:05',
                     'port': 'FC-1:1:1'},
                    {'sp': 2, 'refcnt': 0,
                     'port_name': 'FC-Target-2:1:1',
                     'initr': '', 'online': 0,
                     'wwn': '50:0b:34:20:01:00:46:05',
                     'port': 'FC-2:1:1'},
                    ]
        else:
            return [{'sp': 1, 'refcnt': 0,
                     'port_name': 'FC-Target-1:1:1',
                     'initr': '', 'online': 1,
                     'wwn': '50:0b:34:20:01:00:18:05',
                     'port': 'FC-1:1:1'},
                    {'sp': 2, 'refcnt': 0,
                     'port_name': 'FC-Target-2:1:1',
                     'initr': '', 'online': 1,
                     'wwn': '50:0b:34:20:01:00:46:05',
                     'port': 'FC-2:1:1'},
                    ]

    def get_lun_uuid(self, lun_name):
        return '0x00b34201-025b0000-46b35ae7-b7deec47'

    def get_lun_name(self, lun_uuid):
        if lun_uuid == "0x00b34201-025b0000-46b35ae7-b7deec47":
            return '728ec287-bf30-4d2d-98a8-7f1bed3f59ce'
        if lun_uuid == "0x00b34201-00180000-9ac35425-9e288d9a":
            return 'd42b436a-54cc-480a-916c-275b0258ef59'

    def get_lun_name_from_rename_file(self, name):
        return None

    def backup_lun_name_to_rename_file(self, cur_name, original_name):
        return None

    def get_lun_id(self, tgt_name, lun_name, type='FC'):
        return 0

    def get_view_lun_id(self, tgt_name, view_name, type='FC'):
        return 0


class MacroSANISCSIDriverTestCase(test.TestCase):
    def setUp(self):
        super(MacroSANISCSIDriverTestCase, self).setUp()
        self.configuration = mock.Mock(spec=conf.Configuration)
        self.configuration.san_ip = "172.192.251.1, 172.192.251.2"
        self.configuration.san_login = "openstack"
        self.configuration.san_password = "passwd"
        self.configuration.macrosan_sdas_ipaddrs = None
        self.configuration.macrosan_replication_ipaddrs = None
        self.configuration.san_thin_provision = False
        self.configuration.macrosan_pool = 'Pool-1'
        self.configuration.macrosan_thin_lun_extent_size = 8
        self.configuration.macrosan_thin_lun_low_watermark = 8
        self.configuration.macrosan_thin_lun_high_watermark = 40
        self.configuration.macrosan_force_unmap_itl = False
        self.configuration.macrosan_snapshot_resource_ratio = 0.3
        self.configuration.macrosan_log_timing = True
        self.configuration.macrosan_client = \
            ['devstack; device1; "eth-1:0:0"; "eth-2:0:0"']
        self.configuration.macrosan_client_default = "eth-1:0:0;eth-2:0:0"
        self.driver = FakeMacroSANISCSIDriver(configuration=self.configuration)
        self.driver.do_setup()

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_create_volume(self, mock_volume_type, mock_qos):
        ret = self.driver.create_volume(test_volume)
        actual = ret['provider_location']
        self.assertEqual(test_volume['provider_location'], actual)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_create_qos_volume(self, mock_volume_type, mock_qos):
        test_volume.volume_type_id = 'a2ed23e0-76c4-426f-a574-a1327275e725'
        ret = self.driver.create_volume(test_volume)
        actual = ret['provider_location']
        self.assertEqual(test_volume['provider_location'], actual)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_delete_volume(self, mock_volume_type, mock_qos):
        self.driver.delete_volume(test_volume)

    def test_create_snapshot(self):
        self.driver.client.snappoid = True
        ret = self.driver.create_snapshot(test_snap)
        actual = ret['provider_location']
        self.assertEqual(test_snap['provider_location'], actual)

    def test_delete_snapshot(self):
        self.driver.delete_snapshot(test_snap)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    @mock.patch.object(socket, 'gethostname', return_value='controller')
    @mock.patch.object(volume_utils, 'brick_get_connector',
                       return_value=DummyBrickGetConnector())
    @mock.patch.object(volume_utils, 'copy_volume', return_value=None)
    @mock.patch.object(os.path, 'realpath', return_value=None)
    def test_create_volume_from_snapshot(self, mock_volume_type, mock_qos,
                                         mock_hostname,
                                         mock_brick_get_connector,
                                         mock_copy_volume,
                                         mock_os_path):
        ret = self.driver.create_volume_from_snapshot(test_volume, test_snap)
        actual = ret['provider_location']
        self.assertEqual(test_volume['provider_location'], actual)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    @mock.patch.object(socket, 'gethostname', return_value='controller')
    @mock.patch.object(volume_utils, 'brick_get_connector',
                       return_value=DummyBrickGetConnector())
    @mock.patch.object(volume_utils, 'copy_volume', return_value=None)
    @mock.patch.object(os.path, 'realpath', return_value=None)
    def test_create_cloned_volume(self, mock_volume_types, mock_qos,
                                  mock_hostname,
                                  mock_brick_get_connector,
                                  mock_copy_volume,
                                  mock_os_path):
        self.driver.client.snappoid = True
        ret = self.driver.create_cloned_volume(test_volume, test_volume)
        actual = ret['provider_location']
        self.assertEqual(test_volume['provider_location'], actual)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_extend_volume(self, mock_volume_type, mock_qos):
        self.driver.extend_volume(test_volume, 15)

    def test_update_migrated_volume(self):
        expected = {'_name_id':
                    test_migrate_volume['id'],
                    'provider_location':
                    test_migrate_volume['provider_location']}
        ret = self.driver.update_migrated_volume("", test_volume,
                                                 test_migrate_volume)
        self.assertEqual(expected, ret)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_initialize_connection(self, mock_volume_type, mock_qos):
        ret = self.driver.initialize_connection(test_volume, test_connector)
        self.assertEqual(expected_iscsi_properties, ret['data'])

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_terminate_connection(self, mock_volume_type, mock_qos):
        ret = self.driver.terminate_connection(test_volume, test_connector)
        self.assertEqual({'driver_volume_type': 'iSCSI',
                          'data': expected_iscsi_connection_data}, ret)

    def test_get_raid_list(self):
        expected = ["RAID-1"]
        ret = self.driver.get_raid_list(20)
        self.assertEqual(expected, ret)

    def test_get_volume_stats(self):
        ret = self.driver.get_volume_stats(True)
        expected = "iSCSI"
        self.assertEqual(expected, ret['storage_protocol'])

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_create_qos_volume_fail(self, mock_volume_type, mock_qos):
        test_volume.volume_type_id = 'a2ed23e0-76c4-426f-a574-a1327275e725'
        self.driver.client.cmd_fail = True
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume, test_volume)

    def test_create_snapshot_fail(self):
        self.driver.client.cmd_fail = True
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_snapshot, test_snap)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    @mock.patch.object(socket, 'gethostname', return_value='controller')
    @mock.patch.object(volume_utils, 'brick_get_connector',
                       return_value=DummyBrickGetConnector())
    @mock.patch.object(volume_utils, 'copy_volume', return_value=None)
    @mock.patch.object(os.path, 'realpath', return_value=None)
    def test_create_volume_from_snapshot_fail(self, mock_volume_type,
                                              mock_qos, mock_hostname,
                                              mock_brick_get_connector,
                                              mock_copy_volume,
                                              mock_os_path):
        self.driver.client.cmd_fail = True
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume_from_snapshot,
                          test_volume, test_snap)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    @mock.patch.object(socket, 'gethostname', return_value='controller')
    @mock.patch.object(volume_utils, 'brick_get_connector',
                       return_value=DummyBrickGetConnector())
    @mock.patch.object(volume_utils, 'copy_volume', return_value=None)
    @mock.patch.object(os.path, 'realpath', return_value=None)
    def test_create_cloned_volume_fail(self, mock_volume_types, mock_qos,
                                       mock_hostname,
                                       mock_brick_get_connector,
                                       mock_copy_volume,
                                       mock_os_path):
        self.driver.client.cmd_fail = True
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_cloned_volume,
                          test_volume, test_volume)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_initialize_connection_fail(self, mock_volume_type, mock_qos):
        self.driver.client.cmd_fail = True
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.initialize_connection,
                          test_volume, test_connector)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_terminate_connection_fail(self, mock_volume_type, mock_qos):
        self.driver.client.cmd_fail = True
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.terminate_connection,
                          test_volume, test_connector)

    def test_get_raid_list_fail(self):
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.get_raid_list, 2000)


class MacroSANFCDriverTestCase(test.TestCase):
    def setUp(self):
        super(MacroSANFCDriverTestCase, self).setUp()
        self.configuration = mock.Mock(spec=conf.Configuration)
        self.configuration.san_ip = \
            "172.192.251.1, 172.192.251.2"
        self.configuration.san_login = "openstack"
        self.configuration.san_password = "passwd"
        self.configuration.macrosan_sdas_ipaddrs = None
        self.configuration.macrosan_replication_ipaddrs = None
        self.configuration.san_thin_provision = False
        self.configuration.macrosan_pool = 'Pool-1'
        self.configuration.macrosan_thin_lun_extent_size = 8
        self.configuration.macrosan_thin_lun_low_watermark = 8
        self.configuration.macrosan_thin_lun_high_watermark = 40
        self.configuration.macrosan_force_unmap_itl = False
        self.configuration.macrosan_snapshot_resource_ratio = 0.3
        self.configuration.macrosan_log_timing = True
        self.configuration.macrosan_host_name = 'devstack'
        self.configuration.macrosan_fc_use_sp_port_nr = 1
        self.configuration.macrosan_fc_keep_mapped_ports = True
        self.configuration.macrosan_host_name = 'devstack'
        self.configuration.macrosan_client = \
            ['devstack; device1; "eth-1:0:0"; "eth-2:0:0"']
        self.configuration.macrosan_client_default = \
            "eth-1:0:0;eth-2:0:0"
        self.driver = FakeMacroSANFCDriver(configuration=self.configuration)
        self.driver.do_setup()

    def test_get_initr_port_map_tgtnotexist(self):
        self.driver.client.tgt_notexist = True
        ret = self.driver._get_initr_port_map(self.driver.client,
                                              test_connector['wwpns'])
        self.assertEqual(expected_initr_port_map_tgtnotexist, ret)

    def test_get_initr_port_map_tgtexist(self):
        ret = self.driver._get_initr_port_map(self.driver.client,
                                              test_connector['wwpns'])
        self.assertEqual(expected_initr_port_map_tgtexist, ret)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_initialize_connection(self, mock_volume_types, mock_qos):
        ret = self.driver.initialize_connection(test_volume, test_connector)
        self.assertEqual(expected_fctgtexist_properties, ret['data'])

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_terminate_connection(self, mock_volume_types, mock_qos):
        ret = self.driver.terminate_connection(test_volume, test_connector)
        self.assertEqual({'driver_volume_type': 'fibre_channel', 'data': {}},
                         ret)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    @mock.patch.object(socket, 'gethostname', return_value='controller')
    @mock.patch.object(volume_utils, 'brick_get_connector',
                       return_value=DummyBrickGetConnector())
    @mock.patch.object(volume_utils, 'copy_volume', return_value=None)
    @mock.patch.object(os.path, 'realpath', return_value=None)
    def test_create_volume_from_snapshot(self, mock_volume_types, mock_qos,
                                         mock_hostname,
                                         mock_brick_get_connector,
                                         mock_copy_volume,
                                         mock_os_path):
        ret = self.driver.create_volume_from_snapshot(test_volume, test_snap)
        actual = ret['provider_location']
        self.assertEqual(test_volume['provider_location'], actual)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={
                           'qos_specs_id':
                               '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                           'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    @mock.patch.object(socket, 'gethostname', return_value='controller')
    @mock.patch.object(volume_utils, 'brick_get_connector',
                       return_value=DummyBrickGetConnector())
    @mock.patch.object(volume_utils, 'copy_volume', return_value=None)
    @mock.patch.object(os.path, 'realpath', return_value=None)
    def test_create_cloned_volume(self, mock_volume_types, mock_qos,
                                  mock_hostname,
                                  mock_brick_get_connector,
                                  mock_copy_volume,
                                  mock_os_path):
        self.driver.client.snappoid = True
        ret = self.driver.create_cloned_volume(test_volume, test_volume)
        actual = ret['provider_location']
        self.assertEqual(test_volume['provider_location'], actual)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    @mock.patch.object(socket, 'gethostname', return_value='controller')
    @mock.patch.object(volume_utils, 'brick_get_connector',
                       return_value=DummyBrickGetConnector())
    @mock.patch.object(volume_utils, 'copy_volume', return_value=None)
    @mock.patch.object(os.path, 'realpath', return_value=None)
    def test_create_volume_from_snapshot_fail(self, mock_volume_types,
                                              mock_qos,
                                              mock_hostname,
                                              mock_brick_get_connector,
                                              mock_copy_volume,
                                              mock_os_path):
        self.driver.client.cmd_fail = True
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_volume_from_snapshot,
                          test_volume, test_snap)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    @mock.patch.object(socket, 'gethostname', return_value='controller')
    @mock.patch.object(volume_utils, 'brick_get_connector',
                       return_value=DummyBrickGetConnector())
    @mock.patch.object(volume_utils, 'copy_volume', return_value=None)
    @mock.patch.object(os.path, 'realpath', return_value=None)
    def test_create_cloned_volume_fail(self, mock_volume_types, mock_qos,
                                       mock_hostname,
                                       mock_brick_get_connector,
                                       mock_copy_volume,
                                       mock_os_path):
        self.driver.client.cmd_fail = True
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.create_cloned_volume,
                          test_volume, test_volume)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_initialize_connection_fail(self, mock_volume_types, mock_qos):
        self.driver.client.cmd_fail = True
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.initialize_connection,
                          test_volume, test_connector)

    @mock.patch.object(volume_types, 'get_volume_type',
                       return_value={'qos_specs_id':
                                     '99f3d240-1b20-4b7b-9321-c6b8b86243ff',
                                     'extra_specs': {}})
    @mock.patch.object(qos_specs, 'get_qos_specs',
                       return_value={'specs': {'qos-strategy': 'QoS-1'}})
    def test_terminate_connection_fail(self, mock_volume_types, mock_qos):
        self.driver.client.cmd_fail = True
        self.assertRaises(exception.VolumeBackendAPIException,
                          self.driver.terminate_connection,
                          test_volume, test_connector)
