def setUp(self): super(FIOioControlTestCases, self).setUp() self.configuration = create_configuration() self.ctxt = context.get_admin_context() self.drv = FIOioControlDriver(configuration=self.configuration) self.drv.fio_qos_dict = self.policyTable
class FIOioControlTestCases(test.TestCase): VERSION = '1.0.0' policyTable = {'Policy 4': '00000000-00000000-0000-000000000002', 'Policy 5': '00000000-00000000-0000-000000000000', 'Policy 2': '00000000-00000000-0000-000000000008', 'Policy 3': '00000000-00000000-0000-000000000004', 'Policy 1': '00000000-00000000-0000-000000000010'} def setUp(self): super(FIOioControlTestCases, self).setUp() self.configuration = create_configuration() self.ctxt = context.get_admin_context() self.drv = FIOioControlDriver(configuration=self.configuration) self.drv.fio_qos_dict = self.policyTable def test_do_setup_sucess(self, connmock): # erase policy table, then make sure drv.do_setup builds it self.drv.fio_qos_dict = {} instance = connmock.return_value instance.get.return_value = basic_policy_response self.drv.do_setup(context="") self.assertEqual(self.policyTable, self.drv.fio_qos_dict, "wrong policy table built") def test_create_volume_simple_success_poolA(self, connmock): self.drv.conn = connmock.return_value bPoolResponse = copy.deepcopy(basic_pools_response) bPoolResponse[1]['ExportedVolumeMB'] = 5009 self.drv.conn.get.return_value = bPoolResponse testvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID', 'volume_type_id': None, 'created_at': timeutils.utcnow()} self.drv.create_volume(testvol) cmd = {"Size": int(testvol['size']) * units.Gi, "PolicyUUID": '00000000-00000000-0000-000000000000', "PoolUUID": "FakePoolA_id", "Name": testvol['id'], } expected = [mock.call.get('TierStore/Pools/by-id/'), mock.call.post('TierStore/Volumes/by-id/', cmd)] self.drv.conn.assert_has_calls(expected) def test_create_volume_simple_success_poolB(self, connmock): self.drv.conn = connmock.return_value bPoolResponse = copy.deepcopy(basic_pools_response) bPoolResponse[0]['ExportedVolumeMB'] = 5009 self.drv.conn.get.return_value = bPoolResponse testvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID', 'volume_type_id': None, 'created_at': timeutils.utcnow()} self.drv.create_volume(testvol) cmd = {"Size": int(testvol['size']) * units.Gi, "PolicyUUID": '00000000-00000000-0000-000000000000', "PoolUUID": "FakePoolB_id", "Name": testvol['id'], } expected = [mock.call.get('TierStore/Pools/by-id/'), mock.call.post('TierStore/Volumes/by-id/', cmd)] self.drv.conn.assert_has_calls(expected) def test_delete_volume_sucess(self, connmock): self.drv.conn = connmock.return_value testvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID', 'volume_type_id': None, 'created_at': timeutils.utcnow()} self.drv.conn.get.return_value = basic_vol_response self.drv.delete_volume(testvol) expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.delete('TierStore/Volumes/by-id/FakeBasicVolID')] self.drv.conn.assert_has_calls(expected) def test_create_snapshot_sucess(self, connmock): self.drv.conn = connmock.return_value snapshot = {'volume_id': 'cinderVolumeID', 'id': 'a720b3c0-d1f0-11e1-9b23-1234500cab39', } self.drv.conn.get.return_value = basic_vol_response cmd = {"VolumeUUID": "FakeBasicVolID", "Name": snapshot['id'], } self.drv.create_snapshot(snapshot) expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.post('TierStore/Snapshots/by-id/', cmd), ] self.drv.conn.assert_has_calls(expected) def test_delete_snapshot_sucess(self, connmock): self.drv.conn = connmock.return_value snapshot = {'volume_id': '1dead3c0-d1f0-beef-9b23-1274500cab58', 'id': 'cinderSnapshotID'} self.drv.conn.get.return_value = basic_snapshot_response self.drv.delete_snapshot(snapshot) expected = [mock.call.get('TierStore/Snapshots/by-id/'), mock.call.delete( ('TierStore/Snapshots/by-id/' + '407115424bb9539c')), ] self.drv.conn.assert_has_calls(expected) def test_create_volume_from_snapshot_simple_sucess(self, connmock): self.drv.conn = connmock.return_value testvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID', 'volume_type_id': None, 'created_at': timeutils.utcnow()} snapshot = {'volume_id': testvol['id'], 'id': 'cinderSnapshotID'} self.drv.conn.get.return_value = basic_snapshot_response cmd = {"ParentLayerId": "407115424bb9539c", "Name": testvol['id'], "PolicyUUID": '00000000-00000000-0000-000000000000'} self.drv.create_volume_from_snapshot(testvol, snapshot) expected = [mock.call.get('TierStore/Snapshots/by-id/'), mock.call.put( 'TierStore/Snapshots/functions/CloneSnapshot', cmd), ] self.drv.conn.assert_has_calls(expected) def test_initialize_connection_no_usable_Networks_fail(self, connmock): self.drv.conn = connmock.return_value connector = {'initiator': 'fake:01'} testvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID', 'volume_type_id': None, 'created_at': timeutils.utcnow(), 'provider_auth': {}} cmd = {"GroupName": "fake:01", "InitiatorList": ["fake:01"]} cmd2 = {"AclGroupList": ["3"], } netResponse = copy.deepcopy(basic_net_response) netResponse[4]['OperationalState'] = "down" get_effect = [basic_vol_response, basic_acl_group_response, basic_vol_response, netResponse, ] self.drv.conn.get.side_effect = get_effect self.assertRaises(exception.VolumeDriverException, self.drv.initialize_connection, testvol, connector) expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.post('TierStore/ACLGroup/by-id/', cmd), mock.call.get('TierStore/ACLGroup/by-id/'), mock.call.put('TierStore/Volumes/by-id/FakeBasicVolID', cmd2), mock.call.get('TierStore/Volumes/by-id/'), mock.call.get('System/Network/by-id/'), ] self.drv.conn.assert_has_calls(expected) def test_initialize_connection_simple_sucess(self, connmock): self.drv.conn = connmock.return_value connector = {'initiator': 'fake:01'} testvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID', 'volume_type_id': None, 'created_at': timeutils.utcnow(), 'provider_auth': {}} cmd = {"GroupName": "fake:01", "InitiatorList": ["fake:01"]} cmd2 = {"AclGroupList": ["3"], } netResponse = copy.deepcopy(basic_net_response) netResponse[2]['OperationalState'] = "up" get_effect = [basic_vol_response, basic_acl_group_response, basic_vol_response, netResponse, ] self.drv.conn.get.side_effect = get_effect result = self.drv.initialize_connection(testvol, connector) expected = {'driver_volume_type': 'iscsi', 'data': {'target_lun': 0, 'target_portal': u'10.10.2.84:3260', 'target_iqn': ( 'iqn.2010-11.com.ngs:Volume:FakeBasicVolID'), 'target_discovered': False, 'volume_id': 'cinderVolumeID'}} self.assertEqual(result, expected, "wrong result from init connection") expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.post('TierStore/ACLGroup/by-id/', cmd), mock.call.get('TierStore/ACLGroup/by-id/'), mock.call.put('TierStore/Volumes/by-id/FakeBasicVolID', cmd2), mock.call.get('TierStore/Volumes/by-id/'), mock.call.get('System/Network/by-id/'), ] self.drv.conn.assert_has_calls(expected) def test_terminate_connection_single_delete_sucess(self, connmock): self.drv.conn = connmock.return_value connector = {'initiator': 'fake:01'} testvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID', 'volume_type_id': None, 'created_at': timeutils.utcnow(), 'provider_auth': {}} cmd = {"AclGroupList": ["1"], } get_effect = [basic_vol_response, basic_acl_group_response, basic_acl_group_response, basic_vol_response, ] self.drv.conn.get.side_effect = get_effect self.drv.terminate_connection(testvol, connector) expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.get('TierStore/ACLGroup/by-id/'), mock.call.put('TierStore/Volumes/by-id/FakeBasicVolID', cmd), mock.call.get('TierStore/ACLGroup/by-id/'), mock.call.get('TierStore/Volumes/by-id/'), mock.call.delete('TierStore/ACLGroup/by-id/3')] self.drv.conn.assert_has_calls(expected) def test_terminate_connection_multiple_no_delete(self, connmock): self.drv.conn = connmock.return_value connector = {'initiator': 'fake:01'} testvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID', 'volume_type_id': None, 'created_at': timeutils.utcnow(), 'provider_auth': {}} cmd = {"AclGroupList": ["1"], } return2vol = copy.deepcopy(basic_vol_response) return2vol.append(copy.deepcopy(basic_vol_response[0])) return2vol[1]['AclGroupList'] = ["3"] get_effect = [basic_vol_response, basic_acl_group_response, basic_acl_group_response, return2vol, ] self.drv.conn.get.side_effect = get_effect self.drv.terminate_connection(testvol, connector) expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.get('TierStore/ACLGroup/by-id/'), mock.call.put('TierStore/Volumes/by-id/FakeBasicVolID', cmd), mock.call.get('TierStore/ACLGroup/by-id/'), mock.call.get('TierStore/Volumes/by-id/')] self.drv.conn.assert_has_calls(expected) def test_terminate_connection_multiple_delete(self, connmock): self.drv.conn = connmock.return_value connector = {'initiator': 'fake:01'} testvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID', 'volume_type_id': None, 'created_at': timeutils.utcnow(), 'provider_auth': {}} cmd = {"AclGroupList": ["1"], } return2vol = copy.deepcopy(basic_vol_response) return2vol.append(copy.deepcopy(basic_vol_response[0])) get_effect = [basic_vol_response, basic_acl_group_response, basic_acl_group_response, return2vol, ] self.drv.conn.get.side_effect = get_effect self.drv.terminate_connection(testvol, connector) expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.get('TierStore/ACLGroup/by-id/'), mock.call.put('TierStore/Volumes/by-id/FakeBasicVolID', cmd), mock.call.get('TierStore/ACLGroup/by-id/'), mock.call.get('TierStore/Volumes/by-id/'), mock.call.delete('TierStore/ACLGroup/by-id/3')] self.drv.conn.assert_has_calls(expected) def test_create_cloned_volume_simple_sucess(self, connmock): self.drv.conn = connmock.return_value srcvol = {'id': 'cinderVolumeID'} dstvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID-dst', 'volume_type_id': None, 'created_at': timeutils.utcnow()} cmd = {'VolumeUUID': 'FakeBasicVolID', 'Name': 'mockedFakeUUID'} # also mock _getSnapshotByName because of the random snapshotname. self.drv._get_snapshot_by_name = mock.MagicMock() self.drv._get_snapshot_by_name.return_value = \ basic_snapshot_response[0] cmd2 = {"ParentLayerId": "407115424bb9539c", "Name": "cinderVolumeID-dst", "PolicyUUID": "00000000-00000000-0000-000000000000"} get_effect = [basic_vol_response, ] self.drv.conn.get.side_effect = get_effect with mock.patch('cinder.volume.drivers.fusionio.ioControl.uuid', autospec=True) as uuidmock: uuidmock.uuid4.return_value = cmd['Name'] self.drv.create_cloned_volume(dstvol, srcvol) expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.post('TierStore/Snapshots/by-id/', cmd), mock.call.put(('TierStore/Snapshots/functions/' + 'CloneSnapshot'), cmd2), ] self.drv.conn.assert_has_calls(expected) def test_create_cloned_volume_snapfails(self, connmock): self.drv.conn = connmock.return_value # this operation is a 2 part process, snap, then clone. # This tests for the snap failing srcvol = {'id': 'cinderVolumeID'} dstvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID-dst', 'volume_type_id': None, 'created_at': timeutils.utcnow()} cmd = {'VolumeUUID': 'FakeBasicVolID', 'Name': 'mockedFakeUUID'} get_effect = [basic_vol_response, ] self.drv.conn.get.side_effect = get_effect self.drv.conn.post.side_effect = requests.exceptions.HTTPError with mock.patch('cinder.volume.drivers.fusionio.ioControl.uuid', autospec=True) as uuidmock: uuidmock.uuid4.return_value = cmd['Name'] self.assertRaises(requests.exceptions.HTTPError, self.drv.create_cloned_volume, dstvol, srcvol) expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.post('TierStore/Snapshots/by-id/', cmd), ] self.drv.conn.assert_has_calls(expected) def test_create_cloned_volume_clonefails(self, connmock): self.drv.conn = connmock.return_value srcvol = {'id': 'cinderVolumeID'} dstvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID-dst', 'volume_type_id': None, 'created_at': timeutils.utcnow()} get_effect = [basic_vol_response, basic_snapshot_response[0], ] self.drv.conn.get.side_effect = get_effect # also mock _getSnapshotByName because of the random snapshotname. self.drv._get_snapshot_by_name = mock.MagicMock() self.drv._get_snapshot_by_name.return_value = \ basic_snapshot_response[0] cmd = {'VolumeUUID': 'FakeBasicVolID', 'Name': 'mockedFakeUUID'} cmd2 = {"ParentLayerId": "407115424bb9539c", "Name": "cinderVolumeID-dst", "PolicyUUID": "00000000-00000000-0000-000000000000"} self.drv.conn.put.side_effect = requests.exceptions.HTTPError with mock.patch('cinder.volume.drivers.fusionio.ioControl.uuid', autospec=True) as uuidmock: uuidmock.uuid4.return_value = cmd['Name'] self.assertRaises(requests.exceptions.HTTPError, self.drv.create_cloned_volume, dstvol, srcvol) expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.post('TierStore/Snapshots/by-id/', cmd), mock.call.put(('TierStore/Snapshots/functions/' + 'CloneSnapshot'), cmd2), mock.call.delete(('TierStore/Snapshots/by-id/' + cmd2['ParentLayerId'])), ] self.drv.conn.assert_has_calls(expected) def test_get_volume_stats_simple_sucess(self, connmock): self.drv.conn = connmock.return_value self.drv.conn.get.side_effect = [basic_pools_response, ] result = self.drv.get_volume_stats(refresh=True) self.assertEqual(basic_pools_response[0]['PagingTotalMB'] + basic_pools_response[1]['PagingTotalMB'], result['total_capacity_gb'], "capacity calc wrong") self.assertEqual(self.VERSION, result['driver_version'], "Driver/Test version Mismatch") def test_create_volume_QoS_by_presets(self, connmock): preset_qos = VolumeMetadata(key='fio-qos', value='Policy 2') testvol = {'project_id': 'testprjid', 'name': 'testvol', 'size': 1, 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66', 'volume_metadata': [preset_qos], 'volume_type_id': None, 'created_at': timeutils.utcnow()} expected_qos_result = '00000000-00000000-0000-000000000008' # Policy 2 qos = self.drv._set_qos_presets(testvol) self.assertEqual(qos, expected_qos_result) def test_create_volume_Qos_by_volumeType_QoSspec(self, connmock): qos_ref = qos_specs.create(self.ctxt, 'qos-specs-1', {'fio-qos': 'Policy 2'}) type_ref = volume_types.create(self.ctxt, "type1", {"volume_backend_name": "fio-ioControl", "qos:fio-qos": "Policy 4"} ) qos_specs.associate_qos_with_type(self.ctxt, qos_ref['id'], type_ref['id']) expected_qos_result = '00000000-00000000-0000-000000000008' # Policy 2 qos = self.drv._set_qos_by_volume_type(type_ref['id']) self.assertEqual(qos, expected_qos_result) def test_create_volume_Qos_by_volumeType_extraSpec(self, connmock): type_ref = volume_types.create(self.ctxt, "type1", {"volume_backend_name": "fio-ioControl", "qos:fio-qos": "Policy 4"} ) expected_qos_result = '00000000-00000000-0000-000000000002' # Policy 4 qos = self.drv._set_qos_by_volume_type(type_ref['id']) self.assertEqual(qos, expected_qos_result) def test_extend_volume_simple_success(self, connmock): self.drv.conn = connmock.return_value testvol = {'project_id': 'testproject', 'name': 'cinderVolumeName', 'size': 1, 'id': 'cinderVolumeID', 'volume_type_id': None, 'created_at': timeutils.utcnow()} new_size = 10 cmd = {"Size": int(new_size) * units.Gi} self.drv.conn.get.side_effect = [basic_vol_response, ] self.drv.extend_volume(testvol, new_size) expected = [mock.call.get('TierStore/Volumes/by-id/'), mock.call.put('TierStore/Volumes/by-id/FakeBasicVolID', cmd)] self.drv.conn.assert_has_calls(expected)