# Copyright 2014 Violin Memory, Inc.
# 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 Violin Memory 6000 Series All-Flash Array iSCSI driver
"""

import mock
from oslo.utils import units

from cinder import context
from cinder.db.sqlalchemy import models
from cinder import exception
from cinder import test
from cinder.tests import fake_vmem_xgtools_client as vxg
from cinder.volume import configuration as conf
from cinder.volume.drivers.violin import v6000_common
from cinder.volume.drivers.violin import v6000_iscsi

VOLUME_ID = "abcdabcd-1234-abcd-1234-abcdeffedcba"
VOLUME = {
    "name": "volume-" + VOLUME_ID,
    "id": VOLUME_ID,
    "display_name": "fake_volume",
    "size": 2,
    "host": "irrelevant",
    "volume_type": None,
    "volume_type_id": None,
}
SNAPSHOT_ID = "abcdabcd-1234-abcd-1234-abcdeffedcbb"
SNAPSHOT = {
    "name": "snapshot-" + SNAPSHOT_ID,
    "id": SNAPSHOT_ID,
    "volume_id": VOLUME_ID,
    "volume_name": "volume-" + VOLUME_ID,
    "volume_size": 2,
    "display_name": "fake_snapshot",
    "volume": VOLUME,
}
SRC_VOL_ID = "abcdabcd-1234-abcd-1234-abcdeffedcbc"
SRC_VOL = {
    "name": "volume-" + SRC_VOL_ID,
    "id": SRC_VOL_ID,
    "display_name": "fake_src_vol",
    "size": 2,
    "host": "irrelevant",
    "volume_type": None,
    "volume_type_id": None,
}
INITIATOR_IQN = "iqn.1111-22.org.debian:11:222"
CONNECTOR = {
    "initiator": INITIATOR_IQN,
    "host": "irrelevant"
}


class V6000ISCSIDriverTestCase(test.TestCase):
    """Test cases for VMEM iSCSI driver."""
    def setUp(self):
        super(V6000ISCSIDriverTestCase, self).setUp()
        self.conf = self.setup_configuration()
        self.driver = v6000_iscsi.V6000ISCSIDriver(configuration=self.conf)
        self.driver.common.container = 'myContainer'
        self.driver.device_id = 'ata-VIOLIN_MEMORY_ARRAY_23109R00000022'
        self.driver.gateway_iscsi_ip_addresses_mga = '1.2.3.4'
        self.driver.gateway_iscsi_ip_addresses_mgb = '1.2.3.4'
        self.driver.array_info = [{"node": 'hostname_mga',
                                   "addr": '1.2.3.4',
                                   "conn": self.driver.common.mga},
                                  {"node": 'hostname_mgb',
                                   "addr": '1.2.3.4',
                                   "conn": self.driver.common.mgb}]
        self.stats = {}
        self.driver.set_initialized()

    def tearDown(self):
        super(V6000ISCSIDriverTestCase, self).tearDown()

    def setup_configuration(self):
        config = mock.Mock(spec=conf.Configuration)
        config.volume_backend_name = 'v6000_iscsi'
        config.san_ip = '1.1.1.1'
        config.san_login = 'admin'
        config.san_password = ''
        config.san_thin_provision = False
        config.san_is_local = False
        config.gateway_mga = '2.2.2.2'
        config.gateway_mgb = '3.3.3.3'
        config.use_igroups = False
        config.request_timeout = 300
        config.container = 'myContainer'
        config.iscsi_port = 3260
        config.iscsi_target_prefix = 'iqn.2004-02.com.vmem:'
        return config

    def setup_mock_vshare(self, m_conf=None):
        """Create a fake VShare communication object."""
        _m_vshare = mock.Mock(name='VShare',
                              version='1.1.1',
                              spec=vxg.mock_client_conf)

        if m_conf:
            _m_vshare.configure_mock(**m_conf)

        return _m_vshare

    @mock.patch.object(v6000_common.V6000Common, 'check_for_setup_error')
    def test_check_for_setup_error(self, m_setup_func):
        bn = "/vshare/config/iscsi/enable"
        response = {bn: True}

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        result = self.driver.check_for_setup_error()

        m_setup_func.assert_called_with()
        self.driver.common.vip.basic.get_node_values.assert_called_with(bn)
        self.assertTrue(result is None)

    @mock.patch.object(v6000_common.V6000Common, 'check_for_setup_error')
    def test_check_for_setup_error_iscsi_is_disabled(self, m_setup_func):
        bn = "/vshare/config/iscsi/enable"
        response = {bn: False}

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        self.assertRaises(exception.ViolinInvalidBackendConfig,
                          self.driver.check_for_setup_error)

    @mock.patch.object(v6000_common.V6000Common, 'check_for_setup_error')
    def test_check_for_setup_error_no_iscsi_ips_for_mga(self, m_setup_func):
        bn = "/vshare/config/iscsi/enable"
        response = {bn: True}
        self.driver.gateway_iscsi_ip_addresses_mga = ''

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        self.assertRaises(exception.ViolinInvalidBackendConfig,
                          self.driver.check_for_setup_error)

    @mock.patch.object(v6000_common.V6000Common, 'check_for_setup_error')
    def test_check_for_setup_error_no_iscsi_ips_for_mgb(self, m_setup_func):
        bn = "/vshare/config/iscsi/enable"
        response = {bn: True}
        self.driver.gateway_iscsi_ip_addresses_mgb = ''

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        self.assertRaises(exception.ViolinInvalidBackendConfig,
                          self.driver.check_for_setup_error)

    def test_create_volume(self):
        """Volume created successfully."""
        self.driver.common._create_lun = mock.Mock()

        result = self.driver.create_volume(VOLUME)

        self.driver.common._create_lun.assert_called_with(VOLUME)
        self.assertTrue(result is None)

    def test_delete_volume(self):
        """Volume deleted successfully."""
        self.driver.common._delete_lun = mock.Mock()

        result = self.driver.delete_volume(VOLUME)

        self.driver.common._delete_lun.assert_called_with(VOLUME)
        self.assertTrue(result is None)

    def test_create_snapshot(self):
        """Snapshot created successfully."""
        self.driver.common._create_lun_snapshot = mock.Mock()

        result = self.driver.create_snapshot(SNAPSHOT)

        self.driver.common._create_lun_snapshot.assert_called_with(SNAPSHOT)
        self.assertTrue(result is None)

    def test_delete_snapshot(self):
        """Snapshot deleted successfully."""
        self.driver.common._delete_lun_snapshot = mock.Mock()

        result = self.driver.delete_snapshot(SNAPSHOT)

        self.driver.common._delete_lun_snapshot.assert_called_with(SNAPSHOT)
        self.assertTrue(result is None)

    @mock.patch.object(context, 'get_admin_context')
    def test_create_volume_from_snapshot(self, m_context_func):
        """Volume created from a snapshot successfully."""
        m_context_func.return_value = None
        self.driver.common._create_lun = mock.Mock()
        self.driver.copy_volume_data = mock.Mock()

        result = self.driver.create_volume_from_snapshot(VOLUME, SNAPSHOT)

        m_context_func.assert_called_with()
        self.driver.common._create_lun.assert_called_with(VOLUME)
        self.driver.copy_volume_data.assert_called_with(None, SNAPSHOT, VOLUME)
        self.assertTrue(result is None)

    @mock.patch.object(context, 'get_admin_context')
    def test_create_cloned_volume(self, m_context_func):
        """Volume clone created successfully."""
        m_context_func.return_value = None
        self.driver.common._create_lun = mock.Mock()
        self.driver.copy_volume_data = mock.Mock()

        result = self.driver.create_cloned_volume(VOLUME, SRC_VOL)

        m_context_func.assert_called_with()
        self.driver.common._create_lun.assert_called_with(VOLUME)
        self.driver.copy_volume_data.assert_called_with(None, SRC_VOL, VOLUME)
        self.assertTrue(result is None)

    def test_initialize_connection(self):
        lun_id = 1
        igroup = None
        tgt = self.driver.array_info[0]
        iqn = "%s%s:%s" % (self.conf.iscsi_target_prefix,
                           tgt['node'], VOLUME['id'])
        volume = mock.MagicMock(spec=models.Volume)

        def getitem(name):
            return VOLUME[name]

        volume.__getitem__.side_effect = getitem

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
        self.driver._create_iscsi_target = mock.Mock(return_value=tgt)
        self.driver._export_lun = mock.Mock(return_value=lun_id)

        props = self.driver.initialize_connection(volume, CONNECTOR)

        self.driver._get_short_name.assert_called_with(volume['id'])
        self.driver._create_iscsi_target.assert_called_with(volume)
        self.driver._export_lun.assert_called_with(volume, CONNECTOR, igroup)
        self.driver.common.vip.basic.save_config.assert_called_with()
        self.assertEqual("1.2.3.4:3260", props['data']['target_portal'])
        self.assertEqual(iqn, props['data']['target_iqn'])
        self.assertEqual(lun_id, props['data']['target_lun'])
        self.assertEqual(volume['id'], props['data']['volume_id'])

    def test_initialize_connection_with_snapshot_object(self):
        lun_id = 1
        igroup = None
        tgt = self.driver.array_info[0]
        iqn = "%s%s:%s" % (self.conf.iscsi_target_prefix,
                           tgt['node'], SNAPSHOT['id'])
        snapshot = mock.MagicMock(spec=models.Snapshot)

        def getitem(name):
            return SNAPSHOT[name]

        snapshot.__getitem__.side_effect = getitem

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver._get_short_name = mock.Mock(return_value=SNAPSHOT['id'])
        self.driver._create_iscsi_target = mock.Mock(return_value=tgt)
        self.driver._export_snapshot = mock.Mock(return_value=lun_id)

        props = self.driver.initialize_connection(snapshot, CONNECTOR)

        self.driver._get_short_name.assert_called_with(SNAPSHOT['id'])
        self.driver._create_iscsi_target.assert_called_with(snapshot)
        self.driver._export_snapshot.assert_called_with(snapshot, CONNECTOR,
                                                        igroup)
        self.driver.common.vip.basic.save_config.assert_called_with()
        self.assertEqual("1.2.3.4:3260", props['data']['target_portal'])
        self.assertEqual(iqn, props['data']['target_iqn'])
        self.assertEqual(lun_id, props['data']['target_lun'])
        self.assertEqual(SNAPSHOT['id'], props['data']['volume_id'])

    def test_initialize_connection_with_igroups_enabled(self):
        self.conf.use_igroups = True
        lun_id = 1
        igroup = 'test-igroup-1'
        tgt = self.driver.array_info[0]
        iqn = "%s%s:%s" % (self.conf.iscsi_target_prefix,
                           tgt['node'], VOLUME['id'])
        volume = mock.MagicMock(spec=models.Volume)

        def getitem(name):
            return VOLUME[name]

        volume.__getitem__.side_effect = getitem

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver.common._get_igroup = mock.Mock(return_value=igroup)
        self.driver._add_igroup_member = mock.Mock()
        self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
        self.driver._create_iscsi_target = mock.Mock(return_value=tgt)
        self.driver._export_lun = mock.Mock(return_value=lun_id)

        props = self.driver.initialize_connection(volume, CONNECTOR)

        self.driver.common._get_igroup.assert_called_with(volume, CONNECTOR)
        self.driver._add_igroup_member.assert_called_with(CONNECTOR, igroup)
        self.driver._get_short_name.assert_called_with(volume['id'])
        self.driver._create_iscsi_target.assert_called_with(volume)
        self.driver._export_lun.assert_called_with(volume, CONNECTOR, igroup)
        self.driver.common.vip.basic.save_config.assert_called_with()
        self.assertEqual("1.2.3.4:3260", props['data']['target_portal'])
        self.assertEqual(iqn, props['data']['target_iqn'])
        self.assertEqual(lun_id, props['data']['target_lun'])
        self.assertEqual(volume['id'], props['data']['volume_id'])

    def test_terminate_connection(self):
        volume = mock.MagicMock(spec=models.Volume)

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver._unexport_lun = mock.Mock()
        self.driver._delete_iscsi_target = mock.Mock()

        result = self.driver.terminate_connection(volume, CONNECTOR)

        self.driver._unexport_lun.assert_called_with(volume)
        self.driver._delete_iscsi_target.assert_called_with(volume)
        self.driver.common.vip.basic.save_config.assert_called_with()
        self.assertTrue(result is None)

    def test_terminate_connection_with_snapshot_object(self):
        snapshot = mock.MagicMock(spec=models.Snapshot)

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver._unexport_snapshot = mock.Mock()
        self.driver._delete_iscsi_target = mock.Mock()

        result = self.driver.terminate_connection(snapshot, CONNECTOR)

        self.driver._unexport_snapshot.assert_called_with(snapshot)
        self.driver._delete_iscsi_target.assert_called_with(snapshot)
        self.driver.common.vip.basic.save_config.assert_called_with()
        self.assertTrue(result is None)

    def test_get_volume_stats(self):
        self.driver._update_stats = mock.Mock()
        self.driver._update_stats()

        result = self.driver.get_volume_stats(True)

        self.driver._update_stats.assert_called_with()
        self.assertEqual(self.driver.stats, result)

    def test_create_iscsi_target(self):
        target_name = VOLUME['id']
        response = {'code': 0, 'message': 'success'}

        m_vshare = self.setup_mock_vshare()

        self.driver.common.vip = m_vshare
        self.driver.common.mga = m_vshare
        self.driver.common.mgb = m_vshare
        self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
        self.driver.common._send_cmd_and_verify = mock.Mock(
            return_value=response)
        self.driver.common._send_cmd = mock.Mock(return_value=response)

        calls = [mock.call(self.driver.common.mga.iscsi.bind_ip_to_target, '',
                           VOLUME['id'],
                           self.driver.gateway_iscsi_ip_addresses_mga),
                 mock.call(self.driver.common.mgb.iscsi.bind_ip_to_target, '',
                           VOLUME['id'],
                           self.driver.gateway_iscsi_ip_addresses_mgb)]

        result = self.driver._create_iscsi_target(VOLUME)

        self.driver._get_short_name.assert_called_with(VOLUME['id'])
        self.driver.common._send_cmd_and_verify.assert_called_with(
            self.driver.common.vip.iscsi.create_iscsi_target,
            self.driver._wait_for_targetstate, '',
            [target_name], [target_name])
        self.driver.common._send_cmd.assert_has_calls(calls)
        self.assertTrue(result in self.driver.array_info)

    def test_delete_iscsi_target(self):
        response = {'code': 0, 'message': 'success'}

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
        self.driver.common._send_cmd = mock.Mock(return_value=response)

        result = self.driver._delete_iscsi_target(VOLUME)

        self.driver._get_short_name.assert_called_with(VOLUME['id'])
        self.driver.common._send_cmd(
            self.driver.common.vip.iscsi.delete_iscsi_target,
            '', VOLUME['id'])
        self.assertTrue(result is None)

    def test_delete_iscsi_target_fails_with_exception(self):
        response = {'code': 14000, 'message': 'Generic error'}
        failure = exception.ViolinBackendErr

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
        self.driver.common._send_cmd = mock.Mock(
            side_effect=failure(response['message']))

        self.assertRaises(failure, self.driver._delete_iscsi_target, VOLUME)

    def test_export_lun(self):
        igroup = 'test-igroup-1'
        lun_id = '1'
        response = {'code': 0, 'message': ''}

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
        self.driver.common._send_cmd_and_verify = mock.Mock(
            return_value=response)
        self.driver.common._get_lun_id = mock.Mock(return_value=lun_id)

        result = self.driver._export_lun(VOLUME, CONNECTOR, igroup)

        self.driver._get_short_name.assert_called_with(VOLUME['id'])
        self.driver.common._send_cmd_and_verify.assert_called_with(
            self.driver.common.vip.lun.export_lun,
            self.driver.common._wait_for_export_config, '',
            [self.driver.common.container, VOLUME['id'], VOLUME['id'],
             igroup, 'auto'], [VOLUME['id'], 'state=True'])
        self.driver.common._get_lun_id.assert_called_with(VOLUME['id'])
        self.assertEqual(lun_id, result)

    def test_export_lun_fails_with_exception(self):
        igroup = 'test-igroup-1'
        lun_id = '1'
        response = {'code': 14000, 'message': 'Generic error'}
        failure = exception.ViolinBackendErr

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
        self.driver.common._send_cmd_and_verify = mock.Mock(
            side_effect=failure(response['message']))
        self.driver._get_lun_id = mock.Mock(return_value=lun_id)

        self.assertRaises(failure, self.driver._export_lun,
                          VOLUME, CONNECTOR, igroup)

    def test_unexport_lun(self):
        response = {'code': 0, 'message': ''}

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver.common._send_cmd_and_verify = mock.Mock(
            return_value=response)

        result = self.driver._unexport_lun(VOLUME)

        self.driver.common._send_cmd_and_verify.assert_called_with(
            self.driver.common.vip.lun.unexport_lun,
            self.driver.common._wait_for_export_config, '',
            [self.driver.common.container, VOLUME['id'], 'all', 'all', 'auto'],
            [VOLUME['id'], 'state=False'])
        self.assertTrue(result is None)

    def test_unexport_lun_fails_with_exception(self):
        response = {'code': 14000, 'message': 'Generic error'}
        failure = exception.ViolinBackendErr

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver.common._send_cmd_and_verify = mock.Mock(
            side_effect=failure(response['message']))

        self.assertRaises(failure, self.driver._unexport_lun, VOLUME)

    def test_export_snapshot(self):
        lun_id = '1'
        igroup = 'test-igroup-1'
        response = {'code': 0, 'message': ''}

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver._get_short_name = mock.Mock(return_value=SNAPSHOT['id'])
        self.driver.common._send_cmd = mock.Mock(return_value=response)
        self.driver.common._wait_for_export_config = mock.Mock()
        self.driver.common._get_snapshot_id = mock.Mock(return_value=lun_id)

        result = self.driver._export_snapshot(SNAPSHOT, CONNECTOR, igroup)

        self.driver._get_short_name.assert_called_with(SNAPSHOT['id'])
        self.driver.common._send_cmd.assert_called_with(
            self.driver.common.vip.snapshot.export_lun_snapshot, '',
            self.driver.common.container, SNAPSHOT['volume_id'],
            SNAPSHOT['id'], igroup, SNAPSHOT['id'], 'auto')
        self.driver.common._wait_for_export_config.assert_called_with(
            SNAPSHOT['volume_id'], SNAPSHOT['id'], state=True)
        self.driver.common._get_snapshot_id.assert_called_once_with(
            SNAPSHOT['volume_id'], SNAPSHOT['id'])

        self.assertEqual(lun_id, result)

    def test_unexport_snapshot(self):
        response = {'code': 0, 'message': ''}

        self.driver.common.vip = self.setup_mock_vshare()
        self.driver.common._send_cmd = mock.Mock(return_value=response)
        self.driver.common._wait_for_export_config = mock.Mock()

        result = self.driver._unexport_snapshot(SNAPSHOT)

        self.driver.common._send_cmd.assert_called_with(
            self.driver.common.vip.snapshot.unexport_lun_snapshot, '',
            self.driver.common.container, SNAPSHOT['volume_id'],
            SNAPSHOT['id'], 'all', 'all', 'auto', False)
        self.driver.common._wait_for_export_config.assert_called_with(
            SNAPSHOT['volume_id'], SNAPSHOT['id'], state=False)
        self.assertTrue(result is None)

    def test_add_igroup_member(self):
        igroup = 'test-group-1'
        response = {'code': 0, 'message': 'success'}

        conf = {
            'igroup.add_initiators.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        result = self.driver._add_igroup_member(CONNECTOR, igroup)

        self.driver.common.vip.igroup.add_initiators.assert_called_with(
            igroup, CONNECTOR['initiator'])
        self.assertTrue(result is None)

    def test_update_stats(self):
        backend_name = self.conf.volume_backend_name
        vendor_name = "Violin Memory, Inc."
        tot_bytes = 100 * units.Gi
        free_bytes = 50 * units.Gi
        bn0 = '/cluster/state/master_id'
        bn1 = "/vshare/state/global/1/container/myContainer/total_bytes"
        bn2 = "/vshare/state/global/1/container/myContainer/free_bytes"
        response1 = {bn0: '1'}
        response2 = {bn1: tot_bytes, bn2: free_bytes}

        conf = {
            'basic.get_node_values.side_effect': [response1, response2],
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        result = self.driver._update_stats()

        calls = [mock.call(bn0), mock.call([bn1, bn2])]
        self.driver.common.vip.basic.get_node_values.assert_has_calls(calls)
        self.assertEqual(100, self.driver.stats['total_capacity_gb'])
        self.assertEqual(50, self.driver.stats['free_capacity_gb'])
        self.assertEqual(backend_name,
                         self.driver.stats['volume_backend_name'])
        self.assertEqual(vendor_name, self.driver.stats['vendor_name'])
        self.assertTrue(result is None)

    def test_update_stats_fails_data_query(self):
        backend_name = self.conf.volume_backend_name
        vendor_name = "Violin Memory, Inc."
        bn0 = '/cluster/state/master_id'
        response1 = {bn0: '1'}
        response2 = {}

        conf = {
            'basic.get_node_values.side_effect': [response1, response2],
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        self.assertTrue(self.driver._update_stats() is None)
        self.assertEqual(0, self.driver.stats['total_capacity_gb'])
        self.assertEqual(0, self.driver.stats['free_capacity_gb'])
        self.assertEqual(backend_name,
                         self.driver.stats['volume_backend_name'])
        self.assertEqual(vendor_name, self.driver.stats['vendor_name'])

    def testGetShortName_LongName(self):
        long_name = "abcdefghijklmnopqrstuvwxyz1234567890"
        short_name = "abcdefghijklmnopqrstuvwxyz123456"
        self.assertEqual(short_name, self.driver._get_short_name(long_name))

    def testGetShortName_ShortName(self):
        long_name = "abcdef"
        short_name = "abcdef"
        self.assertEqual(short_name, self.driver._get_short_name(long_name))

    def testGetShortName_EmptyName(self):
        long_name = ""
        short_name = ""
        self.assertEqual(short_name, self.driver._get_short_name(long_name))

    def test_get_active_iscsi_ips(self):
        bn0 = "/net/interface/config/*"
        bn1 = ["/net/interface/state/eth4/addr/ipv4/1/ip",
               "/net/interface/state/eth4/flags/link_up"]
        response1 = {"/net/interface/config/eth4": "eth4"}
        response2 = {"/net/interface/state/eth4/addr/ipv4/1/ip": "1.1.1.1",
                     "/net/interface/state/eth4/flags/link_up": True}

        conf = {
            'basic.get_node_values.side_effect': [response1, response2],
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        results = self.driver._get_active_iscsi_ips(self.driver.common.vip)

        calls = [mock.call(bn0), mock.call(bn1)]
        self.driver.common.vip.basic.get_node_values.assert_has_calls(calls)
        self.assertEqual(1, len(results))
        self.assertEqual("1.1.1.1", results[0])

    def test_get_active_iscsi_ips_with_invalid_interfaces(self):
        response = {"/net/interface/config/lo": "lo",
                    "/net/interface/config/vlan10": "vlan10",
                    "/net/interface/config/eth1": "eth1",
                    "/net/interface/config/eth2": "eth2",
                    "/net/interface/config/eth3": "eth3"}

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        result = self.driver._get_active_iscsi_ips(self.driver.common.vip)

        self.assertEqual(0, len(result))

    def test_get_active_iscsi_ips_with_no_interfaces(self):
        response = {}

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        result = self.driver._get_active_iscsi_ips(self.driver.common.vip)

        self.assertEqual(0, len(result))

    def test_get_hostname(self):
        bn = '/system/hostname'
        response = {bn: 'MYHOST'}

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        result = self.driver._get_hostname()

        self.driver.common.vip.basic.get_node_values.assert_called_with(bn)
        self.assertEqual("MYHOST", result)

    def test_get_hostname_mga(self):
        bn = '/system/hostname'
        response = {bn: 'MYHOST'}

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)
        self.driver.common.mga = self.setup_mock_vshare(m_conf=conf)
        self.assertEqual("MYHOST", self.driver._get_hostname('mga'))

    def test_get_hostname_mgb(self):
        response = {"/system/hostname": "MYHOST"}
        bn = '/system/hostname'
        response = {bn: 'MYHOST'}

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)
        self.driver.common.mgb = self.setup_mock_vshare(m_conf=conf)
        self.assertEqual("MYHOST", self.driver._get_hostname('mgb'))

    def test_get_hostname_query_fails(self):
        response = {}

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.vip = self.setup_mock_vshare(m_conf=conf)

        self.assertEqual(self.conf.san_ip, self.driver._get_hostname())

    def test_wait_for_targetstate(self):
        target = 'mytarget'
        bn = "/vshare/config/iscsi/target/%s" % target
        response = {bn: target}

        conf = {
            'basic.get_node_values.return_value': response,
        }
        self.driver.common.mga = self.setup_mock_vshare(m_conf=conf)
        self.driver.common.mgb = self.setup_mock_vshare(m_conf=conf)

        result = self.driver._wait_for_targetstate(target)

        self.driver.common.mga.basic.get_node_values.assert_called_with(bn)
        self.driver.common.mgb.basic.get_node_values.assert_called_with(bn)
        self.assertTrue(result)
