text: # Copyright (c) 2014 Alex Meade.  All rights reserved.
  # Copyright (c) 2014 Clinton Knight.  All rights reserved.
  # Copyright (c) 2014 Andrew Kerr.  All rights reserved.
  # 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.
  """
  Mock unit tests for the NetApp block storage library
  """
  
  
  import uuid
  
  import mock
  
  from cinder import exception
  from cinder import test
  from cinder.tests.volume.drivers.netapp.dataontap import fakes as fake
  from cinder.volume.drivers.netapp.dataontap import block_base
  from cinder.volume.drivers.netapp.dataontap.client import api as netapp_api
  from cinder.volume.drivers.netapp import utils as na_utils
  
  
  class NetAppBlockStorageLibraryTestCase(test.TestCase):
  
      def setUp(self):
          super(NetAppBlockStorageLibraryTestCase, self).setUp()
  
          kwargs = {'configuration': mock.Mock()}
          self.library = block_base.NetAppBlockStorageLibrary(
              'driver', 'protocol', **kwargs)
          self.library.zapi_client = mock.Mock()
          self.zapi_client = self.library.zapi_client
          self.mock_request = mock.Mock()
  
      def tearDown(self):
          super(NetAppBlockStorageLibraryTestCase, self).tearDown()
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_lun_attr',
                         mock.Mock(return_value={'Volume': 'vol1'}))
      def test_get_pool(self):
          pool = self.library.get_pool({'name': 'volume-fake-uuid'})
          self.assertEqual(pool, 'vol1')
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_lun_attr',
                         mock.Mock(return_value=None))
      def test_get_pool_no_metadata(self):
          pool = self.library.get_pool({'name': 'volume-fake-uuid'})
          self.assertEqual(pool, None)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_lun_attr',
                         mock.Mock(return_value=dict()))
      def test_get_pool_volume_unknown(self):
          pool = self.library.get_pool({'name': 'volume-fake-uuid'})
          self.assertEqual(pool, None)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_create_lun', mock.Mock())
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_create_lun_handle', mock.Mock())
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_add_lun_to_table', mock.Mock())
      @mock.patch.object(na_utils, 'get_volume_extra_specs',
                         mock.Mock(return_value=None))
      @mock.patch.object(block_base, 'LOG', mock.Mock())
      def test_create_volume(self):
          self.library.zapi_client.get_lun_by_args.return_value = ['lun']
          self.library.create_volume({'name': 'lun1', 'size': 100,
                                      'id': uuid.uuid4(),
                                      'host': 'hostname@backend#vol1'})
          self.library._create_lun.assert_called_once_with(
              'vol1', 'lun1', 107374182400, mock.ANY, None)
          self.assertEqual(0, block_base.LOG.warning.call_count)
  
      def test_create_volume_no_pool_provided_by_scheduler(self):
          self.assertRaises(exception.InvalidHost, self.library.create_volume,
                            {'name': 'lun1', 'size': 100,
                             'id': uuid.uuid4(),
                             'host': 'hostname@backend'})  # missing pool
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_lun_attr')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_or_create_igroup')
      def test_map_lun(self, mock_get_or_create_igroup, mock_get_lun_attr):
          os = 'linux'
          protocol = 'fcp'
          mock_get_lun_attr.return_value = {'Path': fake.LUN1, 'OsType': os}
          mock_get_or_create_igroup.return_value = fake.IGROUP1_NAME
          self.zapi_client.map_lun.return_value = '1'
  
          lun_id = self.library._map_lun('fake_volume',
                                         fake.FC_FORMATTED_INITIATORS,
                                         protocol, None)
  
          self.assertEqual(lun_id, '1')
          mock_get_or_create_igroup.assert_called_once_with(
              fake.FC_FORMATTED_INITIATORS, protocol, os)
          self.zapi_client.map_lun.assert_called_once_with(
              fake.LUN1, fake.IGROUP1_NAME, lun_id=None)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_lun_attr')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_or_create_igroup')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_find_mapped_lun_igroup')
      def test_map_lun_preexisting(self, mock_find_mapped_lun_igroup,
                                   mock_get_or_create_igroup, mock_get_lun_attr):
          os = 'linux'
          protocol = 'fcp'
          mock_get_lun_attr.return_value = {'Path': fake.LUN1, 'OsType': os}
          mock_get_or_create_igroup.return_value = fake.IGROUP1_NAME
          mock_find_mapped_lun_igroup.return_value = (fake.IGROUP1_NAME, '2')
          self.zapi_client.map_lun.side_effect = netapp_api.NaApiError
  
          lun_id = self.library._map_lun(
              'fake_volume', fake.FC_FORMATTED_INITIATORS, protocol, None)
  
          self.assertEqual(lun_id, '2')
          mock_find_mapped_lun_igroup.assert_called_once_with(
              fake.LUN1, fake.FC_FORMATTED_INITIATORS)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_lun_attr')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_or_create_igroup')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_find_mapped_lun_igroup')
      def test_map_lun_api_error(self, mock_find_mapped_lun_igroup,
                                 mock_get_or_create_igroup, mock_get_lun_attr):
          os = 'linux'
          protocol = 'fcp'
          mock_get_lun_attr.return_value = {'Path': fake.LUN1, 'OsType': os}
          mock_get_or_create_igroup.return_value = fake.IGROUP1_NAME
          mock_find_mapped_lun_igroup.return_value = (None, None)
          self.zapi_client.map_lun.side_effect = netapp_api.NaApiError
  
          self.assertRaises(netapp_api.NaApiError, self.library._map_lun,
                            'fake_volume', fake.FC_FORMATTED_INITIATORS,
                            protocol, None)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_find_mapped_lun_igroup')
      def test_unmap_lun(self, mock_find_mapped_lun_igroup):
          mock_find_mapped_lun_igroup.return_value = (fake.IGROUP1_NAME, 1)
  
          self.library._unmap_lun(fake.LUN1, fake.FC_FORMATTED_INITIATORS)
  
          self.zapi_client.unmap_lun.assert_called_once_with(fake.LUN1,
                                                             fake.IGROUP1_NAME)
  
      def test_find_mapped_lun_igroup(self):
          self.assertRaises(NotImplementedError,
                            self.library._find_mapped_lun_igroup,
                            fake.LUN1,
                            fake.FC_FORMATTED_INITIATORS)
  
      def test_has_luns_mapped_to_initiators(self):
          self.zapi_client.has_luns_mapped_to_initiators.return_value = True
          self.assertTrue(self.library._has_luns_mapped_to_initiators(
              fake.FC_FORMATTED_INITIATORS))
          self.zapi_client.has_luns_mapped_to_initiators.assert_called_once_with(
              fake.FC_FORMATTED_INITIATORS)
  
      def test_get_or_create_igroup_preexisting(self):
          self.zapi_client.get_igroup_by_initiators.return_value = [fake.IGROUP1]
  
          igroup_name = self.library._get_or_create_igroup(
              fake.FC_FORMATTED_INITIATORS, 'fcp', 'linux')
  
          self.assertEqual(igroup_name, fake.IGROUP1_NAME)
          self.zapi_client.get_igroup_by_initiators.assert_called_once_with(
              fake.FC_FORMATTED_INITIATORS)
  
      @mock.patch.object(uuid, 'uuid4', mock.Mock(return_value=fake.UUID1))
      def test_get_or_create_igroup_none_preexisting(self):
          self.zapi_client.get_igroup_by_initiators.return_value = []
  
          igroup_name = self.library._get_or_create_igroup(
              fake.FC_FORMATTED_INITIATORS, 'fcp', 'linux')
  
          self.assertEqual(igroup_name, 'openstack-' + fake.UUID1)
          self.zapi_client.create_igroup.assert_called_once_with(
              igroup_name, 'fcp', 'linux')
          self.assertEqual(len(fake.FC_FORMATTED_INITIATORS),
                           self.zapi_client.add_igroup_initiator.call_count)
  
      def test_get_fc_target_wwpns(self):
          self.assertRaises(NotImplementedError,
                            self.library._get_fc_target_wwpns)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_build_initiator_target_map')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_map_lun')
      def test_initialize_connection_fc(self, mock_map_lun,
                                        mock_build_initiator_target_map):
          self.maxDiff = None
          mock_map_lun.return_value = '1'
          mock_build_initiator_target_map.return_value = (fake.FC_TARGET_WWPNS,
                                                          fake.FC_I_T_MAP, 4)
  
          target_info = self.library.initialize_connection_fc(fake.FC_VOLUME,
                                                              fake.FC_CONNECTOR)
  
          self.assertDictEqual(target_info, fake.FC_TARGET_INFO)
          mock_map_lun.assert_called_once_with(
              'fake_volume', fake.FC_FORMATTED_INITIATORS, 'fcp', None)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_build_initiator_target_map')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_map_lun')
      def test_initialize_connection_fc_no_wwpns(
              self, mock_map_lun, mock_build_initiator_target_map):
  
          mock_map_lun.return_value = '1'
          mock_build_initiator_target_map.return_value = (None, None, 0)
          self.assertRaises(exception.VolumeBackendAPIException,
                            self.library.initialize_connection_fc,
                            fake.FC_VOLUME,
                            fake.FC_CONNECTOR)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_has_luns_mapped_to_initiators')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_unmap_lun')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_lun_attr')
      def test_terminate_connection_fc(self, mock_get_lun_attr, mock_unmap_lun,
                                       mock_has_luns_mapped_to_initiators):
  
          mock_get_lun_attr.return_value = {'Path': fake.LUN1}
          mock_unmap_lun.return_value = None
          mock_has_luns_mapped_to_initiators.return_value = True
  
          target_info = self.library.terminate_connection_fc(fake.FC_VOLUME,
                                                             fake.FC_CONNECTOR)
  
          self.assertDictEqual(target_info, fake.FC_TARGET_INFO_EMPTY)
          mock_unmap_lun.assert_called_once_with(fake.LUN1,
                                                 fake.FC_FORMATTED_INITIATORS)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_build_initiator_target_map')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_has_luns_mapped_to_initiators')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_unmap_lun')
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_lun_attr')
      def test_terminate_connection_fc_no_more_luns(
              self, mock_get_lun_attr, mock_unmap_lun,
              mock_has_luns_mapped_to_initiators,
              mock_build_initiator_target_map):
  
          mock_get_lun_attr.return_value = {'Path': fake.LUN1}
          mock_unmap_lun.return_value = None
          mock_has_luns_mapped_to_initiators.return_value = False
          mock_build_initiator_target_map.return_value = (fake.FC_TARGET_WWPNS,
                                                          fake.FC_I_T_MAP, 4)
  
          target_info = self.library.terminate_connection_fc(fake.FC_VOLUME,
                                                             fake.FC_CONNECTOR)
  
          self.assertDictEqual(target_info, fake.FC_TARGET_INFO_UNMAP)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_fc_target_wwpns')
      def test_build_initiator_target_map_no_lookup_service(
              self, mock_get_fc_target_wwpns):
  
          self.library.lookup_service = None
          mock_get_fc_target_wwpns.return_value = fake.FC_FORMATTED_TARGET_WWPNS
  
          (target_wwpns, init_targ_map, num_paths) = \
              self.library._build_initiator_target_map(fake.FC_CONNECTOR)
  
          self.assertSetEqual(set(fake.FC_TARGET_WWPNS), set(target_wwpns))
          self.assertDictEqual(fake.FC_I_T_MAP_COMPLETE, init_targ_map)
          self.assertEqual(0, num_paths)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_fc_target_wwpns')
      def test_build_initiator_target_map_with_lookup_service(
              self, mock_get_fc_target_wwpns):
  
          self.library.lookup_service = mock.Mock()
          self.library.lookup_service.get_device_mapping_from_network.\
              return_value = fake.FC_FABRIC_MAP
          mock_get_fc_target_wwpns.return_value = fake.FC_FORMATTED_TARGET_WWPNS
  
          (target_wwpns, init_targ_map, num_paths) = \
              self.library._build_initiator_target_map(fake.FC_CONNECTOR)
  
          self.assertSetEqual(set(fake.FC_TARGET_WWPNS), set(target_wwpns))
          self.assertDictEqual(fake.FC_I_T_MAP, init_targ_map)
          self.assertEqual(4, num_paths)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_create_lun', mock.Mock())
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_create_lun_handle', mock.Mock())
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_add_lun_to_table', mock.Mock())
      @mock.patch.object(na_utils, 'LOG', mock.Mock())
      @mock.patch.object(na_utils, 'get_volume_extra_specs',
                         mock.Mock(return_value={'netapp:raid_type': 'raid4'}))
      def test_create_volume_obsolete_extra_spec(self):
          self.library.zapi_client.get_lun_by_args.return_value = ['lun']
  
          self.library.create_volume({'name': 'lun1', 'size': 100,
                                      'id': uuid.uuid4(),
                                      'host': 'hostname@backend#vol1'})
  
          warn_msg = 'Extra spec netapp:raid_type is obsolete.  ' \
                     'Use netapp_raid_type instead.'
          na_utils.LOG.warning.assert_called_once_with(warn_msg)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_create_lun', mock.Mock())
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_create_lun_handle', mock.Mock())
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_add_lun_to_table', mock.Mock())
      @mock.patch.object(na_utils, 'LOG', mock.Mock())
      @mock.patch.object(na_utils, 'get_volume_extra_specs',
                         mock.Mock(return_value={'netapp_thick_provisioned':
                                                 'true'}))
      def test_create_volume_deprecated_extra_spec(self):
          self.library.zapi_client.get_lun_by_args.return_value = ['lun']
  
          self.library.create_volume({'name': 'lun1', 'size': 100,
                                      'id': uuid.uuid4(),
                                      'host': 'hostname@backend#vol1'})
  
          warn_msg = 'Extra spec netapp_thick_provisioned is deprecated.  ' \
                     'Use netapp_thin_provisioned instead.'
          na_utils.LOG.warning.assert_called_once_with(warn_msg)
  
      @mock.patch.object(na_utils, 'check_flags')
      def test_do_setup(self, mock_check_flags):
          self.library.do_setup(mock.Mock())
  
          self.assertTrue(mock_check_flags.called)
  
      def test_get_existing_vol_manage_missing_id_path(self):
          self.assertRaises(exception.ManageExistingInvalidReference,
                            self.library._get_existing_vol_with_manage_ref,
                            {})
  
      def test_get_existing_vol_manage_not_found(self):
          self.zapi_client.get_lun_by_args.return_value = []
          self.assertRaises(exception.ManageExistingInvalidReference,
                            self.library._get_existing_vol_with_manage_ref,
                            {'source-id': 'src_id',
                             'source-name': 'lun_path'})
          self.assertEqual(1, self.zapi_client.get_lun_by_args.call_count)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_extract_lun_info',
                         mock.Mock(return_value=block_base.NetAppLun(
                                   'lun0', 'lun0', '3', {'UUID': 'src_id'})))
      def test_get_existing_vol_manage_lun(self):
          self.zapi_client.get_lun_by_args.return_value = ['lun0', 'lun1']
          lun = self.library._get_existing_vol_with_manage_ref(
              {'source-id': 'src_id', 'path': 'lun_path'})
          self.assertEqual(1, self.zapi_client.get_lun_by_args.call_count)
          self.library._extract_lun_info.assert_called_once_with('lun0')
          self.assertEqual('lun0', lun.name)
  
      @mock.patch.object(block_base.NetAppBlockStorageLibrary,
                         '_get_existing_vol_with_manage_ref',
                         mock.Mock(return_value=block_base.NetAppLun(
                                   'handle', 'name', '1073742824', {})))
      def test_manage_existing_get_size(self):
          size = self.library.manage_existing_get_size(
              {'id': 'vol_id'}, {'ref': 'ref'})
          self.assertEqual(2, size)
          self.library._get_existing_vol_with_manage_ref.assert_called_once_with(
              {'ref': 'ref'})
  
      @mock.patch.object(block_base.LOG, 'info')
      def test_unmanage(self, log):
          mock_lun = block_base.NetAppLun('handle', 'name', '1',
                                          {'Path': 'p', 'UUID': 'uuid'})
          self.library._get_lun_from_table = mock.Mock(return_value=mock_lun)
          self.library.unmanage({'name': 'vol'})
          self.library._get_lun_from_table.assert_called_once_with('vol')
          self.assertEqual(1, log.call_count)
  
      def test_manage_existing_lun_same_name(self):
          mock_lun = block_base.NetAppLun('handle', 'name', '1',
                                          {'Path': '/vol/vol1/name'})
          self.library._get_existing_vol_with_manage_ref = mock.Mock(
              return_value=mock_lun)
          self.library._check_volume_type_for_lun = mock.Mock()
          self.library._add_lun_to_table = mock.Mock()
          self.zapi_client.move_lun = mock.Mock()
          self.library.manage_existing({'name': 'name'}, {'ref': 'ref'})
          self.library._get_existing_vol_with_manage_ref.assert_called_once_with(
              {'ref': 'ref'})
          self.assertEqual(1, self.library._check_volume_type_for_lun.call_count)
          self.assertEqual(1, self.library._add_lun_to_table.call_count)
          self.assertEqual(0, self.zapi_client.move_lun.call_count)
  
      def test_manage_existing_lun_new_path(self):
          mock_lun = block_base.NetAppLun(
              'handle', 'name', '1', {'Path': '/vol/vol1/name'})
          self.library._get_existing_vol_with_manage_ref = mock.Mock(
              return_value=mock_lun)
          self.library._check_volume_type_for_lun = mock.Mock()
          self.library._add_lun_to_table = mock.Mock()
          self.zapi_client.move_lun = mock.Mock()
          self.library.manage_existing({'name': 'volume'}, {'ref': 'ref'})
          self.assertEqual(
              2, self.library._get_existing_vol_with_manage_ref.call_count)
          self.assertEqual(1, self.library._check_volume_type_for_lun.call_count)
          self.assertEqual(1, self.library._add_lun_to_table.call_count)
          self.zapi_client.move_lun.assert_called_once_with(
              '/vol/vol1/name', '/vol/vol1/volume')
  
      def test_check_vol_type_for_lun(self):
          self.assertRaises(NotImplementedError,
                            self.library._check_volume_type_for_lun,
                            'vol', 'lun', 'existing_ref')
  
      def test_is_lun_valid_on_storage(self):
          self.assertTrue(self.library._is_lun_valid_on_storage('lun'))
  