1# Copyright (c) 2017 Dell Inc. or its subsidiaries.
2# All Rights Reserved.
3#
4#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5#    not use this file except in compliance with the License. You may obtain
6#    a copy of the License at
7#
8#         http://www.apache.org/licenses/LICENSE-2.0
9#
10#    Unless required by applicable law or agreed to in writing, software
11#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13#    License for the specific language governing permissions and limitations
14#    under the License.
15
16import ast
17from copy import deepcopy
18import datetime
19import tempfile
20import time
21from xml.dom import minidom
22
23import mock
24import requests
25import six
26
27from cinder import context
28from cinder import exception
29from cinder import objects
30from cinder.objects import fields
31from cinder.objects import group
32from cinder.objects import group_snapshot
33from cinder.objects import volume_type
34from cinder import test
35from cinder.tests.unit import fake_group
36from cinder.tests.unit import fake_snapshot
37from cinder.tests.unit import fake_volume
38from cinder.tests.unit import utils as test_utils
39from cinder.volume.drivers.dell_emc.vmax import common
40from cinder.volume.drivers.dell_emc.vmax import fc
41from cinder.volume.drivers.dell_emc.vmax import iscsi
42from cinder.volume.drivers.dell_emc.vmax import masking
43from cinder.volume.drivers.dell_emc.vmax import provision
44from cinder.volume.drivers.dell_emc.vmax import rest
45from cinder.volume.drivers.dell_emc.vmax import utils
46from cinder.volume import utils as volume_utils
47from cinder.volume import volume_types
48from cinder.zonemanager import utils as fczm_utils
49
50CINDER_EMC_CONFIG_DIR = '/etc/cinder/'
51
52
53class VMAXCommonData(object):
54    # array info
55    array = '000197800123'
56    uni_array = u'000197800123'
57    array_herc = '000197900123'
58    srp = 'SRP_1'
59    srp2 = 'SRP_2'
60    slo = 'Diamond'
61    workload = 'DSS'
62    port_group_name_f = 'OS-fibre-PG'
63    port_group_name_i = 'OS-iscsi-PG'
64    masking_view_name_f = 'OS-HostX-F-OS-fibre-PG-MV'
65    masking_view_name_i = 'OS-HostX-SRP_1-I-OS-iscsi-PG-MV'
66    initiatorgroup_name_f = 'OS-HostX-F-IG'
67    initiatorgroup_name_i = 'OS-HostX-I-IG'
68    parent_sg_f = 'OS-HostX-F-OS-fibre-PG-SG'
69    parent_sg_i = 'OS-HostX-I-OS-iscsi-PG-SG'
70    storagegroup_name_f = 'OS-HostX-SRP_1-DiamondDSS-OS-fibre-PG'
71    storagegroup_name_i = 'OS-HostX-SRP_1-Diamond-DSS-OS-iscsi-PG'
72    defaultstoragegroup_name = 'OS-SRP_1-Diamond-DSS-SG'
73    storagegroup_list = [defaultstoragegroup_name]
74    default_sg_no_slo = 'OS-no_SLO-SG'
75    default_sg_compr_disabled = 'OS-SRP_1-Diamond-DSS-CD-SG'
76    default_sg_re_enabled = 'OS-SRP_1-Diamond-DSS-RE-SG'
77    failed_resource = 'OS-failed-resource'
78    fake_host = 'HostX@Backend#Diamond+DSS+SRP_1+000197800123'
79    new_host = 'HostX@Backend#Silver+OLTP+SRP_1+000197800123'
80    none_host = 'HostX@Backend#Diamond+None+SRP_1+000197800123'
81    version = '3.1.0'
82    volume_wwn = '600000345'
83    remote_array = '000197800124'
84    device_id = '00001'
85    device_id2 = '00002'
86    device_id3 = '00003'
87    rdf_group_name = '23_24_007'
88    rdf_group_no = '70'
89    u4v_version = '84'
90    storagegroup_name_source = 'Grp_source_sg'
91    storagegroup_name_target = 'Grp_target_sg'
92    group_snapshot_name = 'Grp_snapshot'
93    target_group_name = 'Grp_target'
94    storagegroup_name_with_id = 'GrpId_group_name'
95    rdf_managed_async_grp = "OS-%s-Asynchronous-rdf-sg" % rdf_group_name
96    volume_id = '2b06255d-f5f0-4520-a953-b029196add6a'
97
98    # connector info
99    wwpn1 = "123456789012345"
100    wwpn2 = "123456789054321"
101    wwnn1 = "223456789012345"
102    initiator = 'iqn.1993-08.org.debian: 01: 222'
103    ip, ip2 = u'123.456.7.8', u'123.456.7.9'
104    iqn = u'iqn.1992-04.com.emc:600009700bca30c01e3e012e00000001,t,0x0001'
105    iqn2 = u'iqn.1992-04.com.emc:600009700bca30c01e3e012e00000002,t,0x0001'
106    connector = {'ip': ip,
107                 'initiator': initiator,
108                 'wwpns': [wwpn1, wwpn2],
109                 'wwnns': [wwnn1],
110                 'host': 'HostX'}
111
112    fabric_name_prefix = "fakeFabric"
113    end_point_map = {connector['wwpns'][0]: [wwnn1],
114                     connector['wwpns'][1]: [wwnn1]}
115    target_wwns = [wwnn1]
116    zoning_mappings = {
117        'array': u'000197800123',
118        'init_targ_map': end_point_map,
119        'initiator_group': initiatorgroup_name_f,
120        'port_group': port_group_name_f,
121        'target_wwns': target_wwns}
122    zoning_mappings_metro = deepcopy(zoning_mappings)
123    zoning_mappings_metro.update({'metro_port_group': port_group_name_f,
124                                  'metro_ig': initiatorgroup_name_f,
125                                  'metro_array': remote_array})
126
127    device_map = {}
128    for wwn in connector['wwpns']:
129        fabric_name = ''.join([fabric_name_prefix,
130                              wwn[-2:]])
131        target_wwn = wwn[::-1]
132        fabric_map = {'initiator_port_wwn_list': [wwn],
133                      'target_port_wwn_list': [target_wwn]
134                      }
135        device_map[fabric_name] = fabric_map
136
137    iscsi_device_info = {'maskingview': masking_view_name_i,
138                         'ip_and_iqn': [{'ip': ip,
139                                         'iqn': initiator}],
140                         'is_multipath': True,
141                         'array': array,
142                         'controller': {'host': '10.00.00.00'},
143                         'hostlunid': 3}
144    iscsi_device_info_metro = deepcopy(iscsi_device_info)
145    iscsi_device_info_metro['metro_ip_and_iqn'] = [{'ip': ip2, 'iqn': iqn2}]
146    iscsi_device_info_metro['metro_hostlunid'] = 2
147
148    fc_device_info = {'maskingview': masking_view_name_f,
149                      'array': array,
150                      'controller': {'host': '10.00.00.00'},
151                      'hostlunid': 3}
152
153    # cinder volume info
154    ctx = context.RequestContext('admin', 'fake', True)
155    provider_location = {'array': six.text_type(array),
156                         'device_id': device_id}
157
158    provider_location2 = {'array': six.text_type(array),
159                          'device_id': device_id2}
160
161    provider_location3 = {'array': six.text_type(remote_array),
162                          'device_id': device_id2}
163
164    provider_location4 = {'array': six.text_type(uni_array),
165                          'device_id': device_id}
166
167    legacy_provider_location = {
168        'classname': 'Symm_StorageVolume',
169        'keybindings': {'CreationClassName': u'Symm_StorageVolume',
170                        'SystemName': u'SYMMETRIX+000197800123',
171                        'DeviceID': device_id,
172                        'SystemCreationClassName': u'Symm_StorageSystem'}}
173
174    legacy_provider_location2 = {
175        'classname': 'Symm_StorageVolume',
176        'keybindings': {'CreationClassName': u'Symm_StorageVolume',
177                        'SystemName': u'SYMMETRIX+000197800123',
178                        'DeviceID': device_id2,
179                        'SystemCreationClassName': u'Symm_StorageSystem'}}
180
181    test_volume_type = fake_volume.fake_volume_type_obj(
182        context=ctx
183    )
184
185    test_volume = fake_volume.fake_volume_obj(
186        context=ctx, name='vol1', size=2, provider_auth=None,
187        provider_location=six.text_type(provider_location),
188        volume_type=test_volume_type, host=fake_host,
189        replication_driver_data=six.text_type(provider_location3))
190
191    test_attached_volume = fake_volume.fake_volume_obj(
192        context=ctx, name='vol1', size=2, provider_auth=None,
193        provider_location=six.text_type(provider_location), host=fake_host,
194        volume_type=test_volume_type, attach_status="attached",
195        replication_driver_data=six.text_type(provider_location3))
196
197    test_legacy_vol = fake_volume.fake_volume_obj(
198        context=ctx, name='vol1', size=2, provider_auth=None,
199        provider_location=six.text_type(legacy_provider_location),
200        replication_driver_data=six.text_type(legacy_provider_location2),
201        host=fake_host, volume_type=test_volume_type)
202
203    snapshot_id = '390eeb4d-0f56-4a02-ba14-167167967014'
204
205    test_clone_volume = fake_volume.fake_volume_obj(
206        context=ctx, name='vol1', size=2, provider_auth=None,
207        provider_location=six.text_type(provider_location2),
208        host=fake_host, source_volid=test_volume.id,
209        snapshot_id=snapshot_id, _name_id=test_volume.id)
210
211    test_volume_snap_manage = fake_volume.fake_volume_obj(
212        context=ctx, name='vol1', size=2, provider_auth=None,
213        display_name='vol1',
214        provider_location=six.text_type(provider_location),
215        volume_type=test_volume_type, host=fake_host,
216        replication_driver_data=six.text_type(provider_location4))
217
218    snapshot_display_id = 'my_snap'
219    managed_snap_id = 'OS-390eeb4d-0f56-4a02-ba14-167167967014'
220    test_snapshot_snap_name = 'OS-' + snapshot_id[:6] + snapshot_id[-9:]
221
222    snap_location = {'snap_name': test_snapshot_snap_name,
223                     'source_id': device_id}
224
225    test_snapshot = fake_snapshot.fake_snapshot_obj(
226        context=ctx, id=snapshot_id,
227        name='my_snap', size=2,
228        provider_location=six.text_type(snap_location),
229        host=fake_host, volume=test_volume)
230
231    test_legacy_snapshot = fake_snapshot.fake_snapshot_obj(
232        context=ctx, id=test_volume.id, name='my_snap', size=2,
233        provider_location=six.text_type(legacy_provider_location),
234        host=fake_host, volume=test_volume)
235
236    test_failed_snap = fake_snapshot.fake_snapshot_obj(
237        context=ctx,
238        id='4732de9b-98a4-4b6d-ae4b-3cafb3d34220',
239        name=failed_resource,
240        size=2,
241        provider_location=six.text_type(snap_location),
242        host=fake_host, volume=test_volume)
243
244    test_snapshot_manage = fake_snapshot.fake_snapshot_obj(
245        context=ctx, id=snapshot_id,
246        name='my_snap', size=2,
247        provider_location=six.text_type(snap_location),
248        host=fake_host, volume=test_volume_snap_manage,
249        display_name='my_snap')
250
251    location_info = {'location_info': '000197800123#SRP_1#Diamond#DSS',
252                     'storage_protocol': 'FC'}
253    test_host = {'capabilities': location_info,
254                 'host': fake_host}
255
256    # extra-specs
257    vol_type_extra_specs = {'pool_name': u'Diamond+DSS+SRP_1+000197800123'}
258    vol_type_extra_specs_compr_disabled = {
259        'pool_name': u'Diamond+DSS+SRP_1+000197800123',
260        'storagetype:disablecompression': "true"}
261    vol_type_extra_specs_rep_enabled = {
262        'pool_name': u'Diamond+DSS+SRP_1+000197800123',
263        'replication_enabled': '<is> True'}
264    extra_specs = {'pool_name': u'Diamond+DSS+SRP_1+000197800123',
265                   'slo': slo,
266                   'workload': workload,
267                   'srp': srp,
268                   'array': array,
269                   'interval': 3,
270                   'retries': 120}
271    extra_specs_disable_compression = deepcopy(extra_specs)
272    extra_specs_disable_compression[utils.DISABLECOMPRESSION] = "true"
273    extra_specs_intervals_set = deepcopy(extra_specs)
274    extra_specs_intervals_set['interval'] = 1
275    extra_specs_intervals_set['retries'] = 1
276    extra_specs_rep_enabled = deepcopy(extra_specs)
277    extra_specs_rep_enabled['replication_enabled'] = True
278    rep_extra_specs = deepcopy(extra_specs_rep_enabled)
279    rep_extra_specs['array'] = remote_array
280    rep_extra_specs['interval'] = 0
281    rep_extra_specs['retries'] = 0
282    rep_extra_specs['srp'] = srp2
283    rep_extra_specs['rep_mode'] = 'Synchronous'
284    rep_extra_specs2 = deepcopy(rep_extra_specs)
285    rep_extra_specs2[utils.PORTGROUPNAME] = port_group_name_f
286    test_volume_type_1 = volume_type.VolumeType(
287        id='2b06255d-f5f0-4520-a953-b029196add6a', name='abc',
288        extra_specs=extra_specs
289    )
290    test_volume_type_list = volume_type.VolumeTypeList(
291        objects=[test_volume_type_1])
292
293    test_vol_grp_name_id_only = 'ec870a2f-6bf7-4152-aa41-75aad8e2ea96'
294    test_vol_grp_name = 'Grp_source_sg_%s' % test_vol_grp_name_id_only
295    test_fo_vol_group = 'fo_vol_group_%s' % test_vol_grp_name_id_only
296
297    test_group_1 = group.Group(
298        context=None, name=storagegroup_name_source,
299        group_id='abc', size=1,
300        id=test_vol_grp_name_id_only, status='available',
301        provider_auth=None, volume_type_ids=['abc'],
302        group_type_id='grptypeid',
303        volume_types=test_volume_type_list,
304        host=fake_host, provider_location=six.text_type(provider_location))
305
306    test_group_failed = group.Group(
307        context=None, name=failed_resource,
308        group_id='14b8894e-54ec-450a-b168-c172a16ed166',
309        size=1,
310        id='318c721c-51ad-4160-bfe1-ebde2273836f',
311        status='available',
312        provider_auth=None, volume_type_ids=['abc'],
313        group_type_id='grptypeid',
314        volume_types=test_volume_type_list,
315        host=fake_host, provider_location=six.text_type(provider_location),
316        replication_status=fields.ReplicationStatus.DISABLED)
317
318    test_rep_group = fake_group.fake_group_obj(
319        context=ctx, name=storagegroup_name_source,
320        id=test_vol_grp_name_id_only, host=fake_host,
321        replication_status=fields.ReplicationStatus.ENABLED)
322
323    test_group = fake_group.fake_group_obj(
324        context=ctx, name=storagegroup_name_source,
325        id=test_vol_grp_name_id_only, host=fake_host)
326
327    test_group_without_name = fake_group.fake_group_obj(
328        context=ctx, name=None,
329        id=test_vol_grp_name_id_only, host=fake_host)
330
331    test_group_snapshot_1 = group_snapshot.GroupSnapshot(
332        context=None, id='6560405d-b89a-4f79-9e81-ad1752f5a139',
333        group_id='876d9fbb-de48-4948-9f82-15c913ed05e7',
334        name=group_snapshot_name,
335        group_type_id='c6934c26-dde8-4bf8-a765-82b3d0130e9f',
336        status='available',
337        group=test_group_1)
338
339    test_group_snapshot_failed = group_snapshot.GroupSnapshot(
340        context=None, id='0819dd5e-9aa1-4ec7-9dda-c78e51b2ad76',
341        group_id='1fc735cb-d36c-4352-8aa6-dc1e16b5a0a7',
342        name=failed_resource,
343        group_type_id='6b70de13-98c5-46b2-8f24-e4e96a8988fa',
344        status='available',
345        group=test_group_failed)
346
347    test_volume_group_member = fake_volume.fake_volume_obj(
348        context=ctx, name='vol1', size=2, provider_auth=None,
349        provider_location=six.text_type(provider_location),
350        volume_type=test_volume_type, host=fake_host,
351        replication_driver_data=six.text_type(provider_location3),
352        group_id=test_vol_grp_name_id_only)
353
354    # masking view dict
355    masking_view_dict = {
356        'array': array,
357        'connector': connector,
358        'device_id': device_id,
359        'init_group_name': initiatorgroup_name_f,
360        'initiator_check': False,
361        'maskingview_name': masking_view_name_f,
362        'parent_sg_name': parent_sg_f,
363        'srp': srp,
364        'storagetype:disablecompression': False,
365        utils.PORTGROUPNAME: port_group_name_f,
366        'slo': slo,
367        'storagegroup_name': storagegroup_name_f,
368        'volume_name': test_volume.name,
369        'workload': workload,
370        'replication_enabled': False}
371
372    masking_view_dict_no_slo = deepcopy(masking_view_dict)
373    masking_view_dict_no_slo.update(
374        {'slo': None, 'workload': None,
375         'storagegroup_name': 'OS-HostX-No_SLO-OS-fibre-PG'})
376
377    masking_view_dict_compression_disabled = deepcopy(masking_view_dict)
378    masking_view_dict_compression_disabled.update(
379        {'storagetype:disablecompression': True,
380         'storagegroup_name': 'OS-HostX-SRP_1-DiamondDSS-OS-fibre-PG-CD'})
381
382    masking_view_dict_replication_enabled = deepcopy(masking_view_dict)
383    masking_view_dict_replication_enabled.update(
384        {'replication_enabled': True,
385         'storagegroup_name': 'OS-HostX-SRP_1-DiamondDSS-OS-fibre-PG-RE'})
386
387    # vmax data
388    # sloprovisioning
389    compression_info = {"symmetrixId": ["000197800128"]}
390    inititiatorgroup = [{"initiator": [wwpn1],
391                         "hostId": initiatorgroup_name_f,
392                         "maskingview": [masking_view_name_f]},
393                        {"initiator": [initiator],
394                         "hostId": initiatorgroup_name_i,
395                         "maskingview": [masking_view_name_i]}]
396
397    initiator_list = [{"host": initiatorgroup_name_f,
398                       "initiatorId": wwpn1,
399                       "maskingview": [masking_view_name_f]},
400                      {"host": initiatorgroup_name_i,
401                       "initiatorId": initiator,
402                       "maskingview": [masking_view_name_i]},
403                      {"initiatorId": [
404                          "FA-1D:4:" + wwpn1,
405                          "SE-4E:0:" + initiator]}]
406
407    maskingview = [{"maskingViewId": masking_view_name_f,
408                    "portGroupId": port_group_name_f,
409                    "storageGroupId": storagegroup_name_f,
410                    "hostId": initiatorgroup_name_f,
411                    "maskingViewConnection": [
412                        {"host_lun_address": "0003"}]},
413                   {"maskingViewId": masking_view_name_i,
414                    "portGroupId": port_group_name_i,
415                    "storageGroupId": storagegroup_name_i,
416                    "hostId": initiatorgroup_name_i,
417                    "maskingViewConnection": [
418                        {"host_lun_address": "0003"}]},
419                   {}]
420
421    portgroup = [{"portGroupId": port_group_name_f,
422                  "symmetrixPortKey": [
423                      {"directorId": "FA-1D",
424                       "portId": "FA-1D:4"}],
425                  "maskingview": [masking_view_name_f]},
426                 {"portGroupId": port_group_name_i,
427                  "symmetrixPortKey": [
428                      {"directorId": "SE-4E",
429                       "portId": "SE-4E:0"}],
430                  "maskingview": [masking_view_name_i]}]
431
432    port_list = [
433        {"symmetrixPort": {"num_of_masking_views": 1,
434                           "maskingview": [masking_view_name_f],
435                           "identifier": wwnn1,
436                           "symmetrixPortKey": {
437                               "directorId": "FA-1D",
438                               "portId": "4"},
439                           "portgroup": [port_group_name_f]}},
440        {"symmetrixPort": {"identifier": initiator,
441                           "symmetrixPortKey": {
442                               "directorId": "SE-4E",
443                               "portId": "0"},
444                           "ip_addresses": [ip],
445                           "num_of_masking_views": 1,
446                           "maskingview": [masking_view_name_i],
447                           "portgroup": [port_group_name_i]}}]
448
449    sg_details = [{"srp": srp,
450                   "num_of_vols": 2,
451                   "cap_gb": 2,
452                   "storageGroupId": defaultstoragegroup_name,
453                   "slo": slo,
454                   "workload": workload},
455                  {"srp": srp,
456                   "num_of_vols": 2,
457                   "cap_gb": 2,
458                   "storageGroupId": storagegroup_name_f,
459                   "slo": slo,
460                   "workload": workload,
461                   "maskingview": [masking_view_name_f],
462                   "parent_storage_group": [parent_sg_f]},
463                  {"srp": srp,
464                   "num_of_vols": 2,
465                   "cap_gb": 2,
466                   "storageGroupId": storagegroup_name_i,
467                   "slo": slo,
468                   "workload": workload,
469                   "maskingview": [masking_view_name_i],
470                   "parent_storage_group": [parent_sg_i]},
471                  {"num_of_vols": 2,
472                   "cap_gb": 2,
473                   "storageGroupId": parent_sg_f,
474                   "num_of_child_sgs": 1,
475                   "child_storage_group": [storagegroup_name_f],
476                   "maskingview": [masking_view_name_f]},
477                  {"num_of_vols": 2,
478                   "cap_gb": 2,
479                   "storageGroupId": parent_sg_i,
480                   "num_of_child_sgs": 1,
481                   "child_storage_group": [storagegroup_name_i],
482                   "maskingview": [masking_view_name_i], }
483                  ]
484
485    sg_details_rep = [{"childNames": [],
486                       "numDevicesNonGk": 2,
487                       "isLinkTarget": False,
488                       "rdf": True,
489                       "capacityGB": 2.0,
490                       "name": storagegroup_name_source,
491                       "snapVXSnapshots": ['6560405d-752f5a139'],
492                       "symmetrixId": array,
493                       "numSnapVXSnapshots": 1}]
494
495    sg_rdf_details = [{"storageGroupName": test_vol_grp_name,
496                       "symmetrixId": array,
497                       "modes": ["Synchronous"],
498                       "rdfGroupNumber": rdf_group_no,
499                       "states": ["Synchronized"]},
500                      {"storageGroupName": test_fo_vol_group,
501                       "symmetrixId": array,
502                       "modes": ["Synchronous"],
503                       "rdfGroupNumber": rdf_group_no,
504                       "states": ["Failed Over"]}]
505
506    sg_list = {"storageGroupId": [storagegroup_name_f,
507                                  defaultstoragegroup_name]}
508
509    sg_list_rep = [storagegroup_name_with_id]
510
511    srp_details = {"srpSloDemandId": ["Bronze", "Diamond", "Gold",
512                                      "None", "Optimized", "Silver"],
513                   "srpId": srp,
514                   "total_used_cap_gb": 5244.7,
515                   "total_usable_cap_gb": 20514.4,
516                   "total_subscribed_cap_gb": 84970.1,
517                   "fba_used_capacity": 5244.7,
518                   "reserved_cap_percent": 10}
519
520    array_info_wl = {'RestServerIp': '1.1.1.1', 'RestServerPort': 3448,
521                     'RestUserName': 'smc', 'RestPassword': 'smc',
522                     'SSLVerify': False, 'SerialNumber': array,
523                     'srpName': 'SRP_1', 'PortGroup': port_group_name_i,
524                     'SLO': 'Diamond', 'Workload': 'OLTP'}
525
526    array_info_no_wl = {'RestServerIp': '1.1.1.1', 'RestServerPort': 3448,
527                        'RestUserName': 'smc', 'RestPassword': 'smc',
528                        'SSLVerify': False, 'SerialNumber': array,
529                        'srpName': 'SRP_1', 'PortGroup': port_group_name_i,
530                        'SLO': 'Diamond'}
531
532    volume_details = [{"cap_gb": 2,
533                       "num_of_storage_groups": 1,
534                       "volumeId": device_id,
535                       "volume_identifier": "OS-%s" % test_volume.id,
536                       "wwn": volume_wwn,
537                       "snapvx_target": 'false',
538                       "snapvx_source": 'false',
539                       "storageGroupId": [defaultstoragegroup_name,
540                                          storagegroup_name_f]},
541                      {"cap_gb": 1,
542                       "num_of_storage_groups": 1,
543                       "volumeId": device_id2,
544                       "volume_identifier": "OS-%s" % test_volume.id,
545                       "wwn": '600012345',
546                       "storageGroupId": [defaultstoragegroup_name,
547                                          storagegroup_name_f]},
548                      {"cap_gb": 1,
549                       "num_of_storage_groups": 0,
550                       "volumeId": device_id3,
551                       "volume_identifier": '123',
552                       "wwn": '600012345'}]
553
554    volume_list = [
555        {"resultList": {"result": [{"volumeId": device_id}]}},
556        {"resultList": {"result": [{"volumeId": device_id2}]}},
557        {"resultList": {"result": [{"volumeId": device_id},
558                                   {"volumeId": device_id2}]}}]
559
560    private_vol_details = {
561        "resultList": {
562            "result": [{
563                "timeFinderInfo": {
564                    "snapVXSession": [
565                        {"srcSnapshotGenInfo": [
566                            {"snapshotHeader": {
567                                "snapshotName": "temp-1",
568                                "device": device_id},
569                                "lnkSnapshotGenInfo": [
570                                    {"targetDevice": device_id2}]}]},
571                        {"tgtSrcSnapshotGenInfo": {
572                            "snapshotName": "temp-1",
573                            "targetDevice": device_id2,
574                            "sourceDevice": device_id}}],
575                    "snapVXSrc": 'true',
576                    "snapVXTgt": 'true'},
577                "rdfInfo": {"RDFSession": [
578                    {"SRDFStatus": "Ready",
579                     "pairState": "Synchronized",
580                     "remoteDeviceID": device_id2,
581                     "remoteSymmetrixID": remote_array}]}}]}}
582
583    # Service Levels / Workloads
584    workloadtype = {"workloadId": ["OLTP", "OLTP_REP", "DSS", "DSS_REP"]}
585    srp_slo_details = {"serviceLevelDemand": [
586        {"serviceLevelId": "None"}, {"serviceLevelId": "Diamond"},
587        {"serviceLevelId": "Gold"}, {"serviceLevelId": "Optimized"}]}
588    slo_details = ['None', 'Diamond', 'Gold', 'Optimized']
589    powermax_slo_details = {"sloId": ["Bronze", "Diamond", "Gold",
590                                      "Optimized", "Platinum", "Silver"]}
591    powermax_model_details = {"symmetrixId": array,
592                              "model": "PowerMax_2000",
593                              "ucode": "5978.1091.1092"}
594    vmax_slo_details = {"sloId": ["Diamond", "Optimized"]}
595    vmax_model_details = {"model": "VMAX450F"}
596
597    # replication
598    volume_snap_vx = {"snapshotLnks": [],
599                      "snapshotSrcs": [
600                          {"generation": 0,
601                           "linkedDevices": [
602                               {"targetDevice": device_id2,
603                                "percentageCopied": 100,
604                                "state": "Copied",
605                                "copy": True,
606                                "defined": True,
607                                "linked": True}],
608                           "snapshotName": test_snapshot_snap_name,
609                           "state": "Established"}]}
610    capabilities = {"symmetrixCapability": [{"rdfCapable": True,
611                                             "snapVxCapable": True,
612                                             "symmetrixId": "0001111111"},
613                                            {"symmetrixId": array,
614                                             "snapVxCapable": True,
615                                             "rdfCapable": True}]}
616    group_snap_vx = {"generation": 0,
617                     "isLinked": False,
618                     "numUniqueTracks": 0,
619                     "isRestored": False,
620                     "name": group_snapshot_name,
621                     "numStorageGroupVolumes": 1,
622                     "state": ["Established"],
623                     "timeToLiveExpiryDate": "N/A",
624                     "isExpired": False,
625                     "numSharedTracks": 0,
626                     "timestamp": "00:30:50 Fri, 02 Jun 2017 IST +0100",
627                     "numSourceVolumes": 1
628                     }
629    group_snap_vx_1 = {"generation": 0,
630                       "isLinked": False,
631                       "numUniqueTracks": 0,
632                       "isRestored": False,
633                       "name": group_snapshot_name,
634                       "numStorageGroupVolumes": 1,
635                       "state": ["Copied"],
636                       "timeToLiveExpiryDate": "N/A",
637                       "isExpired": False,
638                       "numSharedTracks": 0,
639                       "timestamp": "00:30:50 Fri, 02 Jun 2017 IST +0100",
640                       "numSourceVolumes": 1,
641                       "linkedStorageGroup":
642                           {"name": target_group_name,
643                            "percentageCopied": 100},
644                       }
645    grp_snapvx_links = [{"name": target_group_name,
646                         "percentageCopied": 100},
647                        {"name": "another-target",
648                         "percentageCopied": 90}]
649
650    rdf_group_list = {"rdfGroupID": [{"rdfgNumber": rdf_group_no,
651                                      "label": rdf_group_name}]}
652    rdf_group_details = {"modes": ["Synchronous"],
653                         "remoteSymmetrix": remote_array,
654                         "label": rdf_group_name,
655                         "type": "Dynamic",
656                         "numDevices": 1,
657                         "remoteRdfgNumber": rdf_group_no,
658                         "rdfgNumber": rdf_group_no}
659    rdf_group_vol_details = {"remoteRdfGroupNumber": rdf_group_no,
660                             "localSymmetrixId": array,
661                             "volumeConfig": "RDF1+TDEV",
662                             "localRdfGroupNumber": rdf_group_no,
663                             "localVolumeName": device_id,
664                             "rdfpairState": "Synchronized",
665                             "remoteVolumeName": device_id2,
666                             "localVolumeState": "Ready",
667                             "rdfMode": "Synchronous",
668                             "remoteVolumeState": "Write Disabled",
669                             "remoteSymmetrixId": remote_array}
670
671    # system
672    job_list = [{"status": "SUCCEEDED",
673                 "jobId": "12345",
674                 "result": "created",
675                 "resourceLink": "storagegroup/%s" % storagegroup_name_f},
676                {"status": "RUNNING", "jobId": "55555"},
677                {"status": "FAILED", "jobId": "09999"}]
678    symmetrix = [{"symmetrixId": array,
679                  "model": "VMAX250F",
680                  "ucode": "5977.1091.1092"},
681                 {"symmetrixId": array_herc,
682                  "model": "VMAXHERC",
683                  "ucode": "5978.1091.1092"}]
684    version_details = {"version": "V9.0.0.1"}
685
686    headroom = {"headroom": [{"headroomCapacity": 20348.29}]}
687
688
689class FakeLookupService(object):
690    def get_device_mapping_from_network(self, initiator_wwns, target_wwns):
691        return VMAXCommonData.device_map
692
693
694class FakeResponse(object):
695
696    def __init__(self, status_code, return_object):
697        self.status_code = status_code
698        self.return_object = return_object
699
700    def json(self):
701        if self.return_object:
702            return self.return_object
703        else:
704            raise ValueError
705
706
707class FakeRequestsSession(object):
708
709    def __init__(self, *args, **kwargs):
710        self.data = VMAXCommonData()
711
712    def request(self, method, url, params=None, data=None):
713        return_object = ''
714        status_code = 200
715        if method == 'GET':
716            status_code, return_object = self._get_request(url, params)
717
718        elif method == 'POST' or method == 'PUT':
719            status_code, return_object = self._post_or_put(url, data)
720
721        elif method == 'DELETE':
722            status_code, return_object = self._delete(url)
723
724        elif method == 'TIMEOUT':
725            raise requests.Timeout
726
727        elif method == 'EXCEPTION':
728            raise Exception
729
730        return FakeResponse(status_code, return_object)
731
732    def _get_request(self, url, params):
733        status_code = 200
734        return_object = None
735        if self.data.failed_resource in url:
736            status_code = 500
737            return_object = self.data.job_list[2]
738        elif 'sloprovisioning' in url:
739            if 'volume' in url:
740                return_object = self._sloprovisioning_volume(url, params)
741            elif 'storagegroup' in url:
742                return_object = self._sloprovisioning_sg(url)
743            elif 'maskingview' in url:
744                return_object = self._sloprovisioning_mv(url)
745            elif 'portgroup' in url:
746                return_object = self._sloprovisioning_pg(url)
747            elif 'director' in url:
748                return_object = self._sloprovisioning_port(url)
749            elif 'host' in url:
750                return_object = self._sloprovisioning_ig(url)
751            elif 'initiator' in url:
752                return_object = self._sloprovisioning_initiator(url)
753            elif 'srp' in url:
754                return_object = self.data.srp_details
755            elif 'workloadtype' in url:
756                return_object = self.data.workloadtype
757            elif 'compressionCapable' in url:
758                return_object = self.data.compression_info
759            elif 'slo' in url:
760                return_object = self.data.powermax_slo_details
761
762        elif 'replication' in url:
763            return_object = self._replication(url)
764
765        elif 'system' in url:
766            return_object = self._system(url)
767
768        elif 'headroom' in url:
769            return_object = self.data.headroom
770
771        return status_code, return_object
772
773    def _sloprovisioning_volume(self, url, params):
774        return_object = self.data.volume_list[2]
775        if '/private' in url:
776            return_object = self.data.private_vol_details
777        elif params:
778            if '1' in params.values():
779                return_object = self.data.volume_list[0]
780            elif '2' in params.values():
781                return_object = self.data.volume_list[1]
782        else:
783            for vol in self.data.volume_details:
784                if vol['volumeId'] in url:
785                    return_object = vol
786                    break
787        return return_object
788
789    def _sloprovisioning_sg(self, url):
790        return_object = self.data.sg_list
791        for sg in self.data.sg_details:
792            if sg['storageGroupId'] in url:
793                return_object = sg
794                break
795        return return_object
796
797    def _sloprovisioning_mv(self, url):
798        if self.data.masking_view_name_i in url:
799            return_object = self.data.maskingview[1]
800        else:
801            return_object = self.data.maskingview[0]
802        return return_object
803
804    def _sloprovisioning_pg(self, url):
805        return_object = None
806        for pg in self.data.portgroup:
807            if pg['portGroupId'] in url:
808                return_object = pg
809                break
810        return return_object
811
812    def _sloprovisioning_port(self, url):
813        return_object = None
814        for port in self.data.port_list:
815            if port['symmetrixPort']['symmetrixPortKey']['directorId'] in url:
816                return_object = port
817                break
818        return return_object
819
820    def _sloprovisioning_ig(self, url):
821        return_object = None
822        for ig in self.data.inititiatorgroup:
823            if ig['hostId'] in url:
824                return_object = ig
825                break
826        return return_object
827
828    def _sloprovisioning_initiator(self, url):
829        return_object = self.data.initiator_list[2]
830        if self.data.wwpn1 in url:
831            return_object = self.data.initiator_list[0]
832        elif self.data.initiator in url:
833            return_object = self.data.initiator_list[1]
834        return return_object
835
836    def _replication(self, url):
837        return_object = None
838        if 'storagegroup' in url:
839            return_object = self._replication_sg(url)
840        elif 'rdf_group' in url:
841            if self.data.device_id in url:
842                return_object = self.data.rdf_group_vol_details
843            elif self.data.rdf_group_no in url:
844                return_object = self.data.rdf_group_details
845            else:
846                return_object = self.data.rdf_group_list
847        elif 'snapshot' in url:
848            return_object = self.data.volume_snap_vx
849        elif 'capabilities' in url:
850            return_object = self.data.capabilities
851        return return_object
852
853    def _replication_sg(self, url):
854        return_object = None
855        if 'generation' in url:
856            return_object = self.data.group_snap_vx
857        elif 'rdf_group' in url:
858            for sg in self.data.sg_rdf_details:
859                if sg['storageGroupName'] in url:
860                    return_object = sg
861                    break
862        elif 'storagegroup' in url:
863            return_object = self.data.sg_details_rep[0]
864        return return_object
865
866    def _system(self, url):
867        return_object = None
868        if 'job' in url:
869            for job in self.data.job_list:
870                if job['jobId'] in url:
871                    return_object = job
872                    break
873        elif 'version' in url:
874            return_object = self.data.version_details
875        else:
876            for symm in self.data.symmetrix:
877                if symm['symmetrixId'] in url:
878                    return_object = symm
879                    break
880        return return_object
881
882    def _post_or_put(self, url, payload):
883        return_object = self.data.job_list[0]
884        status_code = 201
885        if self.data.failed_resource in url:
886            status_code = 500
887            return_object = self.data.job_list[2]
888        elif payload:
889            payload = ast.literal_eval(payload)
890            if self.data.failed_resource in payload.values():
891                status_code = 500
892                return_object = self.data.job_list[2]
893            if payload.get('executionOption'):
894                status_code = 202
895        return status_code, return_object
896
897    def _delete(self, url):
898        if self.data.failed_resource in url:
899            status_code = 500
900            return_object = self.data.job_list[2]
901        else:
902            status_code = 204
903            return_object = None
904        return status_code, return_object
905
906    def session(self):
907        return FakeRequestsSession()
908
909
910class FakeConfiguration(object):
911
912    def __init__(self, emc_file=None, volume_backend_name=None,
913                 interval=0, retries=0, replication_device=None, **kwargs):
914        self.cinder_dell_emc_config_file = emc_file
915        self.interval = interval
916        self.retries = retries
917        self.volume_backend_name = volume_backend_name
918        self.config_group = volume_backend_name
919        self.san_is_local = False
920        if replication_device:
921            self.replication_device = [replication_device]
922        for key, value in kwargs.items():
923            if key == 'san_login':
924                self.san_login = value
925            elif key == 'san_password':
926                self.san_password = value
927            elif key == 'san_ip':
928                self.san_ip = value
929            elif key == 'san_rest_port':
930                self.san_rest_port = value
931            elif key == 'vmax_srp':
932                self.vmax_srp = value
933            elif key == 'vmax_service_level':
934                self.vmax_service_level = value
935            elif key == 'vmax_workload':
936                self.vmax_workload = value
937            elif key == 'vmax_port_groups':
938                self.vmax_port_groups = value
939            elif key == 'vmax_array':
940                self.vmax_array = value
941            elif key == 'use_chap_auth':
942                self.use_chap_auth = value
943            elif key == 'chap_username':
944                self.chap_username = value
945            elif key == 'chap_password':
946                self.chap_password = value
947            elif key == 'driver_ssl_cert_verify':
948                self.driver_ssl_cert_verify = value
949            elif key == 'driver_ssl_cert_path':
950                self.driver_ssl_cert_path = value
951
952    def safe_get(self, key):
953        try:
954            return getattr(self, key)
955        except Exception:
956            return None
957
958    def append_config_values(self, values):
959        pass
960
961
962class FakeXML(object):
963
964    def __init__(self):
965        """"""
966        self.tempdir = tempfile.mkdtemp()
967        self.data = VMAXCommonData()
968
969    def create_fake_config_file(self, config_group, portgroup,
970                                ssl_verify=False):
971
972        doc = minidom.Document()
973        emc = doc.createElement("EMC")
974        doc.appendChild(emc)
975        doc = self.add_array_info(doc, emc, portgroup, ssl_verify)
976        filename = 'cinder_dell_emc_config_%s.xml' % config_group
977        config_file_path = self.tempdir + '/' + filename
978
979        f = open(config_file_path, 'w')
980        doc.writexml(f)
981        f.close()
982        return config_file_path
983
984    def add_array_info(self, doc, emc, portgroup_name, ssl_verify):
985        array = doc.createElement("Array")
986        arraytext = doc.createTextNode(self.data.array)
987        emc.appendChild(array)
988        array.appendChild(arraytext)
989
990        ecomserverip = doc.createElement("RestServerIp")
991        ecomserveriptext = doc.createTextNode("1.1.1.1")
992        emc.appendChild(ecomserverip)
993        ecomserverip.appendChild(ecomserveriptext)
994
995        ecomserverport = doc.createElement("RestServerPort")
996        ecomserverporttext = doc.createTextNode("8443")
997        emc.appendChild(ecomserverport)
998        ecomserverport.appendChild(ecomserverporttext)
999
1000        ecomusername = doc.createElement("RestUserName")
1001        ecomusernametext = doc.createTextNode("smc")
1002        emc.appendChild(ecomusername)
1003        ecomusername.appendChild(ecomusernametext)
1004
1005        ecompassword = doc.createElement("RestPassword")
1006        ecompasswordtext = doc.createTextNode("smc")
1007        emc.appendChild(ecompassword)
1008        ecompassword.appendChild(ecompasswordtext)
1009
1010        portgroup = doc.createElement("PortGroup")
1011        portgrouptext = doc.createTextNode(portgroup_name)
1012        portgroup.appendChild(portgrouptext)
1013
1014        portgroups = doc.createElement("PortGroups")
1015        portgroups.appendChild(portgroup)
1016        emc.appendChild(portgroups)
1017
1018        srp = doc.createElement("SRP")
1019        srptext = doc.createTextNode("SRP_1")
1020        emc.appendChild(srp)
1021        srp.appendChild(srptext)
1022
1023        if ssl_verify:
1024            restcert = doc.createElement("SSLCert")
1025            restcerttext = doc.createTextNode("/path/cert.crt")
1026            emc.appendChild(restcert)
1027            restcert.appendChild(restcerttext)
1028
1029            restverify = doc.createElement("SSLVerify")
1030            restverifytext = doc.createTextNode("/path/cert.pem")
1031            emc.appendChild(restverify)
1032            restverify.appendChild(restverifytext)
1033        return doc
1034
1035
1036class VMAXUtilsTest(test.TestCase):
1037    def setUp(self):
1038        self.data = VMAXCommonData()
1039        volume_utils.get_max_over_subscription_ratio = mock.Mock()
1040        super(VMAXUtilsTest, self).setUp()
1041        config_group = 'UtilsTests'
1042        fake_xml = FakeXML().create_fake_config_file(
1043            config_group, self.data.port_group_name_i, True)
1044        configuration = FakeConfiguration(fake_xml, config_group)
1045        rest.VMAXRest._establish_rest_session = mock.Mock(
1046            return_value=FakeRequestsSession())
1047        driver = iscsi.VMAXISCSIDriver(configuration=configuration)
1048        self.driver = driver
1049        self.common = self.driver.common
1050        self.utils = self.common.utils
1051
1052    def test_get_volumetype_extra_specs(self):
1053        with mock.patch.object(volume_types, 'get_volume_type_extra_specs',
1054                               return_value={'specs'}) as type_mock:
1055            # path 1: volume_type_id not passed in
1056            self.data.test_volume.volume_type_id = (
1057                self.data.test_volume_type.id)
1058            self.utils.get_volumetype_extra_specs(self.data.test_volume)
1059            volume_types.get_volume_type_extra_specs.assert_called_once_with(
1060                self.data.test_volume_type.id)
1061            type_mock.reset_mock()
1062            # path 2: volume_type_id passed in
1063            self.utils.get_volumetype_extra_specs(self.data.test_volume, '123')
1064            volume_types.get_volume_type_extra_specs.assert_called_once_with(
1065                '123')
1066            type_mock.reset_mock()
1067            # path 3: no type_id
1068            self.utils.get_volumetype_extra_specs(self.data.test_clone_volume)
1069            (volume_types.get_volume_type_extra_specs.
1070             assert_not_called())
1071
1072    def test_get_volumetype_extra_specs_exception(self):
1073        extra_specs = self.utils.get_volumetype_extra_specs(
1074            {'name': 'no_type_id'})
1075        self.assertEqual({}, extra_specs)
1076
1077    def test_get_random_portgroup(self):
1078        # 4 portgroups
1079        data = ("<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
1080                "<PortGroups>"
1081                "<PortGroup>OS-PG1</PortGroup>\n"
1082                "<PortGroup>OS-PG2</PortGroup>\n"
1083                "<PortGroup>OS-PG3</PortGroup>\n"
1084                "<PortGroup>OS-PG4</PortGroup>\n"
1085                "</PortGroups>"
1086                "</EMC>")
1087        dom = minidom.parseString(data)
1088        portgroup = self.utils._get_random_portgroup(dom)
1089        self.assertIn('OS-PG', portgroup)
1090
1091        # Duplicate portgroups
1092        data = ("<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
1093                "<PortGroups>"
1094                "<PortGroup>OS-PG1</PortGroup>\n"
1095                "<PortGroup>OS-PG1</PortGroup>\n"
1096                "<PortGroup>OS-PG1</PortGroup>\n"
1097                "<PortGroup>OS-PG2</PortGroup>\n"
1098                "</PortGroups>"
1099                "</EMC>")
1100        dom = minidom.parseString(data)
1101        portgroup = self.utils._get_random_portgroup(dom)
1102        self.assertIn('OS-PG', portgroup)
1103
1104    def test_get_random_portgroup_none(self):
1105        # Missing PortGroup tag
1106        data = ("<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
1107                "</EMC>")
1108        dom = minidom.parseString(data)
1109        self.assertIsNone(self.utils._get_random_portgroup(dom))
1110
1111        # Missing portgroups
1112        data = ("<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
1113                "<PortGroups>"
1114                "</PortGroups>"
1115                "</EMC>")
1116        dom = minidom.parseString(data)
1117        self.assertIsNone(self.utils._get_random_portgroup(dom))
1118
1119    def test_get_host_short_name(self):
1120        host_under_16_chars = 'host_13_chars'
1121        host1 = self.utils.get_host_short_name(
1122            host_under_16_chars)
1123        self.assertEqual(host_under_16_chars, host1)
1124
1125        host_over_16_chars = (
1126            'host_over_16_chars_host_over_16_chars_host_over_16_chars')
1127        # Check that the same md5 value is retrieved from multiple calls
1128        host2 = self.utils.get_host_short_name(
1129            host_over_16_chars)
1130        host3 = self.utils.get_host_short_name(
1131            host_over_16_chars)
1132        self.assertEqual(host2, host3)
1133        host_with_period = 'hostname.with.many.parts'
1134        ref_host_name = self.utils.generate_unique_trunc_host('hostname')
1135        host4 = self.utils.get_host_short_name(host_with_period)
1136        self.assertEqual(ref_host_name, host4)
1137
1138    def test_get_volume_element_name(self):
1139        volume_id = 'ea95aa39-080b-4f11-9856-a03acf9112ad'
1140        volume_element_name = self.utils.get_volume_element_name(volume_id)
1141        expect_vol_element_name = ('OS-' + volume_id)
1142        self.assertEqual(expect_vol_element_name, volume_element_name)
1143
1144    def test_parse_file_to_get_array_map(self):
1145        kwargs = (
1146            {'RestServerIp': '1.1.1.1',
1147             'RestServerPort': '8443',
1148             'RestUserName': 'smc',
1149             'RestPassword': 'smc',
1150             'SSLCert': '/path/cert.crt',
1151             'SSLVerify': '/path/cert.pem',
1152             'SerialNumber': self.data.array,
1153             'srpName': 'SRP_1',
1154             'PortGroup': self.data.port_group_name_i})
1155        array_info = self.utils.parse_file_to_get_array_map(
1156            self.common.configuration.cinder_dell_emc_config_file)
1157        self.assertEqual(kwargs, array_info)
1158
1159    @mock.patch.object(utils.VMAXUtils,
1160                       '_get_connection_info')
1161    @mock.patch.object(utils.VMAXUtils,
1162                       '_get_random_portgroup')
1163    def test_parse_file_to_get_array_map_errors(self, mock_port, mock_conn):
1164        tempdir = tempfile.mkdtemp()
1165        doc = minidom.Document()
1166        emc = doc.createElement("EMC")
1167        doc.appendChild(emc)
1168        filename = 'cinder_dell_emc_config_%s.xml' % 'fake_xml'
1169        config_file_path = tempdir + '/' + filename
1170        f = open(config_file_path, 'w')
1171        doc.writexml(f)
1172        f.close()
1173        array_info = self.utils.parse_file_to_get_array_map(
1174            config_file_path)
1175        self.assertIsNone(array_info['SerialNumber'])
1176
1177    def test_parse_file_to_get_array_map_conn_errors(self):
1178        tempdir = tempfile.mkdtemp()
1179        doc = minidom.Document()
1180        emc = doc.createElement("EMC")
1181        doc.appendChild(emc)
1182        filename = 'cinder_dell_emc_config_%s.xml' % 'fake_xml'
1183        config_file_path = tempdir + '/' + filename
1184        f = open(config_file_path, 'w')
1185        doc.writexml(f)
1186        f.close()
1187        self.assertRaises(exception.VolumeBackendAPIException,
1188                          self.utils.parse_file_to_get_array_map,
1189                          config_file_path)
1190
1191    def test_truncate_string(self):
1192        # string is less than max number
1193        str_to_truncate = 'string'
1194        response = self.utils.truncate_string(str_to_truncate, 10)
1195        self.assertEqual(str_to_truncate, response)
1196
1197    def test_get_default_oversubscription_ratio(self):
1198        default_ratio = 20.0
1199        max_over_sub_ratio1 = 30.0
1200        returned_max = self.utils.get_default_oversubscription_ratio(
1201            max_over_sub_ratio1)
1202        self.assertEqual(max_over_sub_ratio1, returned_max)
1203        max_over_sub_ratio2 = 0.5
1204        returned_max = self.utils.get_default_oversubscription_ratio(
1205            max_over_sub_ratio2)
1206        self.assertEqual(default_ratio, returned_max)
1207
1208    def test_get_default_storage_group_name_slo_workload(self):
1209        srp_name = self.data.srp
1210        slo = self.data.slo
1211        workload = self.data.workload
1212        sg_name = self.utils.get_default_storage_group_name(
1213            srp_name, slo, workload)
1214        self.assertEqual(self.data.defaultstoragegroup_name, sg_name)
1215
1216    def test_get_default_storage_group_name_no_slo(self):
1217        srp_name = self.data.srp
1218        slo = None
1219        workload = None
1220        sg_name = self.utils.get_default_storage_group_name(
1221            srp_name, slo, workload)
1222        self.assertEqual(self.data.default_sg_no_slo, sg_name)
1223
1224    def test_get_default_storage_group_name_compr_disabled(self):
1225        srp_name = self.data.srp
1226        slo = self.data.slo
1227        workload = self.data.workload
1228        sg_name = self.utils.get_default_storage_group_name(
1229            srp_name, slo, workload, True)
1230        self.assertEqual(self.data.default_sg_compr_disabled, sg_name)
1231
1232    def test_get_time_delta(self):
1233        start_time = 1487781721.09
1234        end_time = 1487781758.16
1235        delta = end_time - start_time
1236        ref_delta = six.text_type(datetime.timedelta(seconds=int(delta)))
1237        time_delta = self.utils.get_time_delta(start_time, end_time)
1238        self.assertEqual(ref_delta, time_delta)
1239
1240    def test_get_short_protocol_type(self):
1241        # iscsi
1242        short_i_protocol = self.utils.get_short_protocol_type('iscsi')
1243        self.assertEqual('I', short_i_protocol)
1244        # fc
1245        short_f_protocol = self.utils.get_short_protocol_type('FC')
1246        self.assertEqual('F', short_f_protocol)
1247        # else
1248        other_protocol = self.utils.get_short_protocol_type('OTHER')
1249        self.assertEqual('OTHER', other_protocol)
1250
1251    def test_get_temp_snap_name(self):
1252        clone_name = "12345"
1253        source_device_id = self.data.device_id
1254        ref_name = "temp-00001-12345"
1255        snap_name = self.utils.get_temp_snap_name(
1256            clone_name, source_device_id)
1257        self.assertEqual(ref_name, snap_name)
1258
1259    def test_get_array_and_device_id(self):
1260        volume = deepcopy(self.data.test_volume)
1261        external_ref = {u'source-name': u'00002'}
1262        array, device_id = self.utils.get_array_and_device_id(
1263            volume, external_ref)
1264        self.assertEqual(self.data.array, array)
1265        self.assertEqual('00002', device_id)
1266
1267    def test_get_array_and_device_id_exception(self):
1268        volume = deepcopy(self.data.test_volume)
1269        external_ref = {u'source-name': None}
1270        self.assertRaises(exception.VolumeBackendAPIException,
1271                          self.utils.get_array_and_device_id,
1272                          volume, external_ref)
1273
1274    def test_get_pg_short_name(self):
1275        pg_under_12_chars = 'pg_11_chars'
1276        pg1 = self.utils.get_pg_short_name(pg_under_12_chars)
1277        self.assertEqual(pg_under_12_chars, pg1)
1278
1279        pg_over_12_chars = 'portgroup_over_12_characters'
1280        # Check that the same md5 value is retrieved from multiple calls
1281        pg2 = self.utils.get_pg_short_name(pg_over_12_chars)
1282        pg3 = self.utils.get_pg_short_name(pg_over_12_chars)
1283        self.assertEqual(pg2, pg3)
1284
1285    def test_is_compression_disabled_true(self):
1286        extra_specs = self.data.extra_specs_disable_compression
1287        do_disable_compression = self.utils.is_compression_disabled(
1288            extra_specs)
1289        self.assertTrue(do_disable_compression)
1290
1291    def test_is_compression_disabled_false(self):
1292        # Path 1: no compression extra spec set
1293        extra_specs = self.data.extra_specs
1294        do_disable_compression = self.utils.is_compression_disabled(
1295            extra_specs)
1296        self.assertFalse(do_disable_compression)
1297        # Path 2: compression extra spec set to false
1298        extra_specs2 = deepcopy(extra_specs)
1299        extra_specs2.update({utils.DISABLECOMPRESSION: 'false'})
1300        do_disable_compression2 = self.utils.is_compression_disabled(
1301            extra_specs)
1302        self.assertFalse(do_disable_compression2)
1303
1304    def test_change_compression_type_true(self):
1305        source_compr_disabled_true = 'true'
1306        new_type_compr_disabled = {
1307            'extra_specs': {utils.DISABLECOMPRESSION: 'no'}}
1308        ans = self.utils.change_compression_type(
1309            source_compr_disabled_true, new_type_compr_disabled)
1310        self.assertTrue(ans)
1311
1312    def test_change_compression_type_false(self):
1313        source_compr_disabled_true = True
1314        new_type_compr_disabled = {
1315            'extra_specs': {utils.DISABLECOMPRESSION: 'true'}}
1316        ans = self.utils.change_compression_type(
1317            source_compr_disabled_true, new_type_compr_disabled)
1318        self.assertFalse(ans)
1319
1320    def test_is_replication_enabled(self):
1321        is_re = self.utils.is_replication_enabled(
1322            self.data.vol_type_extra_specs_rep_enabled)
1323        self.assertTrue(is_re)
1324        is_re2 = self.utils.is_replication_enabled(self.data.extra_specs)
1325        self.assertFalse(is_re2)
1326
1327    def test_get_replication_config(self):
1328        # Success, allow_extend false
1329        rep_device_list1 = [{'target_device_id': self.data.remote_array,
1330                             'remote_pool': self.data.srp,
1331                             'remote_port_group': self.data.port_group_name_f,
1332                             'rdf_group_label': self.data.rdf_group_name}]
1333        rep_config1 = self.utils.get_replication_config(rep_device_list1)
1334        self.assertEqual(self.data.remote_array, rep_config1['array'])
1335        # Success, allow_extend true
1336        rep_device_list2 = rep_device_list1
1337        rep_device_list2[0]['allow_extend'] = 'true'
1338        rep_config2 = self.utils.get_replication_config(rep_device_list2)
1339        self.assertTrue(rep_config2['allow_extend'])
1340        # No rep_device_list
1341        rep_device_list3 = []
1342        rep_config3 = self.utils.get_replication_config(rep_device_list3)
1343        self.assertIsNone(rep_config3)
1344        # Exception
1345        rep_device_list4 = [{'target_device_id': self.data.remote_array,
1346                             'remote_pool': self.data.srp}]
1347        self.assertRaises(exception.VolumeBackendAPIException,
1348                          self.utils.get_replication_config, rep_device_list4)
1349        # Success, mode is async
1350        rep_device_list5 = rep_device_list2
1351        rep_device_list5[0]['mode'] = 'async'
1352        rep_config5 = self.utils.get_replication_config(rep_device_list5)
1353        self.assertEqual(utils.REP_ASYNC, rep_config5['mode'])
1354        # Success, mode is metro - no other options set
1355        rep_device_list6 = rep_device_list5
1356        rep_device_list6[0]['mode'] = 'metro'
1357        rep_config6 = self.utils.get_replication_config(rep_device_list6)
1358        self.assertFalse(rep_config6['metro_bias'])
1359        self.assertFalse(rep_config6['allow_delete_metro'])
1360        # Success, mode is metro - metro options true
1361        rep_device_list7 = rep_device_list6
1362        rep_device_list6[0].update(
1363            {'allow_delete_metro': 'true', 'metro_use_bias': 'true'})
1364        rep_config7 = self.utils.get_replication_config(rep_device_list7)
1365        self.assertTrue(rep_config7['metro_bias'])
1366        self.assertTrue(rep_config7['allow_delete_metro'])
1367
1368    def test_is_volume_failed_over(self):
1369        vol = deepcopy(self.data.test_volume)
1370        vol.replication_status = fields.ReplicationStatus.FAILED_OVER
1371        is_fo1 = self.utils.is_volume_failed_over(vol)
1372        self.assertTrue(is_fo1)
1373        is_fo2 = self.utils.is_volume_failed_over(self.data.test_volume)
1374        self.assertFalse(is_fo2)
1375        is_fo3 = self.utils.is_volume_failed_over(None)
1376        self.assertFalse(is_fo3)
1377
1378    def test_add_legacy_pools(self):
1379        pools = [{'pool_name': "Diamond+None+SRP_1+000197800111"},
1380                 {'pool_name': "Diamond+OLTP+SRP_1+000197800111"}]
1381        new_pools = self.utils.add_legacy_pools(pools)
1382        ref_pools = [{'pool_name': "Diamond+None+SRP_1+000197800111"},
1383                     {'pool_name': "Diamond+OLTP+SRP_1+000197800111"},
1384                     {'pool_name': "Diamond+SRP_1+000197800111"}]
1385        self.assertEqual(ref_pools, new_pools)
1386
1387    def test_update_volume_group_name(self):
1388        group = self.data.test_group_1
1389        ref_group_name = self.data.test_vol_grp_name
1390        vol_grp_name = self.utils.update_volume_group_name(group)
1391        self.assertEqual(ref_group_name, vol_grp_name)
1392
1393    def test_update_volume_group_name_id_only(self):
1394        group = self.data.test_group_without_name
1395        ref_group_name = self.data.test_vol_grp_name_id_only
1396        vol_grp_name = self.utils.update_volume_group_name(group)
1397        self.assertEqual(ref_group_name, vol_grp_name)
1398
1399    def test_get_volume_group_utils(self):
1400        array, intervals_retries = self.utils.get_volume_group_utils(
1401            self.data.test_group_1, interval=1, retries=1)
1402        ref_array = self.data.array
1403        self.assertEqual(ref_array, array)
1404
1405    def test_update_volume_model_updates(self):
1406        volume_model_updates = [{'id': '1', 'status': 'available'}]
1407        volumes = [self.data.test_volume]
1408        ref_val = {'id': self.data.test_volume.id,
1409                   'status': 'error_deleting'}
1410        ret_val = self.utils.update_volume_model_updates(
1411            volume_model_updates, volumes, 'abc', status='error_deleting')
1412        self.assertEqual(ref_val, ret_val[1])
1413
1414    def test_update_volume_model_updates_empty_update_list(self):
1415        volume_model_updates = []
1416        volumes = [self.data.test_volume]
1417        ref_val = [{'id': self.data.test_volume.id,
1418                   'status': 'available'}]
1419        ret_val = self.utils.update_volume_model_updates(
1420            volume_model_updates, volumes, 'abc')
1421        self.assertEqual(ref_val, ret_val)
1422
1423    def test_update_volume_model_updates_empty_vol_list(self):
1424        volume_model_updates = []
1425        volumes = []
1426        ref_val = []
1427        ret_val = self.utils.update_volume_model_updates(
1428            volume_model_updates, volumes, 'abc')
1429        self.assertEqual(ref_val, ret_val)
1430
1431    def test_check_replication_matched(self):
1432        # Check 1: Volume is not part of a group
1433        self.utils.check_replication_matched(
1434            self.data.test_volume, self.data.extra_specs)
1435        group_volume = deepcopy(self.data.test_volume)
1436        group_volume.group = self.data.test_group
1437        with mock.patch.object(volume_utils, 'is_group_a_type',
1438                               return_value=False):
1439            # Check 2: Both volume and group have the same rep status
1440            self.utils.check_replication_matched(
1441                group_volume, self.data.extra_specs)
1442            # Check 3: Volume and group have different rep status
1443            with mock.patch.object(self.utils, 'is_replication_enabled',
1444                                   return_value=True):
1445                self.assertRaises(exception.InvalidInput,
1446                                  self.utils.check_replication_matched,
1447                                  group_volume, self.data.extra_specs)
1448
1449    def test_check_rep_status_enabled(self):
1450        # Check 1: not replication enabled
1451        with mock.patch.object(volume_utils, 'is_group_a_type',
1452                               return_value=False):
1453            self.utils.check_rep_status_enabled(self.data.test_group)
1454        # Check 2: replication enabled, status enabled
1455        with mock.patch.object(volume_utils, 'is_group_a_type',
1456                               return_value=True):
1457            self.utils.check_rep_status_enabled(self.data.test_rep_group)
1458        # Check 3: replication enabled, status disabled
1459            self.assertRaises(exception.InvalidInput,
1460                              self.utils.check_rep_status_enabled,
1461                              self.data.test_group)
1462
1463    def test_get_replication_prefix(self):
1464        async_prefix = self.utils.get_replication_prefix(utils.REP_ASYNC)
1465        self.assertEqual('-RA', async_prefix)
1466        sync_prefix = self.utils.get_replication_prefix(utils.REP_SYNC)
1467        self.assertEqual('-RE', sync_prefix)
1468        metro_prefix = self.utils.get_replication_prefix(utils.REP_METRO)
1469        self.assertEqual('-RM', metro_prefix)
1470
1471    def test_get_async_rdf_managed_grp_name(self):
1472        rep_config = {'rdf_group_label': self.data.rdf_group_name,
1473                      'mode': utils.REP_ASYNC}
1474        grp_name = self.utils.get_async_rdf_managed_grp_name(rep_config)
1475        self.assertEqual(self.data.rdf_managed_async_grp, grp_name)
1476
1477    def test_is_metro_device(self):
1478        rep_config = {'mode': utils.REP_METRO}
1479        is_metro = self.utils.is_metro_device(
1480            rep_config, self.data.rep_extra_specs)
1481        self.assertTrue(is_metro)
1482        rep_config2 = {'mode': utils.REP_ASYNC}
1483        is_metro2 = self.utils.is_metro_device(
1484            rep_config2, self.data.rep_extra_specs)
1485        self.assertFalse(is_metro2)
1486
1487    def test_does_vol_need_rdf_management_group(self):
1488        self.assertFalse(self.utils.does_vol_need_rdf_management_group(
1489            self.data.rep_extra_specs))
1490        extra_specs = deepcopy(self.data.rep_extra_specs)
1491        extra_specs[utils.REP_MODE] = utils.REP_ASYNC
1492        self.assertTrue(self.utils.does_vol_need_rdf_management_group(
1493            extra_specs))
1494
1495    def test_modify_snapshot_prefix_manage(self):
1496        snap_name = self.data.snapshot_id
1497        expected_snap_name = self.data.managed_snap_id
1498
1499        updated_name = self.utils.modify_snapshot_prefix(
1500            snap_name, manage=True)
1501
1502        self.assertEqual(expected_snap_name, updated_name)
1503
1504    def test_modify_snapshot_prefix_unmanage(self):
1505        snap_name = self.data.managed_snap_id
1506        expected_snap_name = self.data.snapshot_id
1507
1508        updated_name = self.utils.modify_snapshot_prefix(
1509            snap_name, unmanage=True)
1510
1511        self.assertEqual(expected_snap_name, updated_name)
1512
1513
1514class VMAXRestTest(test.TestCase):
1515    def setUp(self):
1516        self.data = VMAXCommonData()
1517
1518        super(VMAXRestTest, self).setUp()
1519        volume_utils.get_max_over_subscription_ratio = mock.Mock()
1520        config_group = 'RestTests'
1521        fake_xml = FakeXML().create_fake_config_file(
1522            config_group, self.data.port_group_name_f)
1523        configuration = FakeConfiguration(fake_xml, config_group)
1524        rest.VMAXRest._establish_rest_session = mock.Mock(
1525            return_value=FakeRequestsSession())
1526        driver = fc.VMAXFCDriver(configuration=configuration)
1527        self.driver = driver
1528        self.common = self.driver.common
1529        self.rest = self.common.rest
1530        self.utils = self.common.utils
1531
1532    def test_rest_request_exception(self):
1533        sc, msg = self.rest.request('/fake_url', 'TIMEOUT')
1534        self.assertIsNone(sc)
1535        self.assertIsNone(msg)
1536        self.assertRaises(exception.VolumeBackendAPIException,
1537                          self.rest.request, '', 'EXCEPTION')
1538
1539    def test_wait_for_job_complete(self):
1540        rc, job, status, task = self.rest.wait_for_job_complete(
1541            {'status': 'created', 'jobId': '12345'}, self.data.extra_specs)
1542        self.assertEqual(0, rc)
1543
1544    def test_wait_for_job_complete_failed(self):
1545        with mock.patch.object(self.rest, '_is_job_finished',
1546                               side_effect=exception.BadHTTPResponseStatus):
1547            self.assertRaises(exception.VolumeBackendAPIException,
1548                              self.rest.wait_for_job_complete,
1549                              self.data.job_list[0], self.data.extra_specs)
1550
1551    def test_is_job_finished_false(self):
1552        job_id = "55555"
1553        complete, response, rc, status, task = self.rest._is_job_finished(
1554            job_id)
1555        self.assertFalse(complete)
1556
1557    def test_is_job_finished_failed(self):
1558        job_id = "55555"
1559        complete, response, rc, status, task = self.rest._is_job_finished(
1560            job_id)
1561        self.assertFalse(complete)
1562        with mock.patch.object(self.rest, 'request',
1563                               return_value=(200, {'status': 'FAILED'})):
1564            complete, response, rc, status, task = (
1565                self.rest._is_job_finished(job_id))
1566            self.assertTrue(complete)
1567            self.assertEqual(-1, rc)
1568
1569    def test_check_status_code_success(self):
1570        status_code = 200
1571        self.rest.check_status_code_success(
1572            'test success', status_code, "")
1573
1574    def test_check_status_code_not_success(self):
1575        status_code = 500
1576        self.assertRaises(exception.VolumeBackendAPIException,
1577                          self.rest.check_status_code_success,
1578                          'test exception', status_code, "")
1579
1580    def test_wait_for_job_success(self):
1581        operation = 'test'
1582        status_code = 202
1583        job = self.data.job_list[0]
1584        extra_specs = self.data.extra_specs
1585        self.rest.wait_for_job(
1586            operation, status_code, job, extra_specs)
1587
1588    def test_wait_for_job_failed(self):
1589        operation = 'test'
1590        status_code = 202
1591        job = self.data.job_list[2]
1592        extra_specs = self.data.extra_specs
1593        with mock.patch.object(self.rest, 'wait_for_job_complete',
1594                               return_value=(-1, '', '', '')):
1595            self.assertRaises(exception.VolumeBackendAPIException,
1596                              self.rest.wait_for_job,
1597                              operation, status_code, job, extra_specs)
1598
1599    def test_get_resource_present(self):
1600        array = self.data.array
1601        category = 'sloprovisioning'
1602        resource_type = 'storagegroup'
1603        resource = self.rest.get_resource(array, category, resource_type)
1604        self.assertEqual(self.data.sg_list, resource)
1605
1606    def test_get_resource_not_present(self):
1607        array = self.data.array
1608        category = 'sloprovisioning'
1609        resource_type = self.data.failed_resource
1610        resource = self.rest.get_resource(array, category, resource_type)
1611        self.assertIsNone(resource)
1612
1613    def test_create_resource_success(self):
1614        array = self.data.array
1615        category = ''
1616        resource_type = ''
1617        payload = {'someKey': 'someValue'}
1618        status_code, message = self.rest.create_resource(
1619            array, category, resource_type, payload)
1620        self.assertEqual(self.data.job_list[0], message)
1621
1622    def test_create_resource_failed(self):
1623        array = self.data.array
1624        category = ''
1625        resource_type = ''
1626        payload = {'someKey': self.data.failed_resource}
1627        self.assertRaises(
1628            exception.VolumeBackendAPIException,
1629            self.rest.create_resource, array, category,
1630            resource_type, payload)
1631
1632    def test_modify_resource(self):
1633        array = self.data.array
1634        category = ''
1635        resource_type = ''
1636        payload = {'someKey': 'someValue'}
1637        status_code, message = self.rest.modify_resource(
1638            array, category, resource_type, payload)
1639        self.assertEqual(self.data.job_list[0], message)
1640
1641    def test_modify_resource_failed(self):
1642        array = self.data.array
1643        category = ''
1644        resource_type = ''
1645        payload = {'someKey': self.data.failed_resource}
1646        self.assertRaises(
1647            exception.VolumeBackendAPIException,
1648            self.rest.modify_resource, array, category,
1649            resource_type, payload)
1650
1651    def test_delete_resource(self):
1652        operation = 'delete res resource'
1653        status_code = 204
1654        message = None
1655        array = self.data.array
1656        category = 'cat'
1657        resource_type = 'res'
1658        resource_name = 'name'
1659        with mock.patch.object(self.rest, 'check_status_code_success'):
1660            self.rest.delete_resource(
1661                array, category, resource_type, resource_name)
1662            self.rest.check_status_code_success.assert_called_with(
1663                operation, status_code, message)
1664
1665    def test_delete_resource_failed(self):
1666        array = self.data.array
1667        category = self.data.failed_resource
1668        resource_type = self.data.failed_resource
1669        resource_name = self.data.failed_resource
1670        self.assertRaises(
1671            exception.VolumeBackendAPIException,
1672            self.rest.modify_resource, array, category,
1673            resource_type, resource_name)
1674
1675    def test_get_array_serial(self):
1676        ref_details = self.data.symmetrix[0]
1677        array_details = self.rest.get_array_serial(self.data.array)
1678        self.assertEqual(ref_details, array_details)
1679
1680    def test_get_array_serial_failed(self):
1681        array_details = self.rest.get_array_serial(self.data.failed_resource)
1682        self.assertIsNone(array_details)
1683
1684    def test_get_uni_version(self):
1685        version, major_version = self.rest.get_uni_version()
1686        self.assertEqual('90', major_version)
1687        with mock.patch.object(self.rest, '_get_request', return_value=None):
1688            version, major_version = self.rest.get_uni_version()
1689            self.assertIsNone(major_version)
1690
1691    def test_get_srp_by_name(self):
1692        ref_details = self.data.srp_details
1693        srp_details = self.rest.get_srp_by_name(
1694            self.data.array, self.data.srp)
1695        self.assertEqual(ref_details, srp_details)
1696
1697    def test_get_slo_list_powermax(self):
1698        ref_settings = self.data.powermax_slo_details['sloId']
1699        slo_settings = self.rest.get_slo_list(self.data.array)
1700        self.assertEqual(ref_settings, slo_settings)
1701
1702    def test_get_slo_list_vmax(self):
1703        ref_settings = ['Diamond']
1704        with mock.patch.object(self.rest, 'get_resource',
1705                               return_value=self.data.vmax_slo_details):
1706            slo_settings = self.rest.get_slo_list(self.data.array)
1707            self.assertEqual(ref_settings, slo_settings)
1708
1709    def test_get_workload_settings(self):
1710        ref_settings = self.data.workloadtype['workloadId']
1711        wl_settings = self.rest.get_workload_settings(
1712            self.data.array)
1713        self.assertEqual(ref_settings, wl_settings)
1714
1715    def test_get_workload_settings_next_gen(self):
1716        with mock.patch.object(self.rest, 'is_next_gen_array',
1717                               return_value=True):
1718            wl_settings = self.rest.get_workload_settings(
1719                self.data.array_herc)
1720            self.assertEqual(['None'], wl_settings)
1721
1722    def test_get_workload_settings_failed(self):
1723        wl_settings = self.rest.get_workload_settings(
1724            self.data.failed_resource)
1725        self.assertEqual([], wl_settings)
1726
1727    def test_is_compression_capable_true(self):
1728        compr_capable = self.rest.is_compression_capable('000197800128')
1729        self.assertTrue(compr_capable)
1730
1731    def test_is_compression_capable_false(self):
1732        compr_capable = self.rest.is_compression_capable(self.data.array)
1733        self.assertFalse(compr_capable)
1734        with mock.patch.object(self.rest, 'request', return_value=(200, {})):
1735            compr_capable = self.rest.is_compression_capable(self.data.array)
1736            self.assertFalse(compr_capable)
1737
1738    def test_get_storage_group(self):
1739        ref_details = self.data.sg_details[0]
1740        sg_details = self.rest.get_storage_group(
1741            self.data.array, self.data.defaultstoragegroup_name)
1742        self.assertEqual(ref_details, sg_details)
1743
1744    def test_create_storage_group(self):
1745        with mock.patch.object(self.rest, 'create_resource'):
1746            payload = {'someKey': 'someValue'}
1747            self.rest._create_storagegroup(self.data.array, payload)
1748            self.rest.create_resource.assert_called_once_with(
1749                self.data.array, 'sloprovisioning', 'storagegroup', payload)
1750
1751    def test_create_storage_group_success(self):
1752        sg_name = self.rest.create_storage_group(
1753            self.data.array, self.data.storagegroup_name_f, self.data.srp,
1754            self.data.slo, self.data.workload, self.data.extra_specs)
1755        self.assertEqual(self.data.storagegroup_name_f, sg_name)
1756
1757    def test_create_storage_group_next_gen(self):
1758        with mock.patch.object(self.rest, 'is_next_gen_array',
1759                               return_value=True):
1760            with mock.patch.object(self.rest, '_create_storagegroup',
1761                                   return_value=(200, self.data.job_list[0])):
1762                self.rest.create_storage_group(
1763                    self.data.array, self.data.storagegroup_name_f,
1764                    self.data.srp, self.data.slo, self.data.workload,
1765                    self.data.extra_specs)
1766                payload = {"srpId": self.data.srp,
1767                           "storageGroupId": self.data.storagegroup_name_f,
1768                           "emulation": "FBA",
1769                           "sloBasedStorageGroupParam": [
1770                               {"num_of_vols": 0,
1771                                "sloId": self.data.slo,
1772                                "workloadSelection": 'NONE',
1773                                "volumeAttribute": {
1774                                    "volume_size": "0",
1775                                    "capacityUnit": "GB"}}]}
1776                self.rest._create_storagegroup.assert_called_once_with(
1777                    self.data.array, payload)
1778
1779    def test_create_storage_group_failed(self):
1780        self.assertRaises(
1781            exception.VolumeBackendAPIException,
1782            self.rest.create_storage_group, self.data.array,
1783            self.data.failed_resource, self.data.srp, self.data.slo,
1784            self.data.workload, self.data.extra_specs)
1785
1786    def test_create_storage_group_no_slo(self):
1787        sg_name = self.rest.create_storage_group(
1788            self.data.array, self.data.default_sg_no_slo, self.data.srp,
1789            None, None, self.data.extra_specs)
1790        self.assertEqual(self.data.default_sg_no_slo, sg_name)
1791
1792    def test_create_storage_group_compression_disabled(self):
1793        with mock.patch.object(self.rest, '_create_storagegroup',
1794                               return_value=(200, self.data.job_list[0])):
1795            self.rest.create_storage_group(
1796                self.data.array, self.data.default_sg_compr_disabled,
1797                self.data.srp, self.data.slo, self.data.workload,
1798                self.data.extra_specs, True)
1799            payload = {"srpId": self.data.srp,
1800                       "storageGroupId": self.data.default_sg_compr_disabled,
1801                       "emulation": "FBA",
1802                       "sloBasedStorageGroupParam": [
1803                           {"num_of_vols": 0,
1804                            "sloId": self.data.slo,
1805                            "workloadSelection": self.data.workload,
1806                            "volumeAttribute": {
1807                                "volume_size": "0",
1808                                "capacityUnit": "GB"},
1809                            "noCompression": "true"}]}
1810            self.rest._create_storagegroup.assert_called_once_with(
1811                self.data.array, payload)
1812
1813    def test_modify_storage_group(self):
1814        array = self.data.array
1815        storagegroup = self.data.defaultstoragegroup_name
1816        payload = {'someKey': 'someValue'}
1817        version = self.data.u4v_version
1818        with mock.patch.object(self.rest, 'modify_resource'):
1819            self.rest.modify_storage_group(array, storagegroup, payload)
1820            self.rest.modify_resource.assert_called_once_with(
1821                self.data.array, 'sloprovisioning', 'storagegroup',
1822                payload, version, resource_name=storagegroup)
1823
1824    def test_create_volume_from_sg_success(self):
1825        volume_name = self.data.volume_details[0]['volume_identifier']
1826        ref_dict = self.data.provider_location
1827        volume_dict = self.rest.create_volume_from_sg(
1828            self.data.array, volume_name, self.data.defaultstoragegroup_name,
1829            self.data.test_volume.size, self.data.extra_specs)
1830        self.assertEqual(ref_dict, volume_dict)
1831
1832    def test_create_volume_from_sg_failed(self):
1833        volume_name = self.data.volume_details[0]['volume_identifier']
1834        self.assertRaises(
1835            exception.VolumeBackendAPIException,
1836            self.rest.create_volume_from_sg, self.data.array,
1837            volume_name, self.data.failed_resource,
1838            self.data.test_volume.size, self.data.extra_specs)
1839
1840    def test_create_volume_from_sg_cannot_retrieve_device_id(self):
1841        with mock.patch.object(self.rest, 'find_volume_device_id',
1842                               return_value=None):
1843            volume_name = self.data.volume_details[0]['volume_identifier']
1844            self.assertRaises(
1845                exception.VolumeBackendAPIException,
1846                self.rest.create_volume_from_sg, self.data.array,
1847                volume_name, self.data.failed_resource,
1848                self.data.test_volume.size, self.data.extra_specs)
1849
1850    def test_add_vol_to_sg_success(self):
1851        operation = 'Add volume to sg'
1852        status_code = 202
1853        message = self.data.job_list[0]
1854        with mock.patch.object(self.rest, 'wait_for_job'):
1855            device_id = self.data.device_id
1856            self.rest.add_vol_to_sg(
1857                self.data.array, self.data.storagegroup_name_f, device_id,
1858                self.data.extra_specs)
1859            self.rest.wait_for_job.assert_called_with(
1860                operation, status_code, message, self.data.extra_specs)
1861
1862    def test_add_vol_to_sg_failed(self):
1863        device_id = [self.data.device_id]
1864        self.assertRaises(
1865            exception.VolumeBackendAPIException,
1866            self.rest.add_vol_to_sg, self.data.array,
1867            self.data.failed_resource, device_id,
1868            self.data.extra_specs)
1869
1870    def test_remove_vol_from_sg_success(self):
1871        operation = 'Remove vol from sg'
1872        status_code = 202
1873        message = self.data.job_list[0]
1874        with mock.patch.object(self.rest, 'wait_for_job'):
1875            device_id = self.data.device_id
1876            self.rest.remove_vol_from_sg(
1877                self.data.array, self.data.storagegroup_name_f, device_id,
1878                self.data.extra_specs)
1879            self.rest.wait_for_job.assert_called_with(
1880                operation, status_code, message, self.data.extra_specs)
1881
1882    @mock.patch.object(time, 'sleep')
1883    def test_remove_vol_from_sg_failed(self, mock_sleep):
1884        device_id = [self.data.volume_details[0]['volumeId']]
1885        self.assertRaises(
1886            exception.VolumeBackendAPIException,
1887            self.rest.remove_vol_from_sg, self.data.array,
1888            self.data.failed_resource, device_id,
1889            self.data.extra_specs)
1890
1891    def test_get_vmax_default_storage_group(self):
1892        ref_storage_group = self.data.sg_details[0]
1893        ref_sg_name = self.data.defaultstoragegroup_name
1894        storagegroup, storagegroup_name = (
1895            self.rest.get_vmax_default_storage_group(
1896                self.data.array, self.data.srp,
1897                self.data.slo, self.data.workload))
1898        self.assertEqual(ref_sg_name, storagegroup_name)
1899        self.assertEqual(ref_storage_group, storagegroup)
1900
1901    def test_get_vmax_default_storage_group_next_gen(self):
1902        with mock.patch.object(self.rest, 'is_next_gen_array',
1903                               return_value=True):
1904            __, storagegroup_name = self.rest.get_vmax_default_storage_group(
1905                self.data.array, self.data.srp,
1906                self.data.slo, self.data.workload)
1907            self.assertEqual('OS-SRP_1-Diamond-NONE-SG', storagegroup_name)
1908
1909    def test_delete_storage_group(self):
1910        operation = 'delete storagegroup resource'
1911        status_code = 204
1912        message = None
1913        with mock.patch.object(self.rest, 'check_status_code_success'):
1914            self.rest.delete_storage_group(
1915                self.data.array, self.data.storagegroup_name_f)
1916            self.rest.check_status_code_success.assert_called_with(
1917                operation, status_code, message)
1918
1919    def test_is_child_sg_in_parent_sg(self):
1920        is_child1 = self.rest.is_child_sg_in_parent_sg(
1921            self.data.array, self.data.storagegroup_name_f,
1922            self.data.parent_sg_f)
1923        is_child2 = self.rest.is_child_sg_in_parent_sg(
1924            self.data.array, self.data.defaultstoragegroup_name,
1925            self.data.parent_sg_f)
1926        self.assertTrue(is_child1)
1927        self.assertFalse(is_child2)
1928
1929    def test_add_child_sg_to_parent_sg(self):
1930        payload = {"editStorageGroupActionParam": {
1931            "expandStorageGroupParam": {
1932                "addExistingStorageGroupParam": {
1933                    "storageGroupId": [self.data.storagegroup_name_f]}}}}
1934        with mock.patch.object(self.rest, 'modify_storage_group',
1935                               return_value=(202, self.data.job_list[0])):
1936            self.rest.add_child_sg_to_parent_sg(
1937                self.data.array, self.data.storagegroup_name_f,
1938                self.data.parent_sg_f, self.data.extra_specs)
1939            self.rest.modify_storage_group.assert_called_once_with(
1940                self.data.array, self.data.parent_sg_f, payload)
1941
1942    def test_remove_child_sg_from_parent_sg(self):
1943        payload = {"editStorageGroupActionParam": {
1944            "removeStorageGroupParam": {
1945                "storageGroupId": [self.data.storagegroup_name_f],
1946                "force": 'true'}}}
1947        with mock.patch.object(self.rest, 'modify_storage_group',
1948                               return_value=(202, self.data.job_list[0])):
1949            self.rest.remove_child_sg_from_parent_sg(
1950                self.data.array, self.data.storagegroup_name_f,
1951                self.data.parent_sg_f, self.data.extra_specs)
1952            self.rest.modify_storage_group.assert_called_once_with(
1953                self.data.array, self.data.parent_sg_f, payload)
1954
1955    def test_get_volume_list(self):
1956        ref_volumes = [self.data.device_id, self.data.device_id2]
1957        volumes = self.rest.get_volume_list(self.data.array, {})
1958        self.assertEqual(ref_volumes, volumes)
1959
1960    def test_get_volume(self):
1961        ref_volumes = self.data.volume_details[0]
1962        device_id = self.data.device_id
1963        volumes = self.rest.get_volume(self.data.array, device_id)
1964        self.assertEqual(ref_volumes, volumes)
1965
1966    def test_get_private_volume(self):
1967        device_id = self.data.device_id
1968        ref_volume = self.data.private_vol_details['resultList']['result'][0]
1969        volume = self.rest._get_private_volume(self.data.array, device_id)
1970        self.assertEqual(ref_volume, volume)
1971
1972    def test_get_private_volume_exception(self):
1973        device_id = self.data.device_id
1974        with mock.patch.object(self.rest, 'get_resource',
1975                               return_value={}):
1976            self.assertRaises(exception.VolumeBackendAPIException,
1977                              self.rest._get_private_volume,
1978                              self.data.array, device_id)
1979
1980    def test_modify_volume_success(self):
1981        array = self.data.array
1982        device_id = self.data.device_id
1983        payload = {'someKey': 'someValue'}
1984        with mock.patch.object(self.rest, 'modify_resource'):
1985            self.rest._modify_volume(array, device_id, payload)
1986            self.rest.modify_resource.assert_called_once_with(
1987                self.data.array, 'sloprovisioning', 'volume',
1988                payload, resource_name=device_id)
1989
1990    def test_modify_volume_failed(self):
1991        payload = {'someKey': self.data.failed_resource}
1992        device_id = self.data.device_id
1993        self.assertRaises(
1994            exception.VolumeBackendAPIException,
1995            self.rest._modify_volume, self.data.array,
1996            device_id, payload)
1997
1998    def test_extend_volume(self):
1999        device_id = self.data.device_id
2000        new_size = '3'
2001        extend_vol_payload = {"executionOption": "ASYNCHRONOUS",
2002                              "editVolumeActionParam": {
2003                                  "expandVolumeParam": {
2004                                      "volumeAttribute": {
2005                                          "volume_size": new_size,
2006                                          "capacityUnit": "GB"}}}}
2007        with mock.patch.object(self.rest, '_modify_volume',
2008                               return_value=(202, self.data.job_list[0])):
2009            self.rest.extend_volume(self.data.array, device_id, new_size,
2010                                    self.data.extra_specs)
2011            self.rest._modify_volume.assert_called_once_with(
2012                self.data.array, device_id, extend_vol_payload)
2013
2014    def test_delete_volume(self):
2015        device_id = self.data.device_id
2016        with mock.patch.object(self.rest, 'delete_resource'),\
2017            mock.patch.object(
2018                self.rest, '_modify_volume', side_effect=[
2019                    None, None, None, exception.VolumeBackendAPIException]):
2020                for x in range(0, 2):
2021                    self.rest.delete_volume(self.data.array, device_id)
2022                mod_call_count = self.rest._modify_volume.call_count
2023                self.assertEqual(4, mod_call_count)
2024                self.rest.delete_resource.assert_called_once_with(
2025                    self.data.array, 'sloprovisioning', 'volume', device_id)
2026
2027    def test_rename_volume(self):
2028        device_id = self.data.device_id
2029        payload = {"editVolumeActionParam": {
2030            "modifyVolumeIdentifierParam": {
2031                "volumeIdentifier": {
2032                    "identifier_name": 'new_name',
2033                    "volumeIdentifierChoice": "identifier_name"}}}}
2034        payload2 = {"editVolumeActionParam": {"modifyVolumeIdentifierParam": {
2035            "volumeIdentifier": {"volumeIdentifierChoice": "none"}}}}
2036        with mock.patch.object(self.rest, '_modify_volume') as mock_mod:
2037            self.rest.rename_volume(self.data.array, device_id, 'new_name')
2038            mock_mod.assert_called_once_with(
2039                self.data.array, device_id, payload)
2040            mock_mod.reset_mock()
2041            self.rest.rename_volume(self.data.array, device_id, None)
2042            self.rest._modify_volume.assert_called_once_with(
2043                self.data.array, device_id, payload2)
2044
2045    def test_check_volume_device_id(self):
2046        element_name = self.utils.get_volume_element_name(
2047            self.data.test_volume.id)
2048        found_dev_id = self.rest.check_volume_device_id(
2049            self.data.array, self.data.device_id, element_name)
2050        self.assertEqual(self.data.device_id, found_dev_id)
2051        found_dev_id2 = self.rest.check_volume_device_id(
2052            self.data.array, self.data.device_id3, element_name)
2053        self.assertIsNone(found_dev_id2)
2054
2055    def test_check_volume_device_id_host_migration_case(self):
2056        element_name = self.utils.get_volume_element_name(
2057            self.data.test_clone_volume.id)
2058        found_dev_id = self.rest.check_volume_device_id(
2059            self.data.array, self.data.device_id, element_name,
2060            name_id=self.data.test_clone_volume._name_id)
2061        self.assertEqual(self.data.device_id, found_dev_id)
2062
2063    def test_find_mv_connections_for_vol(self):
2064        device_id = self.data.device_id
2065        ref_lun_id = int((self.data.maskingview[0]['maskingViewConnection']
2066                          [0]['host_lun_address']), 16)
2067        host_lun_id = self.rest.find_mv_connections_for_vol(
2068            self.data.array, self.data.masking_view_name_f, device_id)
2069        self.assertEqual(ref_lun_id, host_lun_id)
2070
2071    def test_find_mv_connections_for_vol_failed(self):
2072        # no masking view info retrieved
2073        device_id = self.data.volume_details[0]['volumeId']
2074        host_lun_id = self.rest.find_mv_connections_for_vol(
2075            self.data.array, self.data.failed_resource, device_id)
2076        self.assertIsNone(host_lun_id)
2077        # no connection info received
2078        with mock.patch.object(self.rest, 'get_resource',
2079                               return_value={'no_conn': 'no_info'}):
2080            host_lun_id2 = self.rest.find_mv_connections_for_vol(
2081                self.data.array, self.data.masking_view_name_f, device_id)
2082            self.assertIsNone(host_lun_id2)
2083
2084    def test_get_storage_groups_from_volume(self):
2085        array = self.data.array
2086        device_id = self.data.device_id
2087        ref_list = self.data.volume_details[0]['storageGroupId']
2088        sg_list = self.rest.get_storage_groups_from_volume(array, device_id)
2089        self.assertEqual(ref_list, sg_list)
2090
2091    def test_get_num_vols_in_sg(self):
2092        num_vol = self.rest.get_num_vols_in_sg(
2093            self.data.array, self.data.defaultstoragegroup_name)
2094        self.assertEqual(2, num_vol)
2095
2096    def test_get_num_vols_in_sg_no_num(self):
2097        with mock.patch.object(self.rest, 'get_storage_group',
2098                               return_value={}):
2099            num_vol = self.rest.get_num_vols_in_sg(
2100                self.data.array, self.data.defaultstoragegroup_name)
2101            self.assertEqual(0, num_vol)
2102
2103    def test_is_volume_in_storagegroup(self):
2104        # True
2105        array = self.data.array
2106        device_id = self.data.device_id
2107        storagegroup = self.data.defaultstoragegroup_name
2108        is_vol1 = self.rest.is_volume_in_storagegroup(
2109            array, device_id, storagegroup)
2110        # False
2111        with mock.patch.object(self.rest, 'get_storage_groups_from_volume',
2112                               return_value=[]):
2113            is_vol2 = self.rest.is_volume_in_storagegroup(
2114                array, device_id, storagegroup)
2115        self.assertTrue(is_vol1)
2116        self.assertFalse(is_vol2)
2117
2118    def test_find_volume_device_number(self):
2119        array = self.data.array
2120        volume_name = self.data.volume_details[0]['volume_identifier']
2121        ref_device = self.data.device_id
2122        device_number = self.rest.find_volume_device_id(array, volume_name)
2123        self.assertEqual(ref_device, device_number)
2124
2125    def test_find_volume_device_number_failed(self):
2126        array = self.data.array
2127        with mock.patch.object(self.rest, 'get_volume_list',
2128                               return_value=[]):
2129            device_number = self.rest.find_volume_device_id(
2130                array, 'name')
2131            self.assertIsNone(device_number)
2132
2133    def test_get_volume_success(self):
2134        array = self.data.array
2135        device_id = self.data.device_id
2136        ref_volume = self.data.volume_details[0]
2137        volume = self.rest.get_volume(array, device_id)
2138        self.assertEqual(ref_volume, volume)
2139
2140    def test_get_volume_failed(self):
2141        array = self.data.array
2142        device_id = self.data.failed_resource
2143        self.assertRaises(exception.VolumeBackendAPIException,
2144                          self.rest.get_volume,
2145                          array, device_id)
2146
2147    def test_find_volume_identifier(self):
2148        array = self.data.array
2149        device_id = self.data.device_id
2150        ref_name = self.data.volume_details[0]['volume_identifier']
2151        vol_name = self.rest.find_volume_identifier(array, device_id)
2152        self.assertEqual(ref_name, vol_name)
2153
2154    def test_get_volume_size(self):
2155        array = self.data.array
2156        device_id = self.data.device_id
2157        ref_size = self.data.test_volume.size
2158        size = self.rest.get_size_of_device_on_array(array, device_id)
2159        self.assertEqual(ref_size, size)
2160
2161    def test_get_volume_size_exception(self):
2162        array = self.data.array
2163        device_id = self.data.device_id
2164        with mock.patch.object(self.rest, 'get_volume',
2165                               return_value=None):
2166            size = self.rest.get_size_of_device_on_array(
2167                array, device_id)
2168            self.assertIsNone(size)
2169
2170    def test_get_portgroup(self):
2171        array = self.data.array
2172        pg_name = self.data.port_group_name_f
2173        ref_pg = self.data.portgroup[0]
2174        portgroup = self.rest.get_portgroup(array, pg_name)
2175        self.assertEqual(ref_pg, portgroup)
2176
2177    def test_get_port_ids(self):
2178        array = self.data.array
2179        pg_name = self.data.port_group_name_f
2180        ref_ports = ["FA-1D:4"]
2181        port_ids = self.rest.get_port_ids(array, pg_name)
2182        self.assertEqual(ref_ports, port_ids)
2183
2184    def test_get_port_ids_no_portgroup(self):
2185        array = self.data.array
2186        pg_name = self.data.port_group_name_f
2187        with mock.patch.object(self.rest, 'get_portgroup',
2188                               return_value=None):
2189            port_ids = self.rest.get_port_ids(array, pg_name)
2190            self.assertEqual([], port_ids)
2191
2192    def test_get_port(self):
2193        array = self.data.array
2194        port_id = "FA-1D:4"
2195        ref_port = self.data.port_list[0]
2196        port = self.rest.get_port(array, port_id)
2197        self.assertEqual(ref_port, port)
2198
2199    def test_get_iscsi_ip_address_and_iqn(self):
2200        array = self.data.array
2201        port_id = "SE-4E:0"
2202        ref_ip = [self.data.ip]
2203        ref_iqn = self.data.initiator
2204        ip_addresses, iqn = self.rest.get_iscsi_ip_address_and_iqn(
2205            array, port_id)
2206        self.assertEqual(ref_ip, ip_addresses)
2207        self.assertEqual(ref_iqn, iqn)
2208
2209    def test_get_iscsi_ip_address_and_iqn_no_port(self):
2210        array = self.data.array
2211        port_id = "SE-4E:0"
2212        with mock.patch.object(self.rest, 'get_port', return_value=None):
2213            ip_addresses, iqn = self.rest.get_iscsi_ip_address_and_iqn(
2214                array, port_id)
2215            self.assertIsNone(ip_addresses)
2216            self.assertIsNone(iqn)
2217
2218    def test_get_target_wwns(self):
2219        array = self.data.array
2220        pg_name = self.data.port_group_name_f
2221        ref_wwns = [self.data.wwnn1]
2222        target_wwns = self.rest.get_target_wwns(array, pg_name)
2223        self.assertEqual(ref_wwns, target_wwns)
2224
2225    def test_get_target_wwns_failed(self):
2226        array = self.data.array
2227        pg_name = self.data.port_group_name_f
2228        with mock.patch.object(self.rest, 'get_port',
2229                               return_value=None):
2230            target_wwns = self.rest.get_target_wwns(array, pg_name)
2231            self.assertEqual([], target_wwns)
2232
2233    def test_get_initiator_group(self):
2234        array = self.data.array
2235        ig_name = self.data.initiatorgroup_name_f
2236        ref_ig = self.data.inititiatorgroup[0]
2237        response_ig = self.rest.get_initiator_group(array, ig_name)
2238        self.assertEqual(ref_ig, response_ig)
2239
2240    def test_get_initiator(self):
2241        array = self.data.array
2242        initiator_name = self.data.initiator
2243        ref_initiator = self.data.initiator_list[1]
2244        response_initiator = self.rest.get_initiator(array, initiator_name)
2245        self.assertEqual(ref_initiator, response_initiator)
2246
2247    def test_get_initiator_list(self):
2248        array = self.data.array
2249        with mock.patch.object(self.rest, 'get_resource',
2250                               return_value={'initiatorId': '1234'}):
2251            init_list = self.rest.get_initiator_list(array)
2252            self.assertIsNotNone(init_list)
2253
2254    def test_get_initiator_list_none(self):
2255        array = self.data.array
2256        with mock.patch.object(self.rest, 'get_resource', return_value={}):
2257            init_list = self.rest.get_initiator_list(array)
2258            self.assertEqual([], init_list)
2259
2260    def test_get_initiator_group_from_initiator(self):
2261        initiator = self.data.wwpn1
2262        ref_group = self.data.initiatorgroup_name_f
2263        init_group = self.rest.get_initiator_group_from_initiator(
2264            self.data.array, initiator)
2265        self.assertEqual(ref_group, init_group)
2266
2267    def test_get_initiator_group_from_initiator_failed(self):
2268        initiator = self.data.wwpn1
2269        with mock.patch.object(self.rest, 'get_initiator',
2270                               return_value=None):
2271            init_group = self.rest.get_initiator_group_from_initiator(
2272                self.data.array, initiator)
2273            self.assertIsNone(init_group)
2274        with mock.patch.object(self.rest, 'get_initiator',
2275                               return_value={'name': 'no_host'}):
2276            init_group = self.rest.get_initiator_group_from_initiator(
2277                self.data.array, initiator)
2278            self.assertIsNone(init_group)
2279
2280    def test_create_initiator_group(self):
2281        init_group_name = self.data.initiatorgroup_name_f
2282        init_list = [self.data.wwpn1]
2283        extra_specs = self.data.extra_specs
2284        with mock.patch.object(self.rest, 'create_resource',
2285                               return_value=(202, self.data.job_list[0])):
2286            payload = ({"executionOption": "ASYNCHRONOUS",
2287                        "hostId": init_group_name, "initiatorId": init_list})
2288            self.rest.create_initiator_group(
2289                self.data.array, init_group_name, init_list, extra_specs)
2290            self.rest.create_resource.assert_called_once_with(
2291                self.data.array, 'sloprovisioning', 'host', payload)
2292
2293    def test_delete_initiator_group(self):
2294        with mock.patch.object(self.rest, 'delete_resource'):
2295            self.rest.delete_initiator_group(
2296                self.data.array, self.data.initiatorgroup_name_f)
2297            self.rest.delete_resource.assert_called_once_with(
2298                self.data.array, 'sloprovisioning', 'host',
2299                self.data.initiatorgroup_name_f)
2300
2301    def test_get_masking_view(self):
2302        array = self.data.array
2303        masking_view_name = self.data.masking_view_name_f
2304        ref_mask_view = self.data.maskingview[0]
2305        masking_view = self.rest.get_masking_view(array, masking_view_name)
2306        self.assertEqual(ref_mask_view, masking_view)
2307
2308    def test_get_masking_views_from_storage_group(self):
2309        array = self.data.array
2310        storagegroup_name = self.data.storagegroup_name_f
2311        ref_mask_view = [self.data.masking_view_name_f]
2312        masking_view = self.rest.get_masking_views_from_storage_group(
2313            array, storagegroup_name)
2314        self.assertEqual(ref_mask_view, masking_view)
2315
2316    def test_get_masking_views_by_initiator_group(self):
2317        array = self.data.array
2318        initiatorgroup_name = self.data.initiatorgroup_name_f
2319        ref_mask_view = [self.data.masking_view_name_f]
2320        masking_view = self.rest.get_masking_views_by_initiator_group(
2321            array, initiatorgroup_name)
2322        self.assertEqual(ref_mask_view, masking_view)
2323
2324    def test_get_masking_views_by_initiator_group_failed(self):
2325        array = self.data.array
2326        initiatorgroup_name = self.data.initiatorgroup_name_f
2327        with mock.patch.object(self.rest, 'get_initiator_group',
2328                               return_value=None):
2329            masking_view = self.rest.get_masking_views_by_initiator_group(
2330                array, initiatorgroup_name)
2331            self.assertEqual([], masking_view)
2332        with mock.patch.object(self.rest, 'get_initiator_group',
2333                               return_value={'name': 'no_mv'}):
2334            masking_view = self.rest.get_masking_views_by_initiator_group(
2335                array, initiatorgroup_name)
2336            self.assertEqual([], masking_view)
2337
2338    def test_get_element_from_masking_view(self):
2339        array = self.data.array
2340        maskingview_name = self.data.masking_view_name_f
2341        # storage group
2342        ref_sg = self.data.storagegroup_name_f
2343        storagegroup = self.rest.get_element_from_masking_view(
2344            array, maskingview_name, storagegroup=True)
2345        self.assertEqual(ref_sg, storagegroup)
2346        # initiator group
2347        ref_ig = self.data.initiatorgroup_name_f
2348        initiatorgroup = self.rest.get_element_from_masking_view(
2349            array, maskingview_name, host=True)
2350        self.assertEqual(ref_ig, initiatorgroup)
2351        # portgroup
2352        ref_pg = self.data.port_group_name_f
2353        portgroup = self.rest.get_element_from_masking_view(
2354            array, maskingview_name, portgroup=True)
2355        self.assertEqual(ref_pg, portgroup)
2356
2357    def test_get_element_from_masking_view_failed(self):
2358        array = self.data.array
2359        maskingview_name = self.data.masking_view_name_f
2360        # no element chosen
2361        element = self.rest.get_element_from_masking_view(
2362            array, maskingview_name)
2363        self.assertIsNone(element)
2364        # cannot retrieve maskingview
2365        with mock.patch.object(self.rest, 'get_masking_view',
2366                               return_value=None):
2367            self.assertRaises(exception.VolumeBackendAPIException,
2368                              self.rest.get_element_from_masking_view,
2369                              array, maskingview_name)
2370
2371    def test_get_common_masking_views(self):
2372        array = self.data.array
2373        initiatorgroup = self.data.initiatorgroup_name_f
2374        portgroup = self.data.port_group_name_f
2375        ref_maskingview = self.data.masking_view_name_f
2376        maskingview_list = self.rest.get_common_masking_views(
2377            array, portgroup, initiatorgroup)
2378        self.assertEqual(ref_maskingview, maskingview_list)
2379
2380    def test_get_common_masking_views_none(self):
2381        array = self.data.array
2382        initiatorgroup = self.data.initiatorgroup_name_f
2383        portgroup = self.data.port_group_name_f
2384        with mock.patch.object(self.rest, 'get_masking_view_list',
2385                               return_value=[]):
2386            maskingview_list = self.rest.get_common_masking_views(
2387                array, portgroup, initiatorgroup)
2388            self.assertEqual([], maskingview_list)
2389
2390    def test_create_masking_view(self):
2391        maskingview_name = self.data.masking_view_name_f
2392        storagegroup_name = self.data.storagegroup_name_f
2393        port_group_name = self.data.port_group_name_f
2394        init_group_name = self.data.initiatorgroup_name_f
2395        extra_specs = self.data.extra_specs
2396        with mock.patch.object(self.rest, 'create_resource',
2397                               return_value=(202, self.data.job_list[0])):
2398            payload = ({"executionOption": "ASYNCHRONOUS",
2399                        "portGroupSelection": {
2400                            "useExistingPortGroupParam": {
2401                                "portGroupId": port_group_name}},
2402                        "maskingViewId": maskingview_name,
2403                        "hostOrHostGroupSelection": {
2404                            "useExistingHostParam": {
2405                                "hostId": init_group_name}},
2406                        "storageGroupSelection": {
2407                            "useExistingStorageGroupParam": {
2408                                "storageGroupId": storagegroup_name}}})
2409            self.rest.create_masking_view(
2410                self.data.array, maskingview_name, storagegroup_name,
2411                port_group_name, init_group_name, extra_specs)
2412            self.rest.create_resource.assert_called_once_with(
2413                self.data.array, 'sloprovisioning', 'maskingview', payload)
2414
2415    def test_delete_masking_view(self):
2416        with mock.patch.object(self.rest, 'delete_resource'):
2417            self.rest.delete_masking_view(
2418                self.data.array, self.data.masking_view_name_f)
2419            self.rest.delete_resource.assert_called_once_with(
2420                self.data.array, 'sloprovisioning', 'maskingview',
2421                self.data.masking_view_name_f)
2422
2423    def test_get_replication_capabilities(self):
2424        ref_response = self.data.capabilities['symmetrixCapability'][1]
2425        capabilities = self.rest.get_replication_capabilities(self.data.array)
2426        self.assertEqual(ref_response, capabilities)
2427
2428    def test_is_clone_licenced(self):
2429        licence = self.rest.is_snapvx_licensed(self.data.array)
2430        self.assertTrue(licence)
2431        false_response = {'rdfCapable': True,
2432                          'snapVxCapable': False,
2433                          'symmetrixId': '000197800123'}
2434        with mock.patch.object(self.rest, 'get_replication_capabilities',
2435                               return_value=false_response):
2436            licence2 = self.rest.is_snapvx_licensed(self.data.array)
2437            self.assertFalse(licence2)
2438
2439    def test_is_clone_licenced_error(self):
2440        with mock.patch.object(self.rest, 'get_replication_capabilities',
2441                               return_value=None):
2442            licence3 = self.rest.is_snapvx_licensed(self.data.array)
2443            self.assertFalse(licence3)
2444
2445    def test_create_volume_snap(self):
2446        snap_name = (self.data.volume_snap_vx
2447                     ['snapshotSrcs'][0]['snapshotName'])
2448        device_id = self.data.device_id
2449        extra_specs = self.data.extra_specs
2450        payload = {"deviceNameListSource": [{"name": device_id}],
2451                   "bothSides": 'false', "star": 'false',
2452                   "force": 'false'}
2453        resource_type = 'snapshot/%(snap)s' % {'snap': snap_name}
2454        with mock.patch.object(self.rest, 'create_resource',
2455                               return_value=(202, self.data.job_list[0])):
2456            self.rest.create_volume_snap(
2457                self.data.array, snap_name, device_id, extra_specs)
2458            self.rest.create_resource.assert_called_once_with(
2459                self.data.array, 'replication', resource_type,
2460                payload, private='/private')
2461
2462    def test_modify_volume_snap(self):
2463        array = self.data.array
2464        source_id = self.data.device_id
2465        target_id = (self.data.volume_snap_vx
2466                     ['snapshotSrcs'][0]['linkedDevices'][0]['targetDevice'])
2467        snap_name = (self.data.volume_snap_vx
2468                     ['snapshotSrcs'][0]['snapshotName'])
2469        extra_specs = self.data.extra_specs
2470        payload = {"deviceNameListSource": [{"name": source_id}],
2471                   "deviceNameListTarget": [
2472                       {"name": target_id}],
2473                   "copy": 'true', "action": "",
2474                   "star": 'false', "force": 'false',
2475                   "exact": 'false', "remote": 'false',
2476                   "symforce": 'false', "nocopy": 'false'}
2477        payload_restore = {"deviceNameListSource": [{"name": source_id}],
2478                           "deviceNameListTarget": [{"name": source_id}],
2479                           "action": "Restore",
2480                           "star": 'false', "force": 'false'}
2481        with mock.patch.object(
2482            self.rest, 'modify_resource', return_value=(
2483                202, self.data.job_list[0])) as mock_modify:
2484            # link
2485            payload["action"] = "Link"
2486            self.rest.modify_volume_snap(
2487                array, source_id, target_id, snap_name, extra_specs, link=True)
2488            self.rest.modify_resource.assert_called_once_with(
2489                array, 'replication', 'snapshot', payload,
2490                resource_name=snap_name, private='/private')
2491            # unlink
2492            mock_modify.reset_mock()
2493            payload["action"] = "Unlink"
2494            self.rest.modify_volume_snap(
2495                array, source_id, target_id, snap_name,
2496                extra_specs, unlink=True)
2497            self.rest.modify_resource.assert_called_once_with(
2498                array, 'replication', 'snapshot', payload,
2499                resource_name=snap_name, private='/private')
2500            # restore
2501            mock_modify.reset_mock()
2502            payload["action"] = "Restore"
2503            self.rest.modify_volume_snap(
2504                array, source_id, "", snap_name,
2505                extra_specs, unlink=False, restore=True)
2506            self.rest.modify_resource.assert_called_once_with(
2507                array, 'replication', 'snapshot', payload_restore,
2508                resource_name=snap_name, private='/private')
2509            # link or unlink, list of volumes
2510            mock_modify.reset_mock()
2511            payload["action"] = "Link"
2512            self.rest.modify_volume_snap(
2513                array, "", "", snap_name,
2514                extra_specs, unlink=False, link=True,
2515                list_volume_pairs=[(source_id, target_id)])
2516            self.rest.modify_resource.assert_called_once_with(
2517                array, 'replication', 'snapshot', payload,
2518                resource_name=snap_name, private='/private')
2519            # none selected
2520            mock_modify.reset_mock()
2521            self.rest.modify_volume_snap(
2522                array, source_id, target_id, snap_name,
2523                extra_specs)
2524            self.rest.modify_resource.assert_not_called()
2525
2526    def test_delete_volume_snap(self):
2527        array = self.data.array
2528        snap_name = (self.data.volume_snap_vx
2529                     ['snapshotSrcs'][0]['snapshotName'])
2530        source_device_id = self.data.device_id
2531        payload = {"deviceNameListSource": [{"name": source_device_id}]}
2532        with mock.patch.object(self.rest, 'delete_resource'):
2533            self.rest.delete_volume_snap(array, snap_name, source_device_id)
2534            self.rest.delete_resource.assert_called_once_with(
2535                array, 'replication', 'snapshot', snap_name,
2536                payload=payload, private='/private')
2537
2538    def test_delete_volume_snap_restore(self):
2539        array = self.data.array
2540        snap_name = (self.data.volume_snap_vx
2541                     ['snapshotSrcs'][0]['snapshotName'])
2542        source_device_id = self.data.device_id
2543        payload = {"deviceNameListSource": [{"name": source_device_id}],
2544                   "restore": True}
2545        with mock.patch.object(self.rest, 'delete_resource'):
2546            self.rest.delete_volume_snap(
2547                array, snap_name, source_device_id, restored=True)
2548            self.rest.delete_resource.assert_called_once_with(
2549                array, 'replication', 'snapshot', snap_name,
2550                payload=payload, private='/private')
2551
2552    def test_get_volume_snap_info(self):
2553        array = self.data.array
2554        source_device_id = self.data.device_id
2555        ref_snap_info = self.data.volume_snap_vx
2556        snap_info = self.rest.get_volume_snap_info(array, source_device_id)
2557        self.assertEqual(ref_snap_info, snap_info)
2558
2559    def test_get_volume_snap(self):
2560        array = self.data.array
2561        snap_name = (self.data.volume_snap_vx
2562                     ['snapshotSrcs'][0]['snapshotName'])
2563        device_id = self.data.device_id
2564        ref_snap = self.data.volume_snap_vx['snapshotSrcs'][0]
2565        snap = self.rest.get_volume_snap(array, device_id, snap_name)
2566        self.assertEqual(ref_snap, snap)
2567
2568    def test_get_volume_snap_none(self):
2569        array = self.data.array
2570        snap_name = (self.data.volume_snap_vx
2571                     ['snapshotSrcs'][0]['snapshotName'])
2572        device_id = self.data.device_id
2573        with mock.patch.object(self.rest, 'get_volume_snap_info',
2574                               return_value=None):
2575            snap = self.rest.get_volume_snap(array, device_id, snap_name)
2576            self.assertIsNone(snap)
2577        with mock.patch.object(self.rest, 'get_volume_snap_info',
2578                               return_value={'snapshotSrcs': []}):
2579            snap = self.rest.get_volume_snap(array, device_id, snap_name)
2580            self.assertIsNone(snap)
2581
2582    def test_get_sync_session(self):
2583        array = self.data.array
2584        source_id = self.data.device_id
2585        target_id = (self.data.volume_snap_vx
2586                     ['snapshotSrcs'][0]['linkedDevices'][0]['targetDevice'])
2587        snap_name = (self.data.volume_snap_vx
2588                     ['snapshotSrcs'][0]['snapshotName'])
2589        ref_sync = (self.data.volume_snap_vx
2590                    ['snapshotSrcs'][0]['linkedDevices'][0])
2591        sync = self.rest.get_sync_session(
2592            array, source_id, snap_name, target_id)
2593        self.assertEqual(ref_sync, sync)
2594
2595    def test_find_snap_vx_sessions(self):
2596        array = self.data.array
2597        source_id = self.data.device_id
2598        ref_sessions = [{'snap_name': 'temp-1',
2599                         'source_vol': self.data.device_id,
2600                         'target_vol_list': [self.data.device_id2]},
2601                        {'snap_name': 'temp-1',
2602                         'source_vol': self.data.device_id,
2603                         'target_vol_list': [self.data.device_id2]}]
2604        sessions = self.rest.find_snap_vx_sessions(array, source_id)
2605        self.assertEqual(ref_sessions, sessions)
2606
2607    def test_find_snap_vx_sessions_tgt_only(self):
2608        array = self.data.array
2609        source_id = self.data.device_id
2610        ref_sessions = [{'snap_name': 'temp-1',
2611                         'source_vol': self.data.device_id,
2612                         'target_vol_list': [self.data.device_id2]}]
2613        sessions = self.rest.find_snap_vx_sessions(
2614            array, source_id, tgt_only=True)
2615        self.assertEqual(ref_sessions, sessions)
2616
2617    def test_update_storagegroup_qos(self):
2618        sg_qos = {"srp": self.data.srp, "num_of_vols": 2, "cap_gb": 2,
2619                  "storageGroupId": "OS-QOS-SG",
2620                  "slo": self.data.slo, "workload": self.data.workload,
2621                  "hostIOLimit": {"host_io_limit_io_sec": "4000",
2622                                  "dynamicDistribution": "Always",
2623                                  "host_io_limit_mb_sec": "4000"}}
2624        self.data.sg_details.append(sg_qos)
2625        array = self.data.array
2626        extra_specs = self.data.extra_specs
2627        extra_specs['qos'] = {
2628            'total_iops_sec': '4000', 'DistributionType': 'Always'}
2629        return_value = self.rest.update_storagegroup_qos(
2630            array, "OS-QOS-SG", extra_specs)
2631        self.assertEqual(False, return_value)
2632        extra_specs['qos'] = {
2633            'DistributionType': 'onFailure', 'total_bytes_sec': '419430400'}
2634        return_value = self.rest.update_storagegroup_qos(
2635            array, "OS-QOS-SG", extra_specs)
2636        self.assertTrue(return_value)
2637
2638    def test_update_storagegroup_qos_exception(self):
2639        array = self.data.array
2640        storage_group = self.data.defaultstoragegroup_name
2641        extra_specs = self.data.extra_specs
2642        extra_specs['qos'] = {
2643            'total_iops_sec': '4000', 'DistributionType': 'Wrong',
2644            'total_bytes_sec': '4194304000'}
2645        with mock.patch.object(self.rest, 'check_status_code_success',
2646                               side_effect=[None, None, None, Exception]):
2647            self.assertRaises(exception.VolumeBackendAPIException,
2648                              self.rest.update_storagegroup_qos, array,
2649                              storage_group, extra_specs)
2650            extra_specs['qos']['DistributionType'] = 'Always'
2651            return_value = self.rest.update_storagegroup_qos(
2652                array, "OS-QOS-SG", extra_specs)
2653            self.assertFalse(return_value)
2654
2655    def test_validate_qos_input_exception(self):
2656        qos_extra_spec = {
2657            'total_iops_sec': 90, 'DistributionType': 'Wrong',
2658            'total_bytes_sec': 100}
2659        input_key = 'total_iops_sec'
2660        sg_value = 4000
2661        self.assertRaises(exception.VolumeBackendAPIException,
2662                          self.rest.validate_qos_input, input_key, sg_value,
2663                          qos_extra_spec, {})
2664        input_key = 'total_bytes_sec'
2665        sg_value = 4000
2666        self.assertRaises(exception.VolumeBackendAPIException,
2667                          self.rest.validate_qos_input, input_key, sg_value,
2668                          qos_extra_spec, {})
2669
2670    def test_validate_qos_distribution_type(self):
2671        qos_extra_spec = {
2672            'total_iops_sec': 4000, 'DistributionType': 'Always',
2673            'total_bytes_sec': 4194304000}
2674        input_prop_dict = {'total_iops_sec': 4000}
2675        sg_value = 'Always'
2676        ret_prop_dict = self.rest.validate_qos_distribution_type(
2677            sg_value, qos_extra_spec, input_prop_dict)
2678        self.assertEqual(input_prop_dict, ret_prop_dict)
2679
2680    @mock.patch.object(rest.VMAXRest, 'modify_storage_group',
2681                       return_value=(202, VMAXCommonData.job_list[0]))
2682    def test_set_storagegroup_srp(self, mock_mod):
2683        self.rest.set_storagegroup_srp(
2684            self.data.array, self.data.test_vol_grp_name,
2685            self.data.srp2, self.data.extra_specs)
2686        mock_mod.assert_called_once()
2687
2688    def test_get_rdf_group(self):
2689        with mock.patch.object(self.rest, 'get_resource') as mock_get:
2690            self.rest.get_rdf_group(self.data.array, self.data.rdf_group_no)
2691            mock_get.assert_called_once_with(
2692                self.data.array, 'replication', 'rdf_group',
2693                self.data.rdf_group_no)
2694
2695    def test_get_rdf_group_list(self):
2696        rdf_list = self.rest.get_rdf_group_list(self.data.array)
2697        self.assertEqual(self.data.rdf_group_list, rdf_list)
2698
2699    def test_get_rdf_group_volume(self):
2700        vol_details = self.data.private_vol_details['resultList']['result'][0]
2701        with mock.patch.object(
2702                self.rest, '_get_private_volume', return_value=vol_details
2703        ) as mock_get:
2704            self.rest.get_rdf_group_volume(
2705                self.data.array, self.data.device_id)
2706            mock_get.assert_called_once_with(
2707                self.data.array, self.data.device_id)
2708
2709    def test_are_vols_rdf_paired(self):
2710        are_vols1, local_state, pair_state = self.rest.are_vols_rdf_paired(
2711            self.data.array, self.data.remote_array, self.data.device_id,
2712            self.data.device_id2)
2713        self.assertTrue(are_vols1)
2714        are_vols2, local_state, pair_state = self.rest.are_vols_rdf_paired(
2715            self.data.array, "00012345", self.data.device_id,
2716            self.data.device_id2)
2717        self.assertFalse(are_vols2)
2718        with mock.patch.object(self.rest, "get_rdf_group_volume",
2719                               return_value=None):
2720            are_vols3, local, pair = self.rest.are_vols_rdf_paired(
2721                self.data.array, self.data.remote_array, self.data.device_id,
2722                self.data.device_id2)
2723            self.assertFalse(are_vols3)
2724
2725    def test_get_rdf_group_number(self):
2726        rdfg_num = self.rest.get_rdf_group_number(
2727            self.data.array, self.data.rdf_group_name)
2728        self.assertEqual(self.data.rdf_group_no, rdfg_num)
2729        with mock.patch.object(self.rest, 'get_rdf_group_list',
2730                               return_value=None):
2731            rdfg_num2 = self.rest.get_rdf_group_number(
2732                self.data.array, self.data.rdf_group_name)
2733            self.assertIsNone(rdfg_num2)
2734        with mock.patch.object(self.rest, 'get_rdf_group',
2735                               return_value=None):
2736            rdfg_num3 = self.rest.get_rdf_group_number(
2737                self.data.array, self.data.rdf_group_name)
2738            self.assertIsNone(rdfg_num3)
2739
2740    def test_create_rdf_device_pair(self):
2741        ref_dict = {'array': self.data.remote_array,
2742                    'device_id': self.data.device_id2}
2743        extra_specs = deepcopy(self.data.extra_specs)
2744        extra_specs[utils.REP_MODE] = utils.REP_SYNC
2745        rdf_dict = self.rest.create_rdf_device_pair(
2746            self.data.array, self.data.device_id, self.data.rdf_group_no,
2747            self.data.device_id2, self.data.remote_array, extra_specs)
2748        self.assertEqual(ref_dict, rdf_dict)
2749
2750    def test_create_rdf_device_pair_async(self):
2751        ref_dict = {'array': self.data.remote_array,
2752                    'device_id': self.data.device_id2}
2753        extra_specs = deepcopy(self.data.extra_specs)
2754        extra_specs[utils.REP_MODE] = utils.REP_ASYNC
2755        rdf_dict = self.rest.create_rdf_device_pair(
2756            self.data.array, self.data.device_id, self.data.rdf_group_no,
2757            self.data.device_id2, self.data.remote_array, extra_specs)
2758        self.assertEqual(ref_dict, rdf_dict)
2759
2760    def test_create_rdf_device_pair_metro(self):
2761        ref_dict = {'array': self.data.remote_array,
2762                    'device_id': self.data.device_id2}
2763        extra_specs = deepcopy(self.data.extra_specs)
2764        extra_specs[utils.REP_MODE] = utils.REP_METRO
2765        extra_specs[utils.METROBIAS] = True
2766        rdf_dict = self.rest.create_rdf_device_pair(
2767            self.data.array, self.data.device_id, self.data.rdf_group_no,
2768            self.data.device_id2, self.data.remote_array, extra_specs)
2769        self.assertEqual(ref_dict, rdf_dict)
2770
2771    @mock.patch.object(rest.VMAXRest, 'get_rdf_group',
2772                       side_effect=[{'numDevices': 0}, {'numDevices': 0},
2773                                    {'numDevices': 1}])
2774    def test_get_metro_payload_info(self, mock_rdfg):
2775        ref_payload = {"establish": 'true', "rdfType": 'RDF1'}
2776        payload1 = self.rest.get_metro_payload_info(
2777            self.data.array, ref_payload, self.data.rdf_group_no, {})
2778        self.assertEqual(ref_payload, payload1)
2779        payload2 = self.rest.get_metro_payload_info(
2780            self.data.array, ref_payload, self.data.rdf_group_no,
2781            {'metro_bias': True})
2782        self.assertEqual('true', payload2['metroBias'])
2783        ref_payload2 = {"establish": 'true', "rdfType": 'RDF1'}
2784        payload3 = self.rest.get_metro_payload_info(
2785            self.data.array, ref_payload2, self.data.rdf_group_no, {})
2786        ref_payload3 = {"rdfType": 'NA', "format": 'true'}
2787        self.assertEqual(ref_payload3, payload3)
2788
2789    def test_modify_rdf_device_pair(self):
2790        resource_name = "70/volume/00001"
2791        common_opts = {"force": 'false',
2792                       "symForce": 'false',
2793                       "star": 'false',
2794                       "hop2": 'false',
2795                       "bypass": 'false'}
2796        suspend_payload = {"action": "Suspend",
2797                           'executionOption': 'ASYNCHRONOUS',
2798                           "suspend": common_opts}
2799
2800        failover_opts = deepcopy(common_opts)
2801        failover_opts.update({"establish": 'true',
2802                              "restore": 'false',
2803                              "remote": 'false',
2804                              "immediate": 'false'})
2805        failover_payload = {"action": "Failover",
2806                            'executionOption': 'ASYNCHRONOUS',
2807                            "failover": failover_opts}
2808        with mock.patch.object(
2809                self.rest, "modify_resource",
2810                return_value=(200, self.data.job_list[0])) as mock_mod:
2811            self.rest.modify_rdf_device_pair(
2812                self.data.array, self.data.device_id, self.data.rdf_group_no,
2813                self.data.extra_specs, suspend=True)
2814            mock_mod.assert_called_once_with(
2815                self.data.array, 'replication', 'rdf_group',
2816                suspend_payload, resource_name=resource_name,
2817                private='/private')
2818            mock_mod.reset_mock()
2819            self.rest.modify_rdf_device_pair(
2820                self.data.array, self.data.device_id, self.data.rdf_group_no,
2821                self.data.extra_specs, suspend=False)
2822            mock_mod.assert_called_once_with(
2823                self.data.array, 'replication', 'rdf_group',
2824                failover_payload, resource_name=resource_name,
2825                private='/private')
2826
2827    @mock.patch.object(rest.VMAXRest, 'delete_resource')
2828    def test_delete_rdf_pair(self, mock_del):
2829        self.rest.delete_rdf_pair(
2830            self.data.array, self.data.device_id, self.data.rdf_group_no)
2831        mock_del.assert_called_once()
2832
2833    def test_get_storage_group_rep(self):
2834        array = self.data.array
2835        source_group_name = self.data.storagegroup_name_source
2836        ref_details = self.data.sg_details_rep[0]
2837        volume_group = self.rest.get_storage_group_rep(array,
2838                                                       source_group_name)
2839        self.assertEqual(volume_group, ref_details)
2840
2841    def test_get_volumes_in_storage_group(self):
2842        array = self.data.array
2843        storagegroup_name = self.data.storagegroup_name_source
2844        ref_volumes = [self.data.device_id, self.data.device_id2]
2845        volume_list = self.rest.get_volumes_in_storage_group(
2846            array, storagegroup_name)
2847        self.assertEqual(ref_volumes, volume_list)
2848
2849    def test_create_storagegroup_snap(self):
2850        array = self.data.array
2851        extra_specs = self.data.extra_specs
2852        source_group = self.data.storagegroup_name_source
2853        snap_name = self.data.group_snapshot_name
2854        with mock.patch.object(
2855                self.rest, "create_storagegroup_snap") as mock_create:
2856            self.rest.create_storagegroup_snap(
2857                array, source_group, snap_name, extra_specs)
2858            mock_create.assert_called_once_with(array,
2859                                                source_group,
2860                                                snap_name,
2861                                                extra_specs)
2862
2863    def test_get_storagegroup_rdf_details(self):
2864        details = self.rest.get_storagegroup_rdf_details(
2865            self.data.array, self.data.test_vol_grp_name,
2866            self.data.rdf_group_no)
2867        self.assertEqual(self.data.sg_rdf_details[0], details)
2868
2869    def test_verify_rdf_state(self):
2870        verify1 = self.rest._verify_rdf_state(
2871            self.data.array, self.data.test_vol_grp_name,
2872            self.data.rdf_group_no, 'Failover')
2873        self.assertTrue(verify1)
2874        verify2 = self.rest._verify_rdf_state(
2875            self.data.array, self.data.test_fo_vol_group,
2876            self.data.rdf_group_no, 'Establish')
2877        self.assertTrue(verify2)
2878
2879    def test_modify_storagegroup_rdf(self):
2880        with mock.patch.object(
2881                self.rest, 'modify_resource',
2882                return_value=(202, self.data.job_list[0])) as mock_mod:
2883            self.rest.modify_storagegroup_rdf(
2884                self.data.array, self.data.test_vol_grp_name,
2885                self.data.rdf_group_no, 'Failover',
2886                self.data.extra_specs)
2887            mock_mod.assert_called_once()
2888
2889    def test_delete_storagegroup_rdf(self):
2890        with mock.patch.object(
2891                self.rest, 'delete_resource') as mock_del:
2892            self.rest.delete_storagegroup_rdf(
2893                self.data.array, self.data.test_vol_grp_name,
2894                self.data.rdf_group_no)
2895            mock_del.assert_called_once()
2896
2897    def test_is_next_gen_array(self):
2898        is_next_gen = self.rest.is_next_gen_array(self.data.array)
2899        self.assertFalse(is_next_gen)
2900        is_next_gen2 = self.rest.is_next_gen_array(self.data.array_herc)
2901        self.assertTrue(is_next_gen2)
2902
2903    @mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall',
2904                new=test_utils.ZeroIntervalLoopingCall)
2905    @mock.patch.object(rest.VMAXRest, 'are_vols_rdf_paired',
2906                       side_effect=[('', '', 'syncinprog'),
2907                                    ('', '', 'consistent'),
2908                                    exception.CinderException])
2909    def test_wait_for_rdf_consistent_state(self, mock_paired):
2910        self.rest.wait_for_rdf_consistent_state(
2911            self.data.array, self.data.remote_array,
2912            self.data.device_id, self.data.device_id2,
2913            self.data.extra_specs)
2914        self.assertEqual(2, mock_paired.call_count)
2915        self.assertRaises(exception.VolumeBackendAPIException,
2916                          self.rest.wait_for_rdf_consistent_state,
2917                          self.data.array, self.data.remote_array,
2918                          self.data.device_id, self.data.device_id2,
2919                          self.data.extra_specs)
2920
2921    @mock.patch.object(rest.VMAXRest, 'modify_resource',
2922                       return_value=('200', 'JobComplete'))
2923    def test_modify_volume_snap_rename(self, mock_modify):
2924        array = self.data.array
2925        source_id = self.data.device_id
2926        old_snap_backend_name = self.data.snapshot_id
2927        new_snap_backend_name = self.data.managed_snap_id
2928        self.rest.modify_volume_snap(
2929            array, source_id, source_id, old_snap_backend_name,
2930            self.data.extra_specs, link=False, unlink=False,
2931            rename=True, new_snap_name=new_snap_backend_name)
2932        mock_modify.assert_called_once()
2933
2934    def test_set_rest_credentials(self):
2935        array_info = {
2936            'RestServerIp': '10.10.10.10',
2937            'RestServerPort': '8443',
2938            'RestUserName': 'user_test',
2939            'RestPassword': 'pass_test',
2940            'SSLVerify': True,
2941        }
2942        self.rest.set_rest_credentials(array_info)
2943        self.assertEqual('user_test', self.rest.user)
2944        self.assertEqual('pass_test', self.rest.passwd)
2945        self.assertTrue(self.rest.verify)
2946        self.assertEqual('https://10.10.10.10:8443/univmax/restapi',
2947                         self.rest.base_uri)
2948
2949    def test_get_vmax_model(self):
2950        reference = 'PowerMax_2000'
2951        with mock.patch.object(self.rest, '_get_request',
2952                               return_value=self.data.powermax_model_details):
2953            self.assertEqual(self.rest.get_vmax_model(self.data.array),
2954                             reference)
2955
2956
2957class VMAXProvisionTest(test.TestCase):
2958    def setUp(self):
2959        self.data = VMAXCommonData()
2960
2961        super(VMAXProvisionTest, self).setUp()
2962        volume_utils.get_max_over_subscription_ratio = mock.Mock()
2963        config_group = 'ProvisionTests'
2964        self.fake_xml = FakeXML().create_fake_config_file(
2965            config_group, self.data.port_group_name_i)
2966        configuration = FakeConfiguration(self.fake_xml, config_group)
2967        rest.VMAXRest._establish_rest_session = mock.Mock(
2968            return_value=FakeRequestsSession())
2969        driver = iscsi.VMAXISCSIDriver(configuration=configuration)
2970        self.driver = driver
2971        self.common = self.driver.common
2972        self.provision = self.common.provision
2973        self.utils = self.common.utils
2974        self.rest = self.common.rest
2975
2976    @mock.patch.object(rest.VMAXRest, 'create_storage_group',
2977                       return_value=VMAXCommonData.storagegroup_name_f)
2978    @mock.patch.object(rest.VMAXRest, 'get_storage_group',
2979                       side_effect=[
2980                           VMAXCommonData.storagegroup_name_f, None])
2981    def test_create_storage_group(self, mock_get_sg, mock_create):
2982        array = self.data.array
2983        storagegroup_name = self.data.storagegroup_name_f
2984        srp = self.data.srp
2985        slo = self.data.slo
2986        workload = self.data.workload
2987        extra_specs = self.data.extra_specs
2988        for x in range(0, 2):
2989            storagegroup = self.provision.create_storage_group(
2990                array, storagegroup_name, srp, slo, workload, extra_specs)
2991            self.assertEqual(storagegroup_name, storagegroup)
2992        mock_create.assert_called_once()
2993
2994    def test_create_volume_from_sg(self):
2995        array = self.data.array
2996        storagegroup_name = self.data.storagegroup_name_f
2997        volumeId = self.data.test_volume.id
2998        volume_name = self.utils.get_volume_element_name(volumeId)
2999        volume_size = self.data.test_volume.size
3000        extra_specs = self.data.extra_specs
3001        ref_dict = self.data.provider_location
3002        volume_dict = self.provision.create_volume_from_sg(
3003            array, volume_name, storagegroup_name, volume_size, extra_specs)
3004        self.assertEqual(ref_dict, volume_dict)
3005
3006    def test_delete_volume_from_srp(self):
3007        array = self.data.array
3008        device_id = self.data.device_id
3009        volume_name = self.data.volume_details[0]['volume_identifier']
3010        with mock.patch.object(self.provision.rest, 'delete_volume'):
3011            self.provision.delete_volume_from_srp(
3012                array, device_id, volume_name)
3013            self.provision.rest.delete_volume.assert_called_once_with(
3014                array, device_id)
3015
3016    def test_create_volume_snap_vx(self):
3017        array = self.data.array
3018        source_device_id = self.data.device_id
3019        snap_name = self.data.snap_location['snap_name']
3020        extra_specs = self.data.extra_specs
3021        with mock.patch.object(self.provision.rest, 'create_volume_snap'):
3022            self.provision.create_volume_snapvx(
3023                array, source_device_id, snap_name, extra_specs)
3024            self.provision.rest.create_volume_snap.assert_called_once_with(
3025                array, snap_name, source_device_id, extra_specs)
3026
3027    def test_create_volume_replica_create_snap_true(self):
3028        array = self.data.array
3029        source_device_id = self.data.device_id
3030        target_device_id = self.data.device_id2
3031        snap_name = self.data.snap_location['snap_name']
3032        extra_specs = self.data.extra_specs
3033        with mock.patch.object(self.provision, 'create_volume_snapvx'):
3034            with mock.patch.object(self.provision.rest, 'modify_volume_snap'):
3035                self.provision.create_volume_replica(
3036                    array, source_device_id, target_device_id,
3037                    snap_name, extra_specs, create_snap=True)
3038                self.provision.rest.modify_volume_snap.assert_called_once_with(
3039                    array, source_device_id, target_device_id, snap_name,
3040                    extra_specs, link=True)
3041                self.provision.create_volume_snapvx.assert_called_once_with(
3042                    array, source_device_id, snap_name, extra_specs)
3043
3044    def test_create_volume_replica_create_snap_false(self):
3045        array = self.data.array
3046        source_device_id = self.data.device_id
3047        target_device_id = self.data.device_id2
3048        snap_name = self.data.snap_location['snap_name']
3049        extra_specs = self.data.extra_specs
3050        with mock.patch.object(self.provision, 'create_volume_snapvx'):
3051            with mock.patch.object(self.provision.rest, 'modify_volume_snap'):
3052                self.provision.create_volume_replica(
3053                    array, source_device_id, target_device_id,
3054                    snap_name, extra_specs, create_snap=False)
3055                self.provision.rest.modify_volume_snap.assert_called_once_with(
3056                    array, source_device_id, target_device_id, snap_name,
3057                    extra_specs, link=True)
3058                self.provision.create_volume_snapvx.assert_not_called()
3059
3060    def test_break_replication_relationship(self):
3061        array = self.data.array
3062        source_device_id = self.data.device_id
3063        target_device_id = self.data.device_id2
3064        snap_name = self.data.snap_location['snap_name']
3065        extra_specs = self.data.extra_specs
3066        with mock.patch.object(self.provision.rest, 'modify_volume_snap'):
3067            self.provision.break_replication_relationship(
3068                array, target_device_id, source_device_id, snap_name,
3069                extra_specs)
3070            (self.provision.rest.modify_volume_snap.
3071                assert_called_once_with(
3072                    array, source_device_id, target_device_id,
3073                    snap_name, extra_specs,
3074                    list_volume_pairs=None, unlink=True))
3075
3076    @mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall',
3077                new=test_utils.ZeroIntervalLoopingCall)
3078    def test_unlink_volume(self):
3079        with mock.patch.object(self.rest, 'modify_volume_snap') as mock_mod:
3080            self.provision._unlink_volume(
3081                self.data.array, self.data.device_id, self.data.device_id2,
3082                self.data.snap_location['snap_name'], self.data.extra_specs)
3083            mock_mod.assert_called_once_with(
3084                self.data.array, self.data.device_id, self.data.device_id2,
3085                self.data.snap_location['snap_name'], self.data.extra_specs,
3086                list_volume_pairs=None, unlink=True)
3087
3088    @mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall',
3089                new=test_utils.ZeroIntervalLoopingCall)
3090    def test_unlink_volume_exception(self):
3091        with mock.patch.object(
3092                self.rest, 'modify_volume_snap', side_effect=[
3093                    exception.VolumeBackendAPIException(data=''), '']
3094        ) as mock_mod:
3095            self.provision._unlink_volume(
3096                self.data.array, self.data.device_id, self.data.device_id2,
3097                self.data.snap_location['snap_name'], self.data.extra_specs)
3098            self.assertEqual(2, mock_mod.call_count)
3099
3100    def test_delete_volume_snap(self):
3101        array = self.data.array
3102        source_device_id = self.data.device_id
3103        snap_name = self.data.snap_location['snap_name']
3104        with mock.patch.object(self.provision.rest, 'delete_volume_snap'):
3105            self.provision.delete_volume_snap(
3106                array, snap_name, source_device_id)
3107            self.provision.rest.delete_volume_snap.assert_called_once_with(
3108                array, snap_name, source_device_id, False)
3109
3110    def test_delete_volume_snap_restore(self):
3111        array = self.data.array
3112        source_device_id = self.data.device_id
3113        snap_name = self.data.snap_location['snap_name']
3114        restored = True
3115        with mock.patch.object(self.provision.rest, 'delete_volume_snap'):
3116            self.provision.delete_volume_snap(
3117                array, snap_name, source_device_id, restored)
3118            self.provision.rest.delete_volume_snap.assert_called_once_with(
3119                array, snap_name, source_device_id, True)
3120
3121    @mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall',
3122                new=test_utils.ZeroIntervalLoopingCall)
3123    def test_restore_complete(self):
3124        array = self.data.array
3125        source_device_id = self.data.device_id
3126        snap_name = self.data.snap_location['snap_name']
3127        extra_specs = self.data.extra_specs
3128        with mock.patch.object(
3129                self.provision, '_is_restore_complete',
3130                return_value=True):
3131            isrestored = self.provision.is_restore_complete(
3132                array, source_device_id, snap_name, extra_specs)
3133            self.assertTrue(isrestored)
3134        with mock.patch.object(
3135                self.provision, '_is_restore_complete',
3136                side_effect=exception.CinderException):
3137            self.assertRaises(exception.VolumeBackendAPIException,
3138                              self.provision.is_restore_complete,
3139                              array, source_device_id, snap_name, extra_specs)
3140
3141    def test_is_restore_complete(self):
3142        array = self.data.array
3143        source_device_id = self.data.device_id
3144        snap_name = self.data.snap_location['snap_name']
3145        snap_details = {
3146            'linkedDevices':
3147            [{'targetDevice': source_device_id, 'state': "Restored"}]}
3148        with mock.patch.object(self.provision.rest,
3149                               'get_volume_snap', return_value=snap_details):
3150            isrestored = self.provision._is_restore_complete(
3151                array, source_device_id, snap_name)
3152            self.assertTrue(isrestored)
3153        snap_details['linkedDevices'][0]['state'] = "Restoring"
3154        with mock.patch.object(self.provision.rest,
3155                               'get_volume_snap', return_value=snap_details):
3156            isrestored = self.provision._is_restore_complete(
3157                array, source_device_id, snap_name)
3158            self.assertFalse(isrestored)
3159
3160    def test_revert_volume_snapshot(self):
3161        array = self.data.array
3162        source_device_id = self.data.device_id
3163        snap_name = self.data.snap_location['snap_name']
3164        extra_specs = self.data.extra_specs
3165        with mock.patch.object(
3166                self.provision.rest, 'modify_volume_snap', return_value=None):
3167            self.provision.revert_volume_snapshot(
3168                array, source_device_id, snap_name, extra_specs)
3169            self.provision.rest.modify_volume_snap.assert_called_once_with(
3170                array, source_device_id, "", snap_name,
3171                extra_specs, restore=True)
3172
3173    def test_extend_volume(self):
3174        array = self.data.array
3175        device_id = self.data.device_id
3176        new_size = '3'
3177        extra_specs = self.data.extra_specs
3178        with mock.patch.object(self.provision.rest, 'extend_volume'
3179                               ) as mock_ex:
3180            self.provision.extend_volume(array, device_id, new_size,
3181                                         extra_specs)
3182            mock_ex.assert_called_once_with(
3183                array, device_id, new_size, extra_specs)
3184            mock_ex.reset_mock()
3185            # Pass in rdf group
3186            self.provision.extend_volume(array, device_id, new_size,
3187                                         extra_specs, self.data.rdf_group_no)
3188            mock_ex.assert_called_once_with(
3189                array, device_id, new_size, extra_specs)
3190
3191    def test_get_srp_pool_stats(self):
3192        array = self.data.array
3193        array_info = self.common.pool_info['arrays_info'][0]
3194        ref_stats = (self.data.srp_details['total_usable_cap_gb'],
3195                     float(self.data.srp_details['total_usable_cap_gb']
3196                           - self.data.srp_details['total_used_cap_gb']),
3197                     self.data.srp_details['total_subscribed_cap_gb'],
3198                     self.data.srp_details['reserved_cap_percent'])
3199        stats = self.provision.get_srp_pool_stats(array, array_info)
3200        self.assertEqual(ref_stats, stats)
3201
3202    def test_get_srp_pool_stats_errors(self):
3203        # cannot retrieve srp
3204        array = self.data.array
3205        array_info = {'srpName': self.data.failed_resource}
3206        ref_stats = (0, 0, 0, 0, False)
3207        stats = self.provision.get_srp_pool_stats(array, array_info)
3208        self.assertEqual(ref_stats, stats)
3209        # cannot report on all stats
3210        with mock.patch.object(self.provision.rest, 'get_srp_by_name',
3211                               return_value={'total_usable_cap_gb': 33}):
3212            ref_stats = (33, 0, 0, 0)
3213            stats = self.provision.get_srp_pool_stats(array, array_info)
3214            self.assertEqual(ref_stats, stats)
3215
3216    def test_verify_slo_workload_true(self):
3217        # with slo and workload
3218        array = self.data.array
3219        slo = self.data.slo
3220        workload = self.data.workload
3221        srp = self.data.srp
3222        valid_slo, valid_workload = self.provision.verify_slo_workload(
3223            array, slo, workload, srp)
3224        self.assertTrue(valid_slo)
3225        self.assertTrue(valid_workload)
3226        # slo and workload = none
3227        slo2 = None
3228        workload2 = None
3229        valid_slo2, valid_workload2 = self.provision.verify_slo_workload(
3230            array, slo2, workload2, srp)
3231        self.assertTrue(valid_slo2)
3232        self.assertTrue(valid_workload2)
3233        slo2 = None
3234        workload2 = 'None'
3235        valid_slo2, valid_workload2 = self.provision.verify_slo_workload(
3236            array, slo2, workload2, srp)
3237        self.assertTrue(valid_slo2)
3238        self.assertTrue(valid_workload2)
3239
3240    def test_verify_slo_workload_false(self):
3241        # Both wrong
3242        array = self.data.array
3243        slo = 'Diamante'
3244        workload = 'DSSS'
3245        srp = self.data.srp
3246        valid_slo, valid_workload = self.provision.verify_slo_workload(
3247            array, slo, workload, srp)
3248        self.assertFalse(valid_slo)
3249        self.assertFalse(valid_workload)
3250        # Workload set, no slo set
3251        valid_slo, valid_workload = self.provision.verify_slo_workload(
3252            array, None, self.data.workload, srp)
3253        self.assertTrue(valid_slo)
3254        self.assertFalse(valid_workload)
3255
3256    def test_get_slo_workload_settings_from_storage_group(self):
3257        ref_settings = "Diamond+DSS"
3258        sg_slo_settings = (
3259            self.provision.get_slo_workload_settings_from_storage_group(
3260                self.data.array, self.data.defaultstoragegroup_name))
3261        self.assertEqual(ref_settings, sg_slo_settings)
3262        # No workload
3263        with mock.patch.object(self.provision.rest, 'get_storage_group',
3264                               return_value={'slo': 'Silver'}):
3265            ref_settings2 = "Silver+NONE"
3266            sg_slo_settings2 = (
3267                self.provision.get_slo_workload_settings_from_storage_group(
3268                    self.data.array, 'no_workload_sg'))
3269            self.assertEqual(ref_settings2, sg_slo_settings2)
3270        # NextGen Array
3271        with mock.patch.object(self.rest, 'is_next_gen_array',
3272                               return_value=True):
3273            ref_settings3 = "Diamond+NONE"
3274            sg_slo_settings3 = (
3275                self.provision.get_slo_workload_settings_from_storage_group(
3276                    self.data.array, self.data.defaultstoragegroup_name))
3277            self.assertEqual(ref_settings3, sg_slo_settings3)
3278
3279    @mock.patch.object(rest.VMAXRest, 'wait_for_rdf_consistent_state')
3280    @mock.patch.object(rest.VMAXRest, 'delete_rdf_pair')
3281    @mock.patch.object(rest.VMAXRest, 'modify_rdf_device_pair')
3282    def test_break_rdf_relationship(self, mock_mod, mock_del, mock_wait):
3283        array = self.data.array
3284        device_id = self.data.device_id
3285        target_device = self.data.device_id2
3286        rdf_group_name = self.data.rdf_group_name
3287        rep_extra_specs = self.data.rep_extra_specs
3288        # State is suspended
3289        self.provision.break_rdf_relationship(
3290            array, device_id, target_device,
3291            rdf_group_name, rep_extra_specs, "Suspended")
3292        mock_mod.assert_not_called()
3293        mock_del.assert_called_once_with(
3294            array, device_id, rdf_group_name)
3295        mock_del.reset_mock()
3296        # State is synchronized
3297        self.provision.break_rdf_relationship(
3298            array, device_id, target_device,
3299            rdf_group_name, rep_extra_specs, "Synchronized")
3300        mock_mod.assert_called_once_with(
3301            array, device_id, rdf_group_name, rep_extra_specs,
3302            suspend=True)
3303        mock_del.assert_called_once_with(
3304            array, device_id, rdf_group_name)
3305        # sync still in progress
3306        self.provision.break_rdf_relationship(
3307            array, device_id, target_device,
3308            rdf_group_name, rep_extra_specs, "SyncInProg")
3309        mock_wait.assert_called_once()
3310
3311    @mock.patch.object(provision.VMAXProvision, 'disable_group_replication')
3312    @mock.patch.object(provision.VMAXProvision, 'delete_rdf_pair')
3313    def test_break_metro_rdf_pair(self, mock_del, mock_disable):
3314        self.provision.break_metro_rdf_pair(
3315            self.data.array, self.data.device_id, self.data.device_id2,
3316            self.data.rdf_group_no, self.data.rep_extra_specs, 'metro_grp')
3317        mock_del.assert_called_once()
3318
3319    def test_delete_rdf_pair_async(self):
3320        with mock.patch.object(
3321                self.provision.rest, 'delete_rdf_pair') as mock_del_rdf:
3322            extra_specs = deepcopy(self.data.extra_specs)
3323            extra_specs[utils.REP_MODE] = utils.REP_ASYNC
3324            self.provision.delete_rdf_pair(
3325                self.data.array, self.data.device_id,
3326                self.data.rdf_group_no, self.data.device_id2, extra_specs)
3327            mock_del_rdf.assert_called_once()
3328
3329    def test_failover_volume(self):
3330        array = self.data.array
3331        device_id = self.data.device_id
3332        rdf_group_name = self.data.rdf_group_name
3333        extra_specs = self.data.extra_specs
3334        with mock.patch.object(
3335                self.provision.rest, 'modify_rdf_device_pair') as mod_rdf:
3336            self.provision.failover_volume(
3337                array, device_id, rdf_group_name,
3338                extra_specs, '', True)
3339            mod_rdf.assert_called_once_with(
3340                array, device_id, rdf_group_name, extra_specs)
3341            mod_rdf.reset_mock()
3342            self.provision.failover_volume(
3343                array, device_id, rdf_group_name,
3344                extra_specs, '', False)
3345            mod_rdf.assert_called_once_with(
3346                array, device_id, rdf_group_name, extra_specs)
3347
3348    @mock.patch.object(rest.VMAXRest, 'get_storage_group',
3349                       return_value=None)
3350    def test_create_volume_group_success(self, mock_get_sg):
3351        array = self.data.array
3352        group_name = self.data.storagegroup_name_source
3353        extra_specs = self.data.extra_specs
3354        ref_value = self.data.storagegroup_name_source
3355        storagegroup = self.provision.create_volume_group(
3356            array, group_name, extra_specs)
3357        self.assertEqual(ref_value, storagegroup)
3358
3359    def test_create_group_replica(self):
3360        array = self.data.array
3361        source_group = self.data.storagegroup_name_source
3362        snap_name = self.data.group_snapshot_name
3363        extra_specs = self.data.extra_specs
3364        with mock.patch.object(
3365                self.provision,
3366                'create_group_replica') as mock_create_replica:
3367            self.provision.create_group_replica(
3368                array, source_group, snap_name, extra_specs)
3369            mock_create_replica.assert_called_once_with(
3370                array, source_group, snap_name, extra_specs)
3371
3372    def test_delete_group_replica(self):
3373        array = self.data.array
3374        snap_name = self.data.group_snapshot_name
3375        source_group_name = self.data.storagegroup_name_source
3376        with mock.patch.object(
3377                self.provision,
3378                'delete_group_replica') as mock_delete_replica:
3379            self.provision.delete_group_replica(array,
3380                                                snap_name,
3381                                                source_group_name)
3382            mock_delete_replica.assert_called_once_with(
3383                array, snap_name, source_group_name)
3384
3385    def test_link_and_break_replica(self):
3386        array = self.data.array
3387        source_group_name = self.data.storagegroup_name_source
3388        target_group_name = self.data.target_group_name
3389        snap_name = self.data.group_snapshot_name
3390        extra_specs = self.data.extra_specs
3391        deleteSnapshot = False
3392        with mock.patch.object(
3393                self.provision,
3394                'link_and_break_replica') as mock_link_and_break_replica:
3395            self.provision.link_and_break_replica(
3396                array, source_group_name,
3397                target_group_name, snap_name,
3398                extra_specs, deleteSnapshot)
3399            mock_link_and_break_replica.assert_called_once_with(
3400                array, source_group_name,
3401                target_group_name, snap_name,
3402                extra_specs, deleteSnapshot)
3403
3404    @mock.patch.object(rest.VMAXRest, 'get_storage_group',
3405                       side_effect=[None, VMAXCommonData.sg_details[1]])
3406    @mock.patch.object(provision.VMAXProvision, 'create_volume_group')
3407    def test_get_or_create_volume_group(self, mock_create, mock_sg):
3408        for x in range(0, 2):
3409            self.provision.get_or_create_volume_group(
3410                self.data.array, self.data.test_group, self.data.extra_specs)
3411        self.assertEqual(2, mock_sg.call_count)
3412        self.assertEqual(1, mock_create.call_count)
3413
3414    @mock.patch.object(rest.VMAXRest, 'create_resource',
3415                       return_value=(202, VMAXCommonData.job_list[0]))
3416    def test_replicate_group(self, mock_create):
3417        self.rest.replicate_group(
3418            self.data.array, self.data.test_rep_group,
3419            self.data.rdf_group_no, self.data.remote_array,
3420            self.data.extra_specs)
3421        mock_create.assert_called_once()
3422
3423    def test_enable_group_replication(self):
3424        with mock.patch.object(self.rest,
3425                               'modify_storagegroup_rdf') as mock_mod:
3426            self.provision.enable_group_replication(
3427                self.data.array, self.data.test_vol_grp_name,
3428                self.data.rdf_group_no, self.data.extra_specs)
3429            mock_mod.assert_called_once()
3430
3431    def test_disable_group_replication(self):
3432        with mock.patch.object(self.rest,
3433                               'modify_storagegroup_rdf') as mock_mod:
3434            self.provision.disable_group_replication(
3435                self.data.array, self.data.test_vol_grp_name,
3436                self.data.rdf_group_no, self.data.extra_specs)
3437            mock_mod.assert_called_once()
3438
3439    def test_failover_group(self):
3440        with mock.patch.object(self.rest,
3441                               'modify_storagegroup_rdf') as mock_fo:
3442            # Failover
3443            self.provision.failover_group(
3444                self.data.array, self.data.test_vol_grp_name,
3445                self.data.rdf_group_no, self.data.extra_specs)
3446            mock_fo.assert_called_once_with(
3447                self.data.array, self.data.test_vol_grp_name,
3448                self.data.rdf_group_no, 'Failover', self.data.extra_specs)
3449            mock_fo.reset_mock()
3450            # Failback
3451            self.provision.failover_group(
3452                self.data.array, self.data.test_vol_grp_name,
3453                self.data.rdf_group_no, self.data.extra_specs, False)
3454            mock_fo.assert_called_once_with(
3455                self.data.array, self.data.test_vol_grp_name,
3456                self.data.rdf_group_no, 'Failback', self.data.extra_specs)
3457
3458    @mock.patch.object(rest.VMAXRest, 'modify_storagegroup_rdf')
3459    @mock.patch.object(rest.VMAXRest, 'delete_storagegroup_rdf')
3460    def test_delete_group_replication(self, mock_mod, mock_del):
3461        self.provision.delete_group_replication(
3462            self.data.array, self.data.test_vol_grp_name,
3463            self.data.rdf_group_no, self.data.extra_specs)
3464        mock_mod.assert_called_once()
3465        mock_del.assert_called_once()
3466
3467    @mock.patch.object(
3468        rest.VMAXRest, 'get_snap_linked_device_list',
3469        side_effect=[[{'targetDevice': VMAXCommonData.device_id2}],
3470                     [{'targetDevice': VMAXCommonData.device_id2},
3471                      {'targetDevice': VMAXCommonData.device_id3}]])
3472    @mock.patch.object(provision.VMAXProvision, '_unlink_volume')
3473    def test_delete_volume_snap_check_for_links(self, mock_unlink, mock_tgts):
3474        self.provision.delete_volume_snap_check_for_links(
3475            self.data.array, self.data.test_snapshot_snap_name,
3476            self.data.device_id, self.data.extra_specs)
3477        mock_unlink.assert_called_once_with(
3478            self.data.array, "", "", self.data.test_snapshot_snap_name,
3479            self.data.extra_specs, list_volume_pairs=[
3480                (self.data.device_id, VMAXCommonData.device_id2)])
3481        mock_unlink.reset_mock()
3482        self.provision.delete_volume_snap_check_for_links(
3483            self.data.array, self.data.test_snapshot_snap_name,
3484            self.data.device_id, self.data.extra_specs)
3485        self.assertEqual(2, mock_unlink.call_count)
3486
3487
3488class VMAXCommonTest(test.TestCase):
3489    def setUp(self):
3490        self.data = VMAXCommonData()
3491
3492        super(VMAXCommonTest, self).setUp()
3493        self.mock_object(volume_utils, 'get_max_over_subscription_ratio',
3494                         return_value=1.0)
3495        config_group = 'CommonTests'
3496        self.fake_xml = FakeXML().create_fake_config_file(
3497            config_group, self.data.port_group_name_f)
3498        configuration = FakeConfiguration(self.fake_xml, config_group,
3499                                          1, 1)
3500        rest.VMAXRest._establish_rest_session = mock.Mock(
3501            return_value=FakeRequestsSession())
3502        driver = fc.VMAXFCDriver(configuration=configuration)
3503        self.driver = driver
3504        self.common = self.driver.common
3505        self.masking = self.common.masking
3506        self.provision = self.common.provision
3507        self.rest = self.common.rest
3508        self.utils = self.common.utils
3509        self.utils.get_volumetype_extra_specs = (
3510            mock.Mock(return_value=self.data.vol_type_extra_specs))
3511
3512    @mock.patch.object(rest.VMAXRest,
3513                       'set_rest_credentials')
3514    @mock.patch.object(common.VMAXCommon,
3515                       '_get_slo_workload_combinations',
3516                       return_value=[])
3517    @mock.patch.object(utils.VMAXUtils,
3518                       'parse_file_to_get_array_map',
3519                       return_value=[])
3520    def test_gather_info_no_opts(self, mock_parse, mock_combo, mock_rest):
3521        configuration = FakeConfiguration(None, 'config_group', None, None)
3522        fc.VMAXFCDriver(configuration=configuration)
3523
3524    @mock.patch.object(rest.VMAXRest, 'is_next_gen_array',
3525                       return_value=True)
3526    @mock.patch.object(rest.VMAXRest, 'set_rest_credentials')
3527    @mock.patch.object(common.VMAXCommon, '_get_slo_workload_combinations',
3528                       return_value=[])
3529    @mock.patch.object(common.VMAXCommon, 'get_attributes_from_cinder_config',
3530                       return_value=VMAXCommonData.array_info_wl)
3531    def test_gather_info_next_gen(self, mock_parse, mock_combo, mock_rest,
3532                                  mock_nextgen):
3533        self.common._gather_info()
3534        self.assertTrue(self.common.nextGen)
3535
3536    def test_get_slo_workload_combinations_powermax(self):
3537        finalarrayinfolist = self.common._get_slo_workload_combinations(
3538            self.data.array_info_no_wl)
3539        self.assertTrue(len(finalarrayinfolist) > 1)
3540
3541    @mock.patch.object(rest.VMAXRest, 'get_vmax_model',
3542                       return_value=VMAXCommonData.vmax_model_details['model'])
3543    @mock.patch.object(rest.VMAXRest, 'get_slo_list',
3544                       return_value=VMAXCommonData.vmax_slo_details['sloId'])
3545    def test_get_slo_workload_combinations_vmax(self, mck_slo, mck_model):
3546        finalarrayinfolist = self.common._get_slo_workload_combinations(
3547            self.data.array_info_wl)
3548        self.assertTrue(len(finalarrayinfolist) > 1)
3549
3550    @mock.patch.object(rest.VMAXRest, 'get_vmax_model',
3551                       return_value=VMAXCommonData.powermax_model_details[
3552                           'model'])
3553    @mock.patch.object(rest.VMAXRest, 'get_workload_settings',
3554                       return_value=[])
3555    @mock.patch.object(rest.VMAXRest, 'get_slo_list',
3556                       return_value=VMAXCommonData.powermax_slo_details[
3557                           'sloId'])
3558    def test_get_slo_workload_combinations_next_gen(self, mck_slo, mck_wl,
3559                                                    mck_model):
3560        self.common.nextGen = True
3561        finalarrayinfolist = self.common._get_slo_workload_combinations(
3562            self.data.array_info_no_wl)
3563        self.assertTrue(len(finalarrayinfolist) == 14)
3564
3565    @mock.patch.object(rest.VMAXRest, 'get_vmax_model',
3566                       return_value=VMAXCommonData.vmax_model_details[
3567                           'model'])
3568    @mock.patch.object(rest.VMAXRest, 'get_workload_settings',
3569                       return_value=[])
3570    @mock.patch.object(rest.VMAXRest, 'get_slo_list',
3571                       return_value=VMAXCommonData.powermax_slo_details[
3572                           'sloId'])
3573    def test_get_slo_workload_combinations_next_gen_vmax(
3574            self, mck_slo, mck_wl, mck_model):
3575        self.common.nextGen = True
3576        finalarrayinfolist = self.common._get_slo_workload_combinations(
3577            self.data.array_info_no_wl)
3578        self.assertTrue(len(finalarrayinfolist) == 18)
3579
3580    def test_get_slo_workload_combinations_failed(self):
3581        array_info = {}
3582        self.assertRaises(exception.VolumeBackendAPIException,
3583                          self.common._get_slo_workload_combinations,
3584                          array_info)
3585
3586    def test_create_volume(self):
3587        ref_model_update = (
3588            {'provider_location': six.text_type(self.data.provider_location)})
3589        model_update = self.common.create_volume(self.data.test_volume)
3590        self.assertEqual(ref_model_update, model_update)
3591
3592    def test_create_volume_qos(self):
3593        ref_model_update = (
3594            {'provider_location': six.text_type(self.data.provider_location)})
3595        extra_specs = deepcopy(self.data.extra_specs_intervals_set)
3596        extra_specs['qos'] = {
3597            'total_iops_sec': '4000', 'DistributionType': 'Always'}
3598        with mock.patch.object(self.utils, 'get_volumetype_extra_specs',
3599                               return_value=extra_specs):
3600            model_update = self.common.create_volume(self.data.test_volume)
3601            self.assertEqual(ref_model_update, model_update)
3602
3603    def test_create_volume_from_snapshot(self):
3604        ref_model_update = (
3605            {'provider_location': six.text_type(
3606                self.data.provider_location)})
3607        model_update = self.common.create_volume_from_snapshot(
3608            self.data.test_clone_volume, self.data.test_snapshot)
3609        self.assertEqual(ref_model_update, model_update)
3610        # Test from legacy snapshot
3611        model_update = self.common.create_volume_from_snapshot(
3612            self.data.test_clone_volume, self.data.test_legacy_snapshot)
3613        self.assertEqual(ref_model_update, model_update)
3614
3615    def test_cloned_volume(self):
3616        ref_model_update = (
3617            {'provider_location': six.text_type(
3618                self.data.provider_location)})
3619        model_update = self.common.create_cloned_volume(
3620            self.data.test_clone_volume, self.data.test_volume)
3621        self.assertEqual(ref_model_update, model_update)
3622
3623    def test_delete_volume(self):
3624        with mock.patch.object(self.common, '_delete_volume'):
3625            self.common.delete_volume(self.data.test_volume)
3626            self.common._delete_volume.assert_called_once_with(
3627                self.data.test_volume)
3628
3629    def test_create_snapshot(self):
3630        ref_model_update = (
3631            {'provider_location': six.text_type(
3632                self.data.snap_location)})
3633        model_update = self.common.create_snapshot(
3634            self.data.test_snapshot, self.data.test_volume)
3635        self.assertEqual(ref_model_update, model_update)
3636
3637    def test_delete_snapshot(self):
3638        snap_name = self.data.snap_location['snap_name']
3639        sourcedevice_id = self.data.snap_location['source_id']
3640        with mock.patch.object(self.provision, 'delete_volume_snap'):
3641            self.common.delete_snapshot(self.data.test_snapshot,
3642                                        self.data.test_volume)
3643            self.provision.delete_volume_snap.assert_called_once_with(
3644                self.data.array, snap_name, [sourcedevice_id])
3645
3646    def test_delete_snapshot_not_found(self):
3647        with mock.patch.object(self.common, '_parse_snap_info',
3648                               return_value=(None, 'Something')):
3649            with mock.patch.object(self.provision, 'delete_volume_snap'):
3650                self.common.delete_snapshot(self.data.test_snapshot,
3651                                            self.data.test_volume)
3652                self.provision.delete_volume_snap.assert_not_called()
3653
3654    def test_delete_legacy_snap(self):
3655        with mock.patch.object(self.common, '_delete_volume') as mock_del:
3656            self.common.delete_snapshot(self.data.test_legacy_snapshot,
3657                                        self.data.test_legacy_vol)
3658            mock_del.assert_called_once_with(self.data.test_legacy_snapshot)
3659
3660    def test_remove_members(self):
3661        array = self.data.array
3662        device_id = self.data.device_id
3663        volume = self.data.test_volume
3664        volume_name = self.data.test_volume.name
3665        extra_specs = self.data.extra_specs
3666        with mock.patch.object(self.masking,
3667                               'remove_and_reset_members') as mock_rm:
3668            self.common._remove_members(array, volume, device_id,
3669                                        extra_specs, self.data.connector)
3670            mock_rm.assert_called_once_with(
3671                array, volume, device_id, volume_name,
3672                extra_specs, True, self.data.connector, async_grp=None)
3673
3674    def test_unmap_lun(self):
3675        array = self.data.array
3676        device_id = self.data.device_id
3677        volume = self.data.test_volume
3678        extra_specs = deepcopy(self.data.extra_specs_intervals_set)
3679        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
3680        connector = self.data.connector
3681        with mock.patch.object(self.common, '_remove_members'):
3682            self.common._unmap_lun(volume, connector)
3683            self.common._remove_members.assert_called_once_with(
3684                array, volume, device_id, extra_specs,
3685                connector, async_grp=None)
3686
3687    def test_unmap_lun_qos(self):
3688        array = self.data.array
3689        device_id = self.data.device_id
3690        volume = self.data.test_volume
3691        extra_specs = deepcopy(self.data.extra_specs_intervals_set)
3692        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
3693        extra_specs['qos'] = {
3694            'total_iops_sec': '4000', 'DistributionType': 'Always'}
3695        connector = self.data.connector
3696        with mock.patch.object(self.common, '_remove_members'):
3697            with mock.patch.object(self.utils, 'get_volumetype_extra_specs',
3698                                   return_value=extra_specs):
3699                self.common._unmap_lun(volume, connector)
3700                self.common._remove_members.assert_called_once_with(
3701                    array, volume, device_id, extra_specs,
3702                    connector, async_grp=None)
3703
3704    def test_unmap_lun_not_mapped(self):
3705        volume = self.data.test_volume
3706        connector = self.data.connector
3707        with mock.patch.object(self.common, 'find_host_lun_id',
3708                               return_value=({}, False, [])):
3709            with mock.patch.object(self.common, '_remove_members'):
3710                self.common._unmap_lun(volume, connector)
3711                self.common._remove_members.assert_not_called()
3712
3713    def test_unmap_lun_connector_is_none(self):
3714        array = self.data.array
3715        device_id = self.data.device_id
3716        volume = self.data.test_volume
3717        extra_specs = deepcopy(self.data.extra_specs_intervals_set)
3718        extra_specs['storagetype:portgroupname'] = (
3719            self.data.port_group_name_f)
3720        with mock.patch.object(self.common, '_remove_members'):
3721            self.common._unmap_lun(volume, None)
3722            self.common._remove_members.assert_called_once_with(
3723                array, volume, device_id, extra_specs, None, async_grp=None)
3724
3725    def test_initialize_connection_already_mapped(self):
3726        volume = self.data.test_volume
3727        connector = self.data.connector
3728        host_lun = (self.data.maskingview[0]['maskingViewConnection'][0]
3729                    ['host_lun_address'])
3730        ref_dict = {'hostlunid': int(host_lun, 16),
3731                    'maskingview': self.data.masking_view_name_f,
3732                    'array': self.data.array,
3733                    'device_id': self.data.device_id}
3734        device_info_dict = self.common.initialize_connection(volume, connector)
3735        self.assertEqual(ref_dict, device_info_dict)
3736
3737    def test_initialize_connection_already_mapped_next_gen(self):
3738        with mock.patch.object(self.rest, 'is_next_gen_array',
3739                               return_value=True):
3740            volume = self.data.test_volume
3741            connector = self.data.connector
3742            host_lun = (self.data.maskingview[0]['maskingViewConnection'][0]
3743                        ['host_lun_address'])
3744            ref_dict = {'hostlunid': int(host_lun, 16),
3745                        'maskingview': self.data.masking_view_name_f,
3746                        'array': self.data.array,
3747                        'device_id': self.data.device_id}
3748            device_info_dict = self.common.initialize_connection(volume,
3749                                                                 connector)
3750            self.assertEqual(ref_dict, device_info_dict)
3751
3752    def test_initialize_connection_not_mapped(self):
3753        volume = self.data.test_volume
3754        connector = self.data.connector
3755        extra_specs = deepcopy(self.data.extra_specs_intervals_set)
3756        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
3757        masking_view_dict = self.common._populate_masking_dict(
3758            volume, connector, extra_specs)
3759        with mock.patch.object(self.common, 'find_host_lun_id',
3760                               return_value=({}, False, [])):
3761            with mock.patch.object(
3762                    self.common, '_attach_volume', return_value=(
3763                        {}, self.data.port_group_name_f)):
3764                device_info_dict = self.common.initialize_connection(volume,
3765                                                                     connector)
3766                self.assertEqual({}, device_info_dict)
3767                self.common._attach_volume.assert_called_once_with(
3768                    volume, connector, extra_specs, masking_view_dict, False)
3769
3770    @mock.patch.object(rest.VMAXRest, 'is_next_gen_array',
3771                       return_value=True)
3772    @mock.patch.object(common.VMAXCommon, 'find_host_lun_id',
3773                       return_value=({}, False, []))
3774    @mock.patch.object(common.VMAXCommon, '_attach_volume',
3775                       return_value=({}, VMAXCommonData.port_group_name_f))
3776    def test_initialize_connection_not_mapped_next_gen(self, mock_attach,
3777                                                       mock_id, mck_gen):
3778        volume = self.data.test_volume
3779        connector = self.data.connector
3780        device_info_dict = self.common.initialize_connection(
3781            volume, connector)
3782        self.assertEqual({}, device_info_dict)
3783
3784    def test_attach_volume_success(self):
3785        volume = self.data.test_volume
3786        connector = self.data.connector
3787        extra_specs = deepcopy(self.data.extra_specs)
3788        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
3789        masking_view_dict = self.common._populate_masking_dict(
3790            volume, connector, extra_specs)
3791        host_lun = (self.data.maskingview[0]['maskingViewConnection'][0]
3792                    ['host_lun_address'])
3793        ref_dict = {'hostlunid': int(host_lun, 16),
3794                    'maskingview': self.data.masking_view_name_f,
3795                    'array': self.data.array,
3796                    'device_id': self.data.device_id}
3797        with mock.patch.object(self.masking, 'setup_masking_view',
3798                               return_value={
3799                                   utils.PORTGROUPNAME:
3800                                       self.data.port_group_name_f}):
3801            device_info_dict, pg = self.common._attach_volume(
3802                volume, connector, extra_specs, masking_view_dict)
3803        self.assertEqual(ref_dict, device_info_dict)
3804
3805    @mock.patch.object(masking.VMAXMasking,
3806                       'check_if_rollback_action_for_masking_required')
3807    @mock.patch.object(masking.VMAXMasking, 'setup_masking_view',
3808                       return_value={})
3809    @mock.patch.object(common.VMAXCommon, 'find_host_lun_id',
3810                       return_value=({}, False, []))
3811    def test_attach_volume_failed(self, mock_lun, mock_setup, mock_rollback):
3812        volume = self.data.test_volume
3813        connector = self.data.connector
3814        extra_specs = deepcopy(self.data.extra_specs)
3815        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
3816        masking_view_dict = self.common._populate_masking_dict(
3817            volume, connector, extra_specs)
3818        self.assertRaises(exception.VolumeBackendAPIException,
3819                          self.common._attach_volume, volume,
3820                          connector, extra_specs,
3821                          masking_view_dict)
3822        device_id = self.data.device_id
3823        (mock_rollback.assert_called_once_with(
3824            self.data.array, volume, device_id, {}))
3825
3826    def test_terminate_connection(self):
3827        volume = self.data.test_volume
3828        connector = self.data.connector
3829        with mock.patch.object(self.common, '_unmap_lun'):
3830            self.common.terminate_connection(volume, connector)
3831            self.common._unmap_lun.assert_called_once_with(
3832                volume, connector)
3833
3834    @mock.patch.object(rest.VMAXRest, 'is_next_gen_array', return_value=True)
3835    @mock.patch.object(common.VMAXCommon, '_sync_check')
3836    @mock.patch.object(provision.VMAXProvision, 'extend_volume')
3837    def test_extend_volume_success(self, mock_extend, mock_sync, mock_newgen):
3838        volume = self.data.test_volume
3839        array = self.data.array
3840        device_id = self.data.device_id
3841        new_size = self.data.test_volume.size
3842        ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
3843        ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
3844        with mock.patch.object(self.rest, 'is_vol_in_rep_session',
3845                               side_effect=[(False, False, None),
3846                                            (False, True, None)]):
3847            self.common.extend_volume(volume, new_size)
3848            mock_extend.assert_called_once_with(
3849                array, device_id, new_size, ref_extra_specs)
3850        # Success, with snapshot, on new VMAX array
3851            mock_extend.reset_mock()
3852            self.common.extend_volume(volume, new_size)
3853            mock_extend.assert_called_once_with(
3854                array, device_id, new_size, ref_extra_specs)
3855
3856    def test_extend_volume_failed_snap_src(self):
3857        volume = self.data.test_volume
3858        new_size = self.data.test_volume.size
3859        with mock.patch.object(self.rest, 'is_vol_in_rep_session',
3860                               return_value=(False, True, None)):
3861            self.assertRaises(exception.VolumeBackendAPIException,
3862                              self.common.extend_volume, volume, new_size)
3863
3864    def test_extend_volume_failed_no_device_id(self):
3865        volume = self.data.test_volume
3866        new_size = self.data.test_volume.size
3867        with mock.patch.object(self.common, '_find_device_on_array',
3868                               return_value=None):
3869            self.assertRaises(exception.VolumeBackendAPIException,
3870                              self.common.extend_volume, volume, new_size)
3871
3872    def test_extend_volume_failed_wrong_size(self):
3873        volume = self.data.test_volume
3874        new_size = 1
3875        self.assertRaises(exception.VolumeBackendAPIException,
3876                          self.common.extend_volume, volume, new_size)
3877
3878    def test_update_volume_stats(self):
3879        data = self.common.update_volume_stats()
3880        self.assertEqual('CommonTests', data['volume_backend_name'])
3881
3882    def test_update_volume_stats_no_wlp(self):
3883        with mock.patch.object(self.common, '_update_srp_stats',
3884                               return_value=('123s#SRP_1#None#None',
3885                                             100, 90, 90, 10)):
3886            data = self.common.update_volume_stats()
3887            self.assertEqual('CommonTests', data['volume_backend_name'])
3888
3889    def test_set_config_file_and_get_extra_specs(self):
3890        volume = self.data.test_volume
3891        extra_specs, config_file, qos_specs = (
3892            self.common._set_config_file_and_get_extra_specs(volume))
3893        self.assertEqual(self.data.vol_type_extra_specs, extra_specs)
3894        self.assertEqual(self.fake_xml, config_file)
3895
3896    def test_set_config_file_and_get_extra_specs_no_specs(self):
3897        volume = self.data.test_volume
3898        ref_config = '/etc/cinder/cinder_dell_emc_config.xml'
3899        with mock.patch.object(self.utils, 'get_volumetype_extra_specs',
3900                               return_value=None):
3901            extra_specs, config_file, qos_specs = (
3902                self.common._set_config_file_and_get_extra_specs(volume))
3903            self.assertIsNone(extra_specs)
3904            self.assertEqual(ref_config, config_file)
3905
3906    def test_update_srp_stats_with_wl(self):
3907        with mock.patch.object(self.rest, 'get_srp_by_name',
3908                               return_value=self.data.srp_details):
3909            location_info, __, __, __, __ = self.common._update_srp_stats(
3910                self.data.array_info_wl)
3911            self.assertEqual(location_info, '000197800123#SRP_1#Diamond#OLTP')
3912
3913    def test_update_srp_stats_no_wl(self):
3914        with mock.patch.object(self.rest, 'get_srp_by_name',
3915                               return_value=self.data.srp_details):
3916            location_info, __, __, __, __ = self.common._update_srp_stats(
3917                self.data.array_info_no_wl)
3918            self.assertEqual(location_info, '000197800123#SRP_1#Diamond')
3919
3920    def test_find_device_on_array_success(self):
3921        volume = self.data.test_volume
3922        extra_specs = self.data.extra_specs
3923        ref_device_id = self.data.device_id
3924        founddevice_id = self.common._find_device_on_array(volume, extra_specs)
3925        self.assertEqual(ref_device_id, founddevice_id)
3926
3927    def test_find_device_on_array_provider_location_not_string(self):
3928        volume = fake_volume.fake_volume_obj(
3929            context='cxt', provider_location=None)
3930        extra_specs = self.data.extra_specs
3931        founddevice_id = self.common._find_device_on_array(
3932            volume, extra_specs)
3933        self.assertIsNone(founddevice_id)
3934
3935    def test_find_legacy_device_on_array(self):
3936        volume = self.data.test_legacy_vol
3937        extra_specs = self.data.extra_specs
3938        ref_device_id = self.data.device_id
3939        founddevice_id = self.common._find_device_on_array(volume, extra_specs)
3940        self.assertEqual(ref_device_id, founddevice_id)
3941
3942    def test_find_host_lun_id_attached(self):
3943        volume = self.data.test_volume
3944        extra_specs = self.data.extra_specs
3945        host = 'HostX'
3946        host_lun = (self.data.maskingview[0]['maskingViewConnection'][0]
3947                    ['host_lun_address'])
3948        ref_masked = {'hostlunid': int(host_lun, 16),
3949                      'maskingview': self.data.masking_view_name_f,
3950                      'array': self.data.array,
3951                      'device_id': self.data.device_id}
3952        maskedvols, __, __ = self.common.find_host_lun_id(
3953            volume, host, extra_specs)
3954        self.assertEqual(ref_masked, maskedvols)
3955
3956    def test_find_host_lun_id_not_attached(self):
3957        volume = self.data.test_volume
3958        extra_specs = self.data.extra_specs
3959        host = 'HostX'
3960        with mock.patch.object(self.rest, 'find_mv_connections_for_vol',
3961                               return_value=None):
3962            maskedvols, __, __ = self.common.find_host_lun_id(
3963                volume, host, extra_specs)
3964            self.assertEqual({}, maskedvols)
3965
3966    @mock.patch.object(common.VMAXCommon, 'get_remote_target_device',
3967                       return_value=VMAXCommonData.device_id2)
3968    def test_find_host_lun_id_rep_extra_specs(self, mock_tgt):
3969        self.common.find_host_lun_id(
3970            self.data.test_volume, 'HostX',
3971            self.data.extra_specs, self.data.rep_extra_specs)
3972        mock_tgt.assert_called_once()
3973
3974    def test_get_masking_views_from_volume(self):
3975        array = self.data.array
3976        device_id = self.data.device_id
3977        host = 'HostX'
3978        ref_mv_list = [self.data.masking_view_name_f]
3979        maskingview_list, __ = self.common.get_masking_views_from_volume(
3980            array, self.data.test_volume, device_id, host)
3981        self.assertEqual(ref_mv_list, maskingview_list)
3982        # is metro
3983        with mock.patch.object(self.utils, 'is_metro_device',
3984                               return_value=True):
3985            __, is_metro = self.common.get_masking_views_from_volume(
3986                array, self.data.test_volume, device_id, host)
3987            self.assertTrue(is_metro)
3988
3989    def test_get_masking_views_from_volume_wrong_host(self):
3990        array = self.data.array
3991        device_id = self.data.device_id
3992        host = 'DifferentHost'
3993        maskingview_list, __ = self.common.get_masking_views_from_volume(
3994            array, self.data.test_volume, device_id, host)
3995        self.assertEqual([], maskingview_list)
3996
3997    def test_find_host_lun_id_no_host_check(self):
3998        volume = self.data.test_volume
3999        extra_specs = self.data.extra_specs
4000        host_lun = (self.data.maskingview[0]['maskingViewConnection'][0]
4001                    ['host_lun_address'])
4002        ref_masked = {'hostlunid': int(host_lun, 16),
4003                      'maskingview': self.data.masking_view_name_f,
4004                      'array': self.data.array,
4005                      'device_id': self.data.device_id}
4006        maskedvols, __, __ = self.common.find_host_lun_id(
4007            volume, None, extra_specs)
4008        self.assertEqual(ref_masked, maskedvols)
4009
4010    def test_register_config_file_from_config_group_exists(self):
4011        config_group_name = 'CommonTests'
4012        config_file = self.common._register_config_file_from_config_group(
4013            config_group_name)
4014        self.assertEqual(self.fake_xml, config_file)
4015
4016    def test_register_config_file_from_config_group_does_not_exist(self):
4017        config_group_name = 'IncorrectName'
4018        self.assertRaises(exception.VolumeBackendAPIException,
4019                          self.common._register_config_file_from_config_group,
4020                          config_group_name)
4021
4022    def test_initial_setup_success(self):
4023        volume = self.data.test_volume
4024        ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
4025        ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4026        extra_specs = self.common._initial_setup(volume)
4027        self.assertEqual(ref_extra_specs, extra_specs)
4028
4029    def test_initial_setup_failed(self):
4030        volume = self.data.test_volume
4031        with mock.patch.object(self.utils, 'parse_file_to_get_array_map',
4032                               return_value=None):
4033            self.assertRaises(exception.VolumeBackendAPIException,
4034                              self.common._initial_setup, volume)
4035
4036    @mock.patch.object(common.VMAXCommon, 'get_remote_target_device',
4037                       return_value=VMAXCommonData.device_id2)
4038    def test_populate_masking_dict(self, mock_tgt):
4039        volume = self.data.test_volume
4040        connector = self.data.connector
4041        extra_specs = deepcopy(self.data.extra_specs)
4042        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4043        extra_specs[utils.WORKLOAD] = self.data.workload
4044        ref_mv_dict = self.data.masking_view_dict
4045        self.common.nextGen = False
4046        masking_view_dict = self.common._populate_masking_dict(
4047            volume, connector, extra_specs)
4048        self.assertEqual(ref_mv_dict, masking_view_dict)
4049        # Metro volume, pass in rep_extra_specs and retrieve target device
4050        rep_extra_specs = deepcopy(self.data.rep_extra_specs)
4051        rep_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4052        self.common._populate_masking_dict(
4053            volume, connector, extra_specs, rep_extra_specs)
4054        mock_tgt.assert_called_once()
4055        # device_id is None
4056        with mock.patch.object(self.common, '_find_device_on_array',
4057                               return_value=None):
4058            self.assertRaises(exception.VolumeBackendAPIException,
4059                              self.common._populate_masking_dict,
4060                              volume, connector, extra_specs)
4061
4062    def test_populate_masking_dict_no_slo(self):
4063        volume = self.data.test_volume
4064        connector = self.data.connector
4065        extra_specs = {
4066            'slo': None,
4067            'workload': None,
4068            'srp': self.data.srp,
4069            'array': self.data.array,
4070            utils.PORTGROUPNAME: self.data.port_group_name_f}
4071        ref_mv_dict = self.data.masking_view_dict_no_slo
4072        masking_view_dict = self.common._populate_masking_dict(
4073            volume, connector, extra_specs)
4074        self.assertEqual(ref_mv_dict, masking_view_dict)
4075
4076    def test_populate_masking_dict_compr_disabled(self):
4077        volume = self.data.test_volume
4078        connector = self.data.connector
4079        extra_specs = deepcopy(self.data.extra_specs)
4080        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4081        extra_specs[utils.DISABLECOMPRESSION] = "true"
4082        ref_mv_dict = self.data.masking_view_dict_compression_disabled
4083        extra_specs[utils.WORKLOAD] = self.data.workload
4084        masking_view_dict = self.common._populate_masking_dict(
4085            volume, connector, extra_specs)
4086        self.assertEqual(ref_mv_dict, masking_view_dict)
4087
4088    def test_populate_masking_dict_next_gen(self):
4089        volume = self.data.test_volume
4090        connector = self.data.connector
4091        extra_specs = deepcopy(self.data.extra_specs)
4092        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4093        self.common.nextGen = True
4094        masking_view_dict = self.common._populate_masking_dict(
4095            volume, connector, extra_specs)
4096        self.assertEqual('NONE', masking_view_dict[utils.WORKLOAD])
4097
4098    def test_create_cloned_volume(self):
4099        volume = self.data.test_clone_volume
4100        source_volume = self.data.test_volume
4101        extra_specs = self.data.extra_specs
4102        ref_dict = self.data.provider_location
4103        clone_dict = self.common._create_cloned_volume(
4104            volume, source_volume, extra_specs)
4105        self.assertEqual(ref_dict, clone_dict)
4106
4107    def test_create_cloned_volume_is_snapshot(self):
4108        volume = self.data.test_snapshot
4109        source_volume = self.data.test_volume
4110        extra_specs = self.data.extra_specs
4111        ref_dict = self.data.snap_location
4112        clone_dict = self.common._create_cloned_volume(
4113            volume, source_volume, extra_specs, True, False)
4114        self.assertEqual(ref_dict, clone_dict)
4115
4116    def test_create_cloned_volume_from_snapshot(self):
4117        volume = self.data.test_clone_volume
4118        source_volume = self.data.test_snapshot
4119        extra_specs = self.data.extra_specs
4120        ref_dict = self.data.provider_location
4121        clone_dict = self.common._create_cloned_volume(
4122            volume, source_volume, extra_specs, False, True)
4123        self.assertEqual(ref_dict, clone_dict)
4124
4125    def test_create_cloned_volume_not_licenced(self):
4126        volume = self.data.test_clone_volume
4127        source_volume = self.data.test_volume
4128        extra_specs = self.data.extra_specs
4129        with mock.patch.object(self.rest, 'is_snapvx_licensed',
4130                               return_value=False):
4131            self.assertRaises(exception.VolumeBackendAPIException,
4132                              self.common._create_cloned_volume,
4133                              volume, source_volume, extra_specs)
4134
4135    def test_parse_snap_info_found(self):
4136        ref_device_id = self.data.device_id
4137        ref_snap_name = self.data.snap_location['snap_name']
4138        sourcedevice_id, foundsnap_name = self.common._parse_snap_info(
4139            self.data.array, self.data.test_snapshot)
4140        self.assertEqual(ref_device_id, sourcedevice_id)
4141        self.assertEqual(ref_snap_name, foundsnap_name)
4142
4143    def test_parse_snap_info_not_found(self):
4144        ref_snap_name = None
4145        with mock.patch.object(self.rest, 'get_volume_snap',
4146                               return_value=None):
4147            __, foundsnap_name = self.common._parse_snap_info(
4148                self.data.array, self.data.test_snapshot)
4149            self.assertIsNone(ref_snap_name, foundsnap_name)
4150
4151    def test_parse_snap_info_exception(self):
4152        with mock.patch.object(
4153                self.rest, 'get_volume_snap',
4154                side_effect=exception.VolumeBackendAPIException):
4155            __, foundsnap_name = self.common._parse_snap_info(
4156                self.data.array, self.data.test_snapshot)
4157            self.assertIsNone(foundsnap_name)
4158
4159    def test_parse_snap_info_provider_location_not_string(self):
4160        snapshot = fake_snapshot.fake_snapshot_obj(
4161            context='ctxt', provider_loaction={'not': 'string'})
4162        sourcedevice_id, foundsnap_name = self.common._parse_snap_info(
4163            self.data.array, snapshot)
4164        self.assertIsNone(foundsnap_name)
4165
4166    def test_create_snapshot_success(self):
4167        array = self.data.array
4168        snapshot = self.data.test_snapshot
4169        source_device_id = self.data.device_id
4170        extra_specs = self.data.extra_specs
4171        ref_dict = {'snap_name': self.data.test_snapshot_snap_name,
4172                    'source_id': self.data.device_id}
4173        snap_dict = self.common._create_snapshot(
4174            array, snapshot, source_device_id, extra_specs)
4175        self.assertEqual(ref_dict, snap_dict)
4176
4177    def test_create_snapshot_exception(self):
4178        array = self.data.array
4179        snapshot = self.data.test_snapshot
4180        source_device_id = self.data.device_id
4181        extra_specs = self.data.extra_specs
4182        with mock.patch.object(
4183                self.provision, 'create_volume_snapvx',
4184                side_effect=exception.VolumeBackendAPIException):
4185            self.assertRaises(exception.VolumeBackendAPIException,
4186                              self.common._create_snapshot,
4187                              array, snapshot, source_device_id, extra_specs)
4188
4189    @mock.patch.object(masking.VMAXMasking, 'remove_vol_from_storage_group')
4190    def test_delete_volume_from_srp(self, mock_rm):
4191        array = self.data.array
4192        device_id = self.data.device_id
4193        volume_name = self.data.test_volume.name
4194        ref_extra_specs = self.data.extra_specs_intervals_set
4195        ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4196        volume = self.data.test_volume
4197        with mock.patch.object(self.common, '_sync_check'):
4198            with mock.patch.object(self.common, '_delete_from_srp'):
4199                self.common._delete_volume(volume)
4200                self.common._delete_from_srp.assert_called_once_with(
4201                    array, device_id, volume_name, ref_extra_specs)
4202
4203    def test_delete_volume_not_found(self):
4204        volume = self.data.test_volume
4205        with mock.patch.object(self.common, '_find_device_on_array',
4206                               return_value=None):
4207            with mock.patch.object(self.common, '_delete_from_srp'):
4208                self.common._delete_volume(volume)
4209                self.common._delete_from_srp.assert_not_called()
4210
4211    def test_create_volume_success(self):
4212        volume_name = '1'
4213        volume_size = self.data.test_volume.size
4214        extra_specs = self.data.extra_specs
4215        ref_dict = self.data.provider_location
4216        volume_dict = self.common._create_volume(
4217            volume_name, volume_size, extra_specs)
4218        self.assertEqual(ref_dict, volume_dict)
4219
4220    def test_create_volume_success_next_gen(self):
4221        volume_name = '1'
4222        volume_size = self.data.test_volume.size
4223        extra_specs = self.data.extra_specs
4224        self.common.nextGen = True
4225        with mock.patch.object(self.utils, 'is_compression_disabled',
4226                               return_value=True):
4227            with mock.patch.object(self.rest, 'is_next_gen_array',
4228                                   return_value=True):
4229                with mock.patch.object(self.masking,
4230                                       'get_or_create_default_storage_group'):
4231                    self.common._create_volume(
4232                        volume_name, volume_size, extra_specs)
4233                    (self.masking.get_or_create_default_storage_group
4234                        .assert_called_once_with(extra_specs['array'],
4235                                                 extra_specs[utils.SRP],
4236                                                 extra_specs[utils.SLO],
4237                                                 'NONE', extra_specs, True))
4238
4239    def test_create_volume_failed(self):
4240        volume_name = self.data.test_volume.name
4241        volume_size = self.data.test_volume.size
4242        extra_specs = self.data.extra_specs
4243        with mock.patch.object(self.masking,
4244                               'get_or_create_default_storage_group',
4245                               return_value=self.data.failed_resource):
4246            with mock.patch.object(self.rest, 'delete_storage_group'):
4247                # path 1: not last vol in sg
4248                with mock.patch.object(self.rest, 'get_num_vols_in_sg',
4249                                       return_value=2):
4250                    self.assertRaises(exception.VolumeBackendAPIException,
4251                                      self.common._create_volume,
4252                                      volume_name, volume_size, extra_specs)
4253                    self.rest.delete_storage_group.assert_not_called()
4254                # path 2: last vol in sg, delete sg
4255                with mock.patch.object(self.rest, 'get_num_vols_in_sg',
4256                                       return_value=0):
4257                    self.assertRaises(exception.VolumeBackendAPIException,
4258                                      self.common._create_volume,
4259                                      volume_name, volume_size, extra_specs)
4260                    (self.rest.delete_storage_group.
4261                     assert_called_once_with(self.data.array,
4262                                             self.data.failed_resource))
4263
4264    def test_create_volume_incorrect_slo(self):
4265        volume_name = self.data.test_volume.name
4266        volume_size = self.data.test_volume.size
4267        extra_specs = {'slo': 'Diamondz',
4268                       'workload': 'DSSSS',
4269                       'srp': self.data.srp,
4270                       'array': self.data.array}
4271        self.assertRaises(
4272            exception.VolumeBackendAPIException,
4273            self.common._create_volume,
4274            volume_name, volume_size, extra_specs)
4275
4276    def test_set_vmax_extra_specs(self):
4277        srp_record = self.utils.parse_file_to_get_array_map(
4278            self.fake_xml)
4279        extra_specs = self.common._set_vmax_extra_specs(
4280            self.data.vol_type_extra_specs, srp_record)
4281        ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
4282        ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4283        self.assertEqual(ref_extra_specs, extra_specs)
4284
4285    def test_set_vmax_extra_specs_no_srp_name(self):
4286        with mock.patch.object(self.rest, 'get_slo_list',
4287                               return_value=[]):
4288            extra_specs = self.common._set_vmax_extra_specs(
4289                {}, self.data.array_info_wl)
4290            self.assertIsNone(extra_specs['slo'])
4291
4292    def test_set_vmax_extra_specs_compr_disabled(self):
4293        with mock.patch.object(self.rest, 'is_compression_capable',
4294                               return_value=True):
4295            srp_record = self.utils.parse_file_to_get_array_map(
4296                self.fake_xml)
4297            extra_specs = self.common._set_vmax_extra_specs(
4298                self.data.vol_type_extra_specs_compr_disabled, srp_record)
4299            ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
4300            ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4301            ref_extra_specs[utils.DISABLECOMPRESSION] = "true"
4302            self.assertEqual(ref_extra_specs, extra_specs)
4303
4304    def test_set_vmax_extra_specs_compr_disabled_not_compr_capable(self):
4305        srp_record = self.utils.parse_file_to_get_array_map(
4306            self.fake_xml)
4307        extra_specs = self.common._set_vmax_extra_specs(
4308            self.data.vol_type_extra_specs_compr_disabled, srp_record)
4309        ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
4310        ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4311        self.assertEqual(ref_extra_specs, extra_specs)
4312
4313    def test_set_vmax_extra_specs_portgroup_as_spec(self):
4314        srp_record = self.utils.parse_file_to_get_array_map(
4315            self.fake_xml)
4316        extra_specs = self.common._set_vmax_extra_specs(
4317            {utils.PORTGROUPNAME: 'extra_spec_pg'}, srp_record)
4318        self.assertEqual('extra_spec_pg', extra_specs[utils.PORTGROUPNAME])
4319
4320    def test_set_vmax_extra_specs_no_portgroup_set(self):
4321        fake_xml = FakeXML().create_fake_config_file(
4322            'test_no_pg_set', '')
4323        srp_record = self.utils.parse_file_to_get_array_map(fake_xml)
4324        self.assertRaises(exception.VolumeBackendAPIException,
4325                          self.common._set_vmax_extra_specs,
4326                          {}, srp_record)
4327
4328    def test_set_vmax_extra_specs_next_gen(self):
4329        srp_record = self.utils.parse_file_to_get_array_map(
4330            self.fake_xml)
4331        self.common.nextGen = True
4332        extra_specs = self.common._set_vmax_extra_specs(
4333            self.data.vol_type_extra_specs, srp_record)
4334        ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
4335        ref_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4336        self.assertEqual('NONE', extra_specs[utils.WORKLOAD])
4337
4338    def test_delete_volume_from_srp_success(self):
4339        array = self.data.array
4340        device_id = self.data.device_id
4341        volume_name = self.data.test_volume.name
4342        extra_specs = self.data.extra_specs
4343        with mock.patch.object(
4344                self.provision, 'delete_volume_from_srp') as mock_del:
4345            self.common._delete_from_srp(array, device_id, volume_name,
4346                                         extra_specs)
4347            mock_del.assert_called_once_with(array, device_id, volume_name)
4348
4349    def test_delete_volume_from_srp_failed(self):
4350        array = self.data.array
4351        device_id = self.data.failed_resource
4352        volume_name = self.data.test_volume.name
4353        extra_specs = self.data.extra_specs
4354        with mock.patch.object(self.masking,
4355                               'add_volume_to_default_storage_group'):
4356            self.assertRaises(exception.VolumeBackendAPIException,
4357                              self.common._delete_from_srp, array,
4358                              device_id, volume_name, extra_specs)
4359            (self.masking.add_volume_to_default_storage_group.
4360                assert_called_once_with(
4361                    array, device_id, volume_name, extra_specs))
4362
4363    @mock.patch.object(utils.VMAXUtils, 'is_replication_enabled',
4364                       side_effect=[False, True])
4365    def test_remove_vol_and_cleanup_replication(self, mock_rep_enabled):
4366        array = self.data.array
4367        device_id = self.data.device_id
4368        volume = self.data.test_volume
4369        volume_name = self.data.test_volume.name
4370        extra_specs = self.data.extra_specs
4371        with mock.patch.object(
4372                self.masking, 'remove_and_reset_members') as mock_rm:
4373            with mock.patch.object(
4374                    self.common, 'cleanup_lun_replication') as mock_clean:
4375                self.common._remove_vol_and_cleanup_replication(
4376                    array, device_id, volume_name, extra_specs, volume)
4377                mock_rm.assert_called_once_with(
4378                    array, volume, device_id, volume_name, extra_specs, False)
4379                mock_clean.assert_not_called()
4380                self.common._remove_vol_and_cleanup_replication(
4381                    array, device_id, volume_name, extra_specs, volume)
4382                mock_clean.assert_called_once_with(
4383                    volume, volume_name, device_id, extra_specs)
4384
4385    @mock.patch.object(utils.VMAXUtils, 'is_volume_failed_over',
4386                       side_effect=[True, False])
4387    @mock.patch.object(common.VMAXCommon, '_get_replication_extra_specs',
4388                       return_value=VMAXCommonData.rep_extra_specs)
4389    def test_get_target_wwns_from_masking_view(self, mock_rep_specs, mock_fo):
4390        ref_wwns = [self.data.wwnn1]
4391        for x in range(0, 2):
4392            target_wwns = self.common._get_target_wwns_from_masking_view(
4393                self.data.device_id, self.data.connector['host'],
4394                self.data.extra_specs)
4395            self.assertEqual(ref_wwns, target_wwns)
4396
4397    @mock.patch.object(common.VMAXCommon, 'get_port_group_from_masking_view',
4398                       return_value=None)
4399    def test_get_target_wwns_from_masking_view_no_mv(self, mock_pgmv):
4400        with mock.patch.object(self.common, '_get_masking_views_from_volume',
4401                               return_value=[]):
4402            self.common._get_target_wwns_from_masking_view(
4403                self.data.device_id, self.data.connector['host'],
4404                self.data.extra_specs)
4405            mock_pgmv.assert_not_called()
4406
4407    @mock.patch.object(common.VMAXCommon, '_get_replication_extra_specs',
4408                       return_value=VMAXCommonData.rep_extra_specs)
4409    @mock.patch.object(common.VMAXCommon, 'get_remote_target_device',
4410                       return_value=(VMAXCommonData.device_id2,))
4411    @mock.patch.object(utils.VMAXUtils, 'is_metro_device',
4412                       side_effect=[False, True])
4413    def test_get_target_wwns(self, mock_metro, mock_tgt, mock_specs):
4414        __, metro_wwns = self.common.get_target_wwns_from_masking_view(
4415            self.data.test_volume, self.data.connector)
4416        self.assertEqual([], metro_wwns)
4417        # Is metro volume
4418        __, metro_wwns = self.common.get_target_wwns_from_masking_view(
4419            self.data.test_volume, self.data.connector)
4420        self.assertEqual([self.data.wwnn1], metro_wwns)
4421
4422    def test_get_port_group_from_masking_view(self):
4423        array = self.data.array
4424        maskingview_name = self.data.masking_view_name_f
4425        with mock.patch.object(self.rest,
4426                               'get_element_from_masking_view'):
4427            self.common.get_port_group_from_masking_view(
4428                array, maskingview_name)
4429            self.rest.get_element_from_masking_view.assert_called_once_with(
4430                array, maskingview_name, portgroup=True)
4431
4432    def test_get_initiator_group_from_masking_view(self):
4433        array = self.data.array
4434        maskingview_name = self.data.masking_view_name_f
4435        with mock.patch.object(self.rest,
4436                               'get_element_from_masking_view'):
4437            self.common.get_initiator_group_from_masking_view(
4438                array, maskingview_name)
4439            self.rest.get_element_from_masking_view.assert_called_once_with(
4440                array, maskingview_name, host=True)
4441
4442    def test_get_common_masking_views(self):
4443        array = self.data.array
4444        portgroup_name = self.data.port_group_name_f
4445        initiator_group_name = self.data.initiatorgroup_name_f
4446        with mock.patch.object(self.rest, 'get_common_masking_views'):
4447            self.common.get_common_masking_views(
4448                array, portgroup_name, initiator_group_name)
4449            self.rest.get_common_masking_views.assert_called_once_with(
4450                array, portgroup_name, initiator_group_name)
4451
4452    def test_get_ip_and_iqn(self):
4453        ref_ip_iqn = [{'iqn': self.data.initiator,
4454                       'ip': self.data.ip}]
4455        port = self.data.portgroup[1]['symmetrixPortKey'][0]['portId']
4456        ip_iqn_list = self.common._get_ip_and_iqn(self.data.array, port)
4457        self.assertEqual(ref_ip_iqn, ip_iqn_list)
4458
4459    def test_find_ip_and_iqns(self):
4460        ref_ip_iqn = [{'iqn': self.data.initiator,
4461                       'ip': self.data.ip}]
4462        ip_iqn_list = self.common._find_ip_and_iqns(
4463            self.data.array, self.data.port_group_name_i)
4464        self.assertEqual(ref_ip_iqn, ip_iqn_list)
4465
4466    def test_create_replica_snap_name(self):
4467        array = self.data.array
4468        clone_volume = self.data.test_clone_volume
4469        source_device_id = self.data.device_id
4470        snap_name = self.data.snap_location['snap_name']
4471        ref_dict = self.data.provider_location
4472        clone_dict = self.common._create_replica(
4473            array, clone_volume, source_device_id,
4474            self.data.extra_specs, snap_name)
4475        self.assertEqual(ref_dict, clone_dict)
4476
4477    def test_create_replica_no_snap_name(self):
4478        array = self.data.array
4479        clone_volume = self.data.test_clone_volume
4480        source_device_id = self.data.device_id
4481        snap_name = "temp-" + source_device_id + clone_volume.id
4482        ref_dict = self.data.provider_location
4483        with mock.patch.object(self.utils, 'get_temp_snap_name',
4484                               return_value=snap_name):
4485            clone_dict = self.common._create_replica(
4486                array, clone_volume, source_device_id,
4487                self.data.extra_specs)
4488            self.assertEqual(ref_dict, clone_dict)
4489            self.utils.get_temp_snap_name.assert_called_once_with(
4490                ('OS-' + clone_volume.id), source_device_id)
4491
4492    def test_create_replica_failed_cleanup_target(self):
4493        array = self.data.array
4494        clone_volume = self.data.test_clone_volume
4495        device_id = self.data.device_id
4496        snap_name = self.data.failed_resource
4497        clone_name = 'OS-' + clone_volume.id
4498        extra_specs = self.data.extra_specs
4499        with mock.patch.object(self.common, '_cleanup_target'):
4500            self.assertRaises(
4501                exception.VolumeBackendAPIException,
4502                self.common._create_replica, array, clone_volume,
4503                device_id, self.data.extra_specs, snap_name)
4504            self.common._cleanup_target.assert_called_once_with(
4505                array, device_id, device_id, clone_name,
4506                snap_name, extra_specs)
4507
4508    def test_create_replica_failed_no_target(self):
4509        array = self.data.array
4510        clone_volume = self.data.test_clone_volume
4511        source_device_id = self.data.device_id
4512        snap_name = self.data.failed_resource
4513        with mock.patch.object(self.common, '_create_volume',
4514                               return_value={'device_id': None}):
4515            with mock.patch.object(self.common, '_cleanup_target'):
4516                self.assertRaises(
4517                    exception.VolumeBackendAPIException,
4518                    self.common._create_replica, array, clone_volume,
4519                    source_device_id, self.data.extra_specs, snap_name)
4520                self.common._cleanup_target.assert_not_called()
4521
4522    @mock.patch.object(
4523        masking.VMAXMasking,
4524        'remove_and_reset_members')
4525    def test_cleanup_target_sync_present(self, mock_remove):
4526        array = self.data.array
4527        clone_volume = self.data.test_clone_volume
4528        source_device_id = self.data.device_id
4529        target_device_id = self.data.device_id2
4530        snap_name = self.data.failed_resource
4531        clone_name = clone_volume.name
4532        extra_specs = self.data.extra_specs
4533        with mock.patch.object(self.rest, 'get_sync_session',
4534                               return_value='session'):
4535            with mock.patch.object(self.provision,
4536                                   'break_replication_relationship'):
4537                self.common._cleanup_target(
4538                    array, target_device_id, source_device_id,
4539                    clone_name, snap_name, extra_specs)
4540                (self.provision.break_replication_relationship.
4541                    assert_called_with(
4542                        array, target_device_id, source_device_id,
4543                        snap_name, extra_specs))
4544
4545    def test_cleanup_target_no_sync(self):
4546        array = self.data.array
4547        clone_volume = self.data.test_clone_volume
4548        source_device_id = self.data.device_id
4549        target_device_id = self.data.device_id2
4550        snap_name = self.data.failed_resource
4551        clone_name = clone_volume.name
4552        extra_specs = self.data.extra_specs
4553        with mock.patch.object(self.rest, 'get_sync_session',
4554                               return_value=None):
4555            with mock.patch.object(self.common,
4556                                   '_delete_from_srp'):
4557                self.common._cleanup_target(
4558                    array, target_device_id, source_device_id,
4559                    clone_name, snap_name, extra_specs)
4560                self.common._delete_from_srp.assert_called_once_with(
4561                    array, target_device_id, clone_name,
4562                    extra_specs)
4563
4564    @mock.patch.object(
4565        provision.VMAXProvision,
4566        'delete_volume_snap')
4567    @mock.patch.object(
4568        provision.VMAXProvision,
4569        'break_replication_relationship')
4570    def test_sync_check_temp_snap(self, mock_break, mock_delete):
4571        array = self.data.array
4572        device_id = self.data.device_id
4573        target = self.data.volume_details[1]['volumeId']
4574        volume_name = self.data.test_volume.name
4575        extra_specs = self.data.extra_specs
4576        snap_name = 'temp-1'
4577        with mock.patch.object(self.rest, 'get_volume_snap',
4578                               return_value=snap_name):
4579            self.common._sync_check(array, device_id, volume_name,
4580                                    extra_specs)
4581            mock_break.assert_called_with(
4582                array, target, device_id, snap_name, extra_specs)
4583            mock_delete.assert_called_with(array, snap_name, device_id)
4584        # Delete legacy temp snap
4585        mock_delete.reset_mock()
4586        snap_name2 = 'EMC_SMI_12345'
4587        sessions = [{'source_vol': device_id,
4588                     'snap_name': snap_name2,
4589                     'target_vol_list': []}]
4590        with mock.patch.object(self.rest, 'find_snap_vx_sessions',
4591                               return_value=sessions):
4592            with mock.patch.object(self.rest, 'get_volume_snap',
4593                                   return_value=snap_name2):
4594                self.common._sync_check(array, device_id, volume_name,
4595                                        extra_specs)
4596                mock_delete.assert_called_once_with(
4597                    array, snap_name2, device_id)
4598
4599    @mock.patch.object(
4600        provision.VMAXProvision,
4601        'delete_volume_snap')
4602    @mock.patch.object(
4603        provision.VMAXProvision,
4604        'break_replication_relationship')
4605    def test_sync_check_not_temp_snap(self, mock_break, mock_delete):
4606        array = self.data.array
4607        device_id = self.data.device_id
4608        target = self.data.volume_details[1]['volumeId']
4609        volume_name = self.data.test_volume.name
4610        extra_specs = self.data.extra_specs
4611        snap_name = 'OS-1'
4612        sessions = [{'source_vol': device_id,
4613                     'snap_name': snap_name,
4614                     'target_vol_list': [target]}]
4615        with mock.patch.object(self.rest, 'find_snap_vx_sessions',
4616                               return_value=sessions):
4617            self.common._sync_check(array, device_id, volume_name,
4618                                    extra_specs)
4619            mock_break.assert_called_with(
4620                array, target, device_id, snap_name, extra_specs)
4621            mock_delete.assert_not_called()
4622
4623    @mock.patch.object(
4624        provision.VMAXProvision,
4625        'break_replication_relationship')
4626    def test_sync_check_no_sessions(self, mock_break):
4627        array = self.data.array
4628        device_id = self.data.device_id
4629        volume_name = self.data.test_volume.name
4630        extra_specs = self.data.extra_specs
4631        with mock.patch.object(self.rest, 'find_snap_vx_sessions',
4632                               return_value=None):
4633            self.common._sync_check(array, device_id, volume_name,
4634                                    extra_specs)
4635            mock_break.assert_not_called()
4636
4637    def test_manage_existing_success(self):
4638        external_ref = {u'source-name': u'00002'}
4639        provider_location = {'device_id': u'00002', 'array': u'000197800123'}
4640        ref_update = {'provider_location': six.text_type(provider_location)}
4641        with mock.patch.object(
4642                self.common, '_check_lun_valid_for_cinder_management'):
4643            model_update = self.common.manage_existing(
4644                self.data.test_volume, external_ref)
4645            self.assertEqual(ref_update, model_update)
4646
4647    @mock.patch.object(
4648        rest.VMAXRest, 'get_masking_views_from_storage_group',
4649        return_value=None)
4650    @mock.patch.object(
4651        rest.VMAXRest, 'is_vol_in_rep_session',
4652        return_value=(False, False, None))
4653    def test_check_lun_valid_for_cinder_management(self, mock_rep, mock_mv):
4654        external_ref = {u'source-name': u'00003'}
4655        self.common._check_lun_valid_for_cinder_management(
4656            self.data.array, self.data.device_id3,
4657            self.data.test_volume.id, external_ref)
4658
4659    @mock.patch.object(
4660        rest.VMAXRest, 'get_volume',
4661        side_effect=[
4662            None,
4663            VMAXCommonData.volume_details[2],
4664            VMAXCommonData.volume_details[2],
4665            VMAXCommonData.volume_details[1]])
4666    @mock.patch.object(
4667        rest.VMAXRest, 'get_masking_views_from_storage_group',
4668        side_effect=[VMAXCommonData.sg_details[1]['maskingview'],
4669                     None])
4670    @mock.patch.object(rest.VMAXRest, 'get_storage_groups_from_volume',
4671                       return_value=[VMAXCommonData.defaultstoragegroup_name])
4672    @mock.patch.object(rest.VMAXRest, 'is_vol_in_rep_session',
4673                       side_effect=[(True, False, []), (False, False, None)])
4674    def test_check_lun_valid_for_cinder_management_exception(
4675            self, mock_rep, mock_sg, mock_mvs, mock_get_vol):
4676        external_ref = {u'source-name': u'00003'}
4677        for x in range(0, 3):
4678            self.assertRaises(
4679                exception.ManageExistingInvalidReference,
4680                self.common._check_lun_valid_for_cinder_management,
4681                self.data.array, self.data.device_id3,
4682                self.data.test_volume.id, external_ref)
4683        self.assertRaises(exception.ManageExistingAlreadyManaged,
4684                          self.common._check_lun_valid_for_cinder_management,
4685                          self.data.array, self.data.device_id3,
4686                          self.data.test_volume.id, external_ref)
4687
4688    def test_manage_existing_get_size(self):
4689        external_ref = {u'source-name': u'00001'}
4690        size = self.common.manage_existing_get_size(
4691            self.data.test_volume, external_ref)
4692        self.assertEqual(2, size)
4693
4694    def test_manage_existing_get_size_exception(self):
4695        external_ref = {u'source-name': u'00001'}
4696        with mock.patch.object(self.rest, 'get_size_of_device_on_array',
4697                               return_value=3.5):
4698            self.assertRaises(exception.ManageExistingInvalidReference,
4699                              self.common.manage_existing_get_size,
4700                              self.data.test_volume, external_ref)
4701
4702    @mock.patch.object(common.VMAXCommon,
4703                       '_remove_vol_and_cleanup_replication')
4704    def test_unmanage_success(self, mock_rm):
4705        volume = self.data.test_volume
4706        with mock.patch.object(self.rest, 'rename_volume'):
4707            self.common.unmanage(volume)
4708            self.rest.rename_volume.assert_called_once_with(
4709                self.data.array, self.data.device_id,
4710                self.data.test_volume.id)
4711
4712    def test_unmanage_device_not_found(self):
4713        volume = self.data.test_volume
4714        with mock.patch.object(self.common, '_find_device_on_array',
4715                               return_value=None):
4716            with mock.patch.object(self.rest, 'rename_volume'):
4717                self.common.unmanage(volume)
4718                self.rest.rename_volume.assert_not_called()
4719
4720    @mock.patch.object(common.VMAXCommon,
4721                       '_slo_workload_migration')
4722    def test_retype(self, mock_migrate):
4723        device_id = self.data.device_id
4724        volume_name = self.data.test_volume.name
4725        extra_specs = self.data.extra_specs_intervals_set
4726        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
4727        volume = self.data.test_volume
4728        new_type = {'extra_specs': {}}
4729        host = {'host': self.data.new_host}
4730        self.common.retype(volume, new_type, host)
4731        mock_migrate.assert_called_once_with(
4732            device_id, volume, host, volume_name, new_type, extra_specs)
4733        mock_migrate.reset_mock()
4734        with mock.patch.object(
4735                self.common, '_find_device_on_array', return_value=None):
4736            self.common.retype(volume, new_type, host)
4737            mock_migrate.assert_not_called()
4738        mock_migrate.reset_mock()
4739        volume2 = self.data.test_attached_volume
4740        self.common.retype(volume2, new_type, host)
4741        mock_migrate.assert_not_called()
4742
4743    def test_slo_workload_migration_valid(self):
4744        device_id = self.data.device_id
4745        volume_name = self.data.test_volume.name
4746        extra_specs = self.data.extra_specs
4747        new_type = {'extra_specs': {}}
4748        volume = self.data.test_volume
4749        host = {'host': self.data.new_host}
4750        with mock.patch.object(self.common, '_migrate_volume'):
4751            self.common._slo_workload_migration(
4752                device_id, volume, host, volume_name, new_type, extra_specs)
4753            self.common._migrate_volume.assert_called_once_with(
4754                extra_specs[utils.ARRAY], volume, device_id,
4755                extra_specs[utils.SRP], 'Silver',
4756                'OLTP', volume_name, new_type, extra_specs)
4757
4758    def test_slo_workload_migration_not_valid(self):
4759        device_id = self.data.device_id
4760        volume_name = self.data.test_volume.name
4761        extra_specs = self.data.extra_specs
4762        volume = self.data.test_volume
4763        new_type = {'extra_specs': {}}
4764        host = {'host': self.data.new_host}
4765        with mock.patch.object(self.common,
4766                               '_is_valid_for_storage_assisted_migration',
4767                               return_value=(False, 'Silver', 'OLTP')):
4768            migrate_status = self.common._slo_workload_migration(
4769                device_id, volume, host, volume_name, new_type, extra_specs)
4770            self.assertFalse(migrate_status)
4771
4772    def test_slo_workload_migration_same_hosts(self):
4773        device_id = self.data.device_id
4774        volume_name = self.data.test_volume.name
4775        extra_specs = self.data.extra_specs
4776        volume = self.data.test_volume
4777        host = {'host': self.data.fake_host}
4778        new_type = {'extra_specs': {}}
4779        migrate_status = self.common._slo_workload_migration(
4780            device_id, volume, host, volume_name, new_type, extra_specs)
4781        self.assertFalse(migrate_status)
4782
4783    def test_slo_workload_migration_same_host_change_compression(self):
4784        device_id = self.data.device_id
4785        volume_name = self.data.test_volume.name
4786        extra_specs = self.data.extra_specs
4787        volume = self.data.test_volume
4788        host = {'host': self.data.fake_host}
4789        new_type = {'extra_specs': {utils.DISABLECOMPRESSION: "true"}}
4790        with mock.patch.object(
4791                self.common, '_is_valid_for_storage_assisted_migration',
4792                return_value=(True, self.data.slo, self.data.workload)):
4793            with mock.patch.object(self.common, '_migrate_volume'):
4794                migrate_status = self.common._slo_workload_migration(
4795                    device_id, volume, host, volume_name, new_type,
4796                    extra_specs)
4797                self.assertTrue(bool(migrate_status))
4798                self.common._migrate_volume.assert_called_once_with(
4799                    extra_specs[utils.ARRAY], volume, device_id,
4800                    extra_specs[utils.SRP], self.data.slo,
4801                    self.data.workload, volume_name, new_type, extra_specs)
4802
4803    @mock.patch.object(masking.VMAXMasking, 'remove_and_reset_members')
4804    def test_migrate_volume_success(self, mock_remove):
4805        with mock.patch.object(self.rest, 'is_volume_in_storagegroup',
4806                               return_value=True):
4807            device_id = self.data.device_id
4808            volume_name = self.data.test_volume.name
4809            extra_specs = self.data.extra_specs
4810            volume = self.data.test_volume
4811            new_type = {'extra_specs': {}}
4812            migrate_status = self.common._migrate_volume(
4813                self.data.array, volume, device_id, self.data.srp,
4814                self.data.slo, self.data.workload, volume_name,
4815                new_type, extra_specs)
4816            self.assertTrue(migrate_status)
4817            target_extra_specs = {
4818                'array': self.data.array, 'interval': 3,
4819                'retries': 120, 'slo': self.data.slo,
4820                'srp': self.data.srp, 'workload': self.data.workload}
4821            mock_remove.assert_called_once_with(
4822                self.data.array, volume, device_id, volume_name,
4823                target_extra_specs, reset=True)
4824            mock_remove.reset_mock()
4825            with mock.patch.object(
4826                    self.rest, 'get_storage_groups_from_volume',
4827                    return_value=[]):
4828                migrate_status = self.common._migrate_volume(
4829                    self.data.array, volume, device_id, self.data.srp,
4830                    self.data.slo, self.data.workload, volume_name,
4831                    new_type, extra_specs)
4832                self.assertTrue(migrate_status)
4833                mock_remove.assert_not_called()
4834
4835    @mock.patch.object(masking.VMAXMasking, 'remove_and_reset_members')
4836    def test_migrate_volume_failed_get_new_sg_failed(self, mock_remove):
4837        device_id = self.data.device_id
4838        volume_name = self.data.test_volume.name
4839        extra_specs = self.data.extra_specs
4840        new_type = {'extra_specs': {}}
4841        with mock.patch.object(
4842                self.masking, 'get_or_create_default_storage_group',
4843                side_effect=exception.VolumeBackendAPIException):
4844            migrate_status = self.common._migrate_volume(
4845                self.data.array, self.data.test_volume, device_id,
4846                self.data.srp, self.data.slo,
4847                self.data.workload, volume_name, new_type, extra_specs)
4848            self.assertFalse(migrate_status)
4849
4850    def test_migrate_volume_failed_vol_not_added(self):
4851        device_id = self.data.device_id
4852        volume_name = self.data.test_volume.name
4853        extra_specs = self.data.extra_specs
4854        new_type = {'extra_specs': {}}
4855        with mock.patch.object(
4856                self.rest, 'is_volume_in_storagegroup',
4857                return_value=False):
4858            migrate_status = self.common._migrate_volume(
4859                self.data.array, self.data.test_volume, device_id,
4860                self.data.srp, self.data.slo,
4861                self.data.workload, volume_name, new_type, extra_specs)
4862            self.assertFalse(migrate_status)
4863
4864    def test_is_valid_for_storage_assisted_migration_true(self):
4865        device_id = self.data.device_id
4866        host = {'host': self.data.new_host}
4867        volume_name = self.data.test_volume.name
4868        ref_return = (True, 'Silver', 'OLTP')
4869        return_val = self.common._is_valid_for_storage_assisted_migration(
4870            device_id, host, self.data.array,
4871            self.data.srp, volume_name, False)
4872        self.assertEqual(ref_return, return_val)
4873        # No current sgs found
4874        with mock.patch.object(self.rest, 'get_storage_groups_from_volume',
4875                               return_value=None):
4876            return_val = self.common._is_valid_for_storage_assisted_migration(
4877                device_id, host, self.data.array, self.data.srp,
4878                volume_name, False)
4879            self.assertEqual(ref_return, return_val)
4880        host = {'host': 'HostX@Backend#Silver+SRP_1+000197800123'}
4881        ref_return = (True, 'Silver', 'NONE')
4882        return_val = self.common._is_valid_for_storage_assisted_migration(
4883            device_id, host, self.data.array,
4884            self.data.srp, volume_name, False)
4885        self.assertEqual(ref_return, return_val)
4886
4887    def test_is_valid_for_storage_assisted_migration_false(self):
4888        device_id = self.data.device_id
4889        volume_name = self.data.test_volume.name
4890        ref_return = (False, None, None)
4891        # IndexError
4892        host = {'host': 'HostX@Backend#Silver+SRP_1+000197800123+dummy+data'}
4893        return_val = self.common._is_valid_for_storage_assisted_migration(
4894            device_id, host, self.data.array,
4895            self.data.srp, volume_name, False)
4896        self.assertEqual(ref_return, return_val)
4897        # Wrong array
4898        host2 = {'host': 'HostX@Backend#Silver+OLTP+SRP_1+00012345678'}
4899        return_val = self.common._is_valid_for_storage_assisted_migration(
4900            device_id, host2, self.data.array,
4901            self.data.srp, volume_name, False)
4902        self.assertEqual(ref_return, return_val)
4903        # Wrong srp
4904        host3 = {'host': 'HostX@Backend#Silver+OLTP+SRP_2+000197800123'}
4905        return_val = self.common._is_valid_for_storage_assisted_migration(
4906            device_id, host3, self.data.array,
4907            self.data.srp, volume_name, False)
4908        self.assertEqual(ref_return, return_val)
4909        # Already in correct sg
4910        host4 = {'host': self.data.fake_host}
4911        return_val = self.common._is_valid_for_storage_assisted_migration(
4912            device_id, host4, self.data.array,
4913            self.data.srp, volume_name, False)
4914        self.assertEqual(ref_return, return_val)
4915
4916    def test_is_valid_for_storage_assisted_migration_none(self):
4917        device_id = self.data.device_id
4918        host = {'host': self.data.none_host}
4919        volume_name = self.data.test_volume.name
4920        # Testing for 'NONE' Workload
4921        ref_return = (True, 'Diamond', 'NONE')
4922        return_val = self.common._is_valid_for_storage_assisted_migration(
4923            device_id, host, self.data.array,
4924            self.data.srp, volume_name, False)
4925        self.assertEqual(ref_return, return_val)
4926
4927    def test_is_valid_for_storage_assisted_migration_next_gen(self):
4928        device_id = self.data.device_id
4929        host = {'host': self.data.new_host}
4930        volume_name = self.data.test_volume.name
4931        ref_return = (True, 'Silver', 'NONE')
4932        with mock.patch.object(self.rest, 'is_next_gen_array',
4933                               return_value=True):
4934            return_val = self.common._is_valid_for_storage_assisted_migration(
4935                device_id, host, self.data.array,
4936                self.data.srp, volume_name, False)
4937            self.assertEqual(ref_return, return_val)
4938
4939    def test_find_volume_group(self):
4940        group = self.data.test_group_1
4941        array = self.data.array
4942        volume_group = self.common._find_volume_group(array, group)
4943        ref_group = self.data.sg_details_rep[0]
4944        self.assertEqual(ref_group, volume_group)
4945
4946    def test_get_volume_device_ids(self):
4947        array = self.data.array
4948        volumes = [self.data.test_volume]
4949        ref_device_ids = [self.data.device_id]
4950        device_ids = self.common._get_volume_device_ids(volumes, array)
4951        self.assertEqual(ref_device_ids, device_ids)
4952
4953    def test_get_members_of_volume_group(self):
4954        array = self.data.array
4955        group_name = self.data.storagegroup_name_source
4956        ref_volumes = [self.data.device_id, self.data.device_id2]
4957        member_device_ids = self.common._get_members_of_volume_group(
4958            array, group_name)
4959        self.assertEqual(ref_volumes, member_device_ids)
4960
4961    def test_get_members_of_volume_group_empty(self):
4962        array = self.data.array
4963        group_name = self.data.storagegroup_name_source
4964        with mock.patch.object(
4965                self.rest, 'get_volumes_in_storage_group',
4966                return_value=None):
4967            member_device_ids = self.common._get_members_of_volume_group(
4968                array, group_name
4969            )
4970        self.assertIsNone(member_device_ids)
4971
4972    @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
4973                       return_value=True)
4974    def test_create_group_replica(self, mock_check):
4975        source_group = self.data.test_group_1
4976        snap_name = self.data.group_snapshot_name
4977        with mock.patch.object(
4978                self.common,
4979                '_create_group_replica') as mock_create_replica:
4980            self.common._create_group_replica(
4981                source_group, snap_name)
4982            mock_create_replica.assert_called_once_with(
4983                source_group, snap_name)
4984
4985    def test_create_group_replica_exception(self):
4986        source_group = self.data.test_group_failed
4987        snap_name = self.data.group_snapshot_name
4988        with mock.patch.object(
4989                volume_utils, 'is_group_a_cg_snapshot_type',
4990                return_value=True):
4991            self.assertRaises(exception.VolumeBackendAPIException,
4992                              self.common._create_group_replica,
4993                              source_group,
4994                              snap_name)
4995
4996    def test_create_group_snapshot(self):
4997        context = None
4998        group_snapshot = self.data.test_group_snapshot_1
4999        snapshots = []
5000        ref_model_update = {'status': fields.GroupStatus.AVAILABLE}
5001        with mock.patch.object(
5002                volume_utils, 'is_group_a_cg_snapshot_type',
5003                return_value=True):
5004            model_update, snapshots_model_update = (
5005                self.common.create_group_snapshot(
5006                    context, group_snapshot, snapshots))
5007            self.assertEqual(ref_model_update, model_update)
5008
5009    def test_create_group_snapshot_exception(self):
5010        context = None
5011        group_snapshot = self.data.test_group_snapshot_failed
5012        snapshots = []
5013        with mock.patch.object(
5014                volume_utils, 'is_group_a_cg_snapshot_type',
5015                return_value=True):
5016            self.assertRaises(exception.VolumeBackendAPIException,
5017                              self.common.create_group_snapshot,
5018                              context,
5019                              group_snapshot,
5020                              snapshots)
5021
5022    @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5023                       return_value=True)
5024    @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
5025    def test_create_group(self, mock_type, mock_cg_type):
5026        ref_model_update = {'status': fields.GroupStatus.AVAILABLE}
5027        model_update = self.common.create_group(None, self.data.test_group_1)
5028        self.assertEqual(ref_model_update, model_update)
5029
5030    @mock.patch.object(provision.VMAXProvision, 'create_volume_group',
5031                       side_effect=exception.CinderException)
5032    @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
5033    def test_create_group_exception(self, mock_type, mock_create):
5034        context = None
5035        group = self.data.test_group_failed
5036        with mock.patch.object(
5037                volume_utils, 'is_group_a_cg_snapshot_type',
5038                return_value=True):
5039            self.assertRaises(exception.VolumeBackendAPIException,
5040                              self.common.create_group,
5041                              context, group)
5042
5043    def test_delete_group_snapshot(self):
5044        group_snapshot = self.data.test_group_snapshot_1
5045        snapshots = []
5046        context = None
5047        ref_model_update = {'status': fields.GroupSnapshotStatus.DELETED}
5048        with mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5049                               return_value=True):
5050            model_update, snapshots_model_update = (
5051                self.common.delete_group_snapshot(context,
5052                                                  group_snapshot, snapshots))
5053            self.assertEqual(ref_model_update, model_update)
5054
5055    def test_delete_group_snapshot_success(self):
5056        group_snapshot = self.data.test_group_snapshot_1
5057        snapshots = []
5058        ref_model_update = {'status': fields.GroupSnapshotStatus.DELETED}
5059        with mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5060                               return_value=True):
5061            model_update, snapshots_model_update = (
5062                self.common._delete_group_snapshot(group_snapshot,
5063                                                   snapshots))
5064            self.assertEqual(ref_model_update, model_update)
5065
5066    def test_delete_group_snapshot_failed(self):
5067        group_snapshot = self.data.test_group_snapshot_failed
5068        snapshots = []
5069        ref_model_update = (
5070            {'status': fields.GroupSnapshotStatus.ERROR_DELETING})
5071        with mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5072                               return_value=True):
5073            model_update, snapshots_model_update = (
5074                self.common._delete_group_snapshot(group_snapshot,
5075                                                   snapshots))
5076            self.assertEqual(ref_model_update, model_update)
5077
5078    @mock.patch.object(volume_utils, 'is_group_a_type',
5079                       return_value=False)
5080    @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5081                       return_value=True)
5082    def test_update_group(self, mock_cg_type, mock_type_check):
5083        group = self.data.test_group_1
5084        add_vols = [self.data.test_volume]
5085        remove_vols = []
5086        ref_model_update = {'status': fields.GroupStatus.AVAILABLE}
5087        model_update, __, __ = self.common.update_group(group,
5088                                                        add_vols,
5089                                                        remove_vols)
5090        self.assertEqual(ref_model_update, model_update)
5091
5092    @mock.patch.object(common.VMAXCommon, '_find_volume_group',
5093                       return_value=None)
5094    @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5095                       return_value=True)
5096    def test_update_group_not_found(self, mock_check, mock_grp):
5097        self.assertRaises(exception.GroupNotFound, self.common.update_group,
5098                          self.data.test_group_1, [], [])
5099
5100    @mock.patch.object(common.VMAXCommon, '_find_volume_group',
5101                       side_effect=exception.VolumeBackendAPIException)
5102    @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5103                       return_value=True)
5104    def test_update_group_exception(self, mock_check, mock_grp):
5105        self.assertRaises(exception.VolumeBackendAPIException,
5106                          self.common.update_group,
5107                          self.data.test_group_1, [], [])
5108
5109    @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
5110    def test_delete_group(self, mock_check):
5111        group = self.data.test_group_1
5112        volumes = [self.data.test_volume]
5113        context = None
5114        ref_model_update = {'status': fields.GroupStatus.DELETED}
5115        with mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5116                               return_value=True),\
5117                mock.patch.object(self.rest, 'get_volumes_in_storage_group',
5118                                  return_value=[]):
5119            model_update, __ = self.common.delete_group(
5120                context, group, volumes)
5121            self.assertEqual(ref_model_update, model_update)
5122
5123    @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
5124    def test_delete_group_success(self, mock_check):
5125        group = self.data.test_group_1
5126        volumes = []
5127        ref_model_update = {'status': fields.GroupStatus.DELETED}
5128        with mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5129                               return_value=True),\
5130                mock.patch.object(self.rest, 'get_volumes_in_storage_group',
5131                                  return_value=[]):
5132            model_update, __ = self.common._delete_group(group, volumes)
5133            self.assertEqual(ref_model_update, model_update)
5134
5135    def test_delete_group_already_deleted(self):
5136        group = self.data.test_group_failed
5137        ref_model_update = {'status': fields.GroupStatus.DELETED}
5138        volumes = []
5139        with mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5140                               return_value=True):
5141            model_update, __ = self.common._delete_group(group, volumes)
5142            self.assertEqual(ref_model_update, model_update)
5143
5144    @mock.patch.object(volume_utils, 'is_group_a_type', return_value=False)
5145    @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5146                       return_value=True)
5147    def test_delete_group_failed(self, mock_check, mock_type_check):
5148        group = self.data.test_group_1
5149        volumes = []
5150        ref_model_update = {'status': fields.GroupStatus.ERROR_DELETING}
5151        with mock.patch.object(
5152                self.rest, 'delete_storage_group',
5153                side_effect=exception.VolumeBackendAPIException):
5154            model_update, __ = self.common._delete_group(
5155                group, volumes)
5156        self.assertEqual(ref_model_update, model_update)
5157
5158    @mock.patch.object(
5159        common.VMAXCommon, '_get_clone_vol_info',
5160        return_value=(VMAXCommonData.device_id,
5161                      VMAXCommonData.extra_specs, 1, 'tgt_vol'))
5162    @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
5163                       return_value=True)
5164    @mock.patch.object(volume_utils, 'is_group_a_type',
5165                       return_value=False)
5166    def test_create_group_from_src_success(self, mock_type,
5167                                           mock_cg_type, mock_info):
5168        ref_model_update = {'status': fields.GroupStatus.AVAILABLE}
5169        model_update, volumes_model_update = (
5170            self.common.create_group_from_src(
5171                None, self.data.test_group_1, [self.data.test_volume],
5172                self.data.test_group_snapshot_1, [], None, []))
5173        self.assertEqual(ref_model_update, model_update)
5174
5175    @mock.patch.object(
5176        common.VMAXCommon, '_remove_vol_and_cleanup_replication')
5177    @mock.patch.object(
5178        masking.VMAXMasking, 'remove_volumes_from_storage_group')
5179    def test_rollback_create_group_from_src(
5180            self, mock_rm, mock_clean):
5181        rollback_dict = {
5182            'target_group_name': self.data.target_group_name,
5183            'snap_name': 'snap1', 'source_group_name': 'src_grp',
5184            'volumes': (self.data.device_id, self.data.extra_specs,
5185                        self.data.test_volume),
5186            'device_ids': [self.data.device_id],
5187            'interval_retries_dict': self.data.extra_specs}
5188        for x in range(0, 2):
5189            self.common._rollback_create_group_from_src(
5190                self.data.array, rollback_dict)
5191        self.assertEqual(2, mock_rm.call_count)
5192
5193    def test_get_snap_src_dev_list(self):
5194        src_dev_ids = self.common._get_snap_src_dev_list(
5195            self.data.array, [self.data.test_snapshot])
5196        ref_dev_ids = [self.data.device_id]
5197        self.assertEqual(ref_dev_ids, src_dev_ids)
5198
5199    def test_get_clone_vol_info(self):
5200        ref_dev_id = self.data.device_id
5201        source_vols = [self.data.test_volume,
5202                       self.data.test_attached_volume]
5203        src_snapshots = [self.data.test_snapshot]
5204        src_dev_id1, extra_specs1, vol_size1, tgt_vol_name1 = (
5205            self.common._get_clone_vol_info(
5206                self.data.test_clone_volume, source_vols, []))
5207        src_dev_id2, extra_specs2, vol_size2, tgt_vol_name2 = (
5208            self.common._get_clone_vol_info(
5209                self.data.test_clone_volume, [], src_snapshots))
5210        self.assertEqual(ref_dev_id, src_dev_id1)
5211        self.assertEqual(ref_dev_id, src_dev_id2)
5212
5213    def test_get_attributes_from_cinder_config(self):
5214        kwargs_expected = (
5215            {'RestServerIp': '1.1.1.1',
5216             'RestServerPort': 8443,
5217             'RestUserName': 'smc',
5218             'RestPassword': 'smc',
5219             'SSLVerify': False,
5220             'SerialNumber': self.data.array,
5221             'srpName': 'SRP_1',
5222             'PortGroup': self.data.port_group_name_i})
5223        backup_conf = self.common.configuration
5224        configuration = FakeConfiguration(
5225            None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
5226            vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
5227            san_rest_port=8443, vmax_port_groups=[self.data.port_group_name_i])
5228        self.common.configuration = configuration
5229        kwargs_returned = self.common.get_attributes_from_cinder_config()
5230        self.assertEqual(kwargs_expected, kwargs_returned)
5231        self.common.configuration = backup_conf
5232        kwargs = self.common.get_attributes_from_cinder_config()
5233        self.assertIsNone(kwargs)
5234
5235    def test_get_ssl_attributes_from_cinder_config(self):
5236        conf = FakeConfiguration(
5237            None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
5238            vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
5239            vmax_port_groups=[self.data.port_group_name_i],
5240            driver_ssl_cert_verify=True,
5241            driver_ssl_cert_path='/path/to/cert')
5242
5243        self.common.configuration = conf
5244        conf_returned = self.common.get_attributes_from_cinder_config()
5245        self.assertEqual('/path/to/cert', conf_returned['SSLVerify'])
5246
5247        conf.driver_ssl_cert_verify = True
5248        conf.driver_ssl_cert_path = None
5249        conf_returned = self.common.get_attributes_from_cinder_config()
5250        self.assertTrue(conf_returned['SSLVerify'])
5251
5252        conf.driver_ssl_cert_verify = False
5253        conf.driver_ssl_cert_path = None
5254        conf_returned = self.common.get_attributes_from_cinder_config()
5255        self.assertFalse(conf_returned['SSLVerify'])
5256
5257    @mock.patch.object(rest.VMAXRest,
5258                       'get_size_of_device_on_array',
5259                       return_value=2.0)
5260    def test_manage_snapshot_get_size_success(self, mock_get_size):
5261        size = self.common.manage_existing_snapshot_get_size(
5262            self.data.test_snapshot)
5263        self.assertEqual(2, size)
5264
5265    @mock.patch.object(rest.VMAXRest, 'get_volume_snap',
5266                       return_value={'snap_name': 'snap_name'})
5267    def test_manage_snapshot_success(self, mock_snap):
5268        snapshot = self.data.test_snapshot_manage
5269        existing_ref = {u'source-name': u'test_snap'}
5270        updates_response = self.common.manage_existing_snapshot(
5271            snapshot, existing_ref)
5272
5273        prov_loc = {'source_id': self.data.device_id,
5274                    'snap_name': 'OS-%s' % existing_ref['source-name']}
5275
5276        updates = {
5277            'display_name': self.data.test_snapshot_manage.display_name,
5278            'provider_location': six.text_type(prov_loc)}
5279
5280        self.assertEqual(updates_response, updates)
5281
5282    def test_manage_snapshot_fail_already_managed(self):
5283        snapshot = self.data.test_snapshot_manage
5284        existing_ref = {u'source-name': u'OS-test_snap'}
5285
5286        self.assertRaises(exception.VolumeBackendAPIException,
5287                          self.common.manage_existing_snapshot,
5288                          snapshot, existing_ref)
5289
5290    @mock.patch.object(utils.VMAXUtils,
5291                       'is_volume_failed_over',
5292                       return_value=True)
5293    def test_manage_snapshot_fail_vol_failed_over(self, mock_failed):
5294        snapshot = self.data.test_snapshot_manage
5295        existing_ref = {u'source-name': u'test_snap'}
5296        self.assertRaises(exception.VolumeBackendAPIException,
5297                          self.common.manage_existing_snapshot,
5298                          snapshot, existing_ref)
5299
5300    @mock.patch.object(rest.VMAXRest, 'get_volume_snap', return_value=False)
5301    def test_manage_snapshot_fail_vol_not_snap_src(self, mock_snap):
5302        snapshot = self.data.test_snapshot_manage
5303        existing_ref = {u'source-name': u'test_snap'}
5304        self.assertRaises(exception.VolumeBackendAPIException,
5305                          self.common.manage_existing_snapshot,
5306                          snapshot, existing_ref)
5307
5308    @mock.patch.object(utils.VMAXUtils, 'modify_snapshot_prefix',
5309                       side_effect=exception.VolumeBackendAPIException)
5310    def test_manage_snapshot_fail_add_prefix(self, mock_mod):
5311        snapshot = self.data.test_snapshot_manage
5312        existing_ref = {u'source-name': u'test_snap'}
5313        self.assertRaises(exception.VolumeBackendAPIException,
5314                          self.common.manage_existing_snapshot,
5315                          snapshot, existing_ref)
5316
5317    @mock.patch.object(common.VMAXCommon, '_sync_check')
5318    @mock.patch.object(rest.VMAXRest, 'modify_volume_snap')
5319    def test_unmanage_snapshot_success(self, mock_mod, mock_sync):
5320        self.common.unmanage_snapshot(self.data.test_snapshot_manage)
5321        mock_mod.assert_called_once()
5322
5323    @mock.patch.object(
5324        utils.VMAXUtils, 'is_volume_failed_over', return_value=True)
5325    def test_unmanage_snapshot_fail_failover(self, mock_failed):
5326        self.assertRaises(exception.VolumeBackendAPIException,
5327                          self.common.unmanage_snapshot,
5328                          self.data.test_snapshot_manage)
5329
5330    @mock.patch.object(rest.VMAXRest,
5331                       'modify_volume_snap',
5332                       side_effect=exception.VolumeBackendAPIException)
5333    def test_unmanage_snapshot_fail_rename(self, mock_snap):
5334        self.assertRaises(exception.VolumeBackendAPIException,
5335                          self.common.unmanage_snapshot,
5336                          self.data.test_snapshot_manage)
5337
5338    @mock.patch.object(provision.VMAXProvision, 'is_restore_complete',
5339                       return_value=True)
5340    @mock.patch.object(common.VMAXCommon, '_sync_check')
5341    @mock.patch.object(provision.VMAXProvision,
5342                       'revert_volume_snapshot')
5343    def test_revert_to_snapshot(self, mock_revert, mock_sync, mock_complete):
5344        volume = self.data.test_volume
5345        snapshot = self.data.test_snapshot
5346        array = self.data.array
5347        device_id = self.data.device_id
5348        snap_name = self.data.snap_location['snap_name']
5349        extra_specs = deepcopy(self.data.extra_specs_intervals_set)
5350        extra_specs['storagetype:portgroupname'] = (
5351            self.data.port_group_name_f)
5352        self.common.revert_to_snapshot(volume, snapshot)
5353        mock_revert.assert_called_once_with(
5354            array, device_id, snap_name, extra_specs)
5355
5356    @mock.patch.object(utils.VMAXUtils, 'is_replication_enabled',
5357                       return_value=True)
5358    def test_revert_to_snapshot_replicated(self, mock_rep):
5359        volume = self.data.test_volume
5360        snapshot = self.data.test_snapshot
5361        self.assertRaises(exception.VolumeDriverException,
5362                          self.common.revert_to_snapshot, volume, snapshot)
5363
5364    def test_get_initiator_check_flag(self):
5365        self.common.configuration.initiator_check = False
5366        initiator_check = self.common._get_initiator_check_flag()
5367        self.assertFalse(initiator_check)
5368
5369    def test_get_initiator_check_flag_true(self):
5370        self.common.configuration.initiator_check = True
5371        initiator_check = self.common._get_initiator_check_flag()
5372        self.assertTrue(initiator_check)
5373
5374    def test_get_slo_workload_combo_from_cinder_conf(self):
5375        configuration = FakeConfiguration(
5376            None, 'ProvisionTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
5377            vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
5378            san_rest_port=8443, vmax_port_groups=[self.data.port_group_name_i])
5379        #    vmax_service_level='Diamond', vmax_workload='DSS')
5380        self.common.configuration = configuration
5381
5382        self.common.configuration.vmax_service_level = 'Diamond'
5383        self.common.configuration.vmax_workload = 'DSS'
5384        response1 = self.common.get_attributes_from_cinder_config()
5385        self.assertEqual('Diamond', response1['ServiceLevel'])
5386        self.assertEqual('DSS', response1['Workload'])
5387
5388        self.common.configuration.vmax_service_level = 'Diamond'
5389        self.common.configuration.vmax_workload = None
5390        response2 = self.common.get_attributes_from_cinder_config()
5391        self.assertEqual(self.common.configuration.vmax_service_level,
5392                         response2['ServiceLevel'])
5393        self.assertIsNone(response2['Workload'])
5394
5395        expected_response = {
5396            'RestServerIp': '1.1.1.1',
5397            'RestServerPort': 8443,
5398            'RestUserName': 'smc',
5399            'RestPassword': 'smc',
5400            'SSLVerify': False,
5401            'SerialNumber': '000197800123',
5402            'srpName': 'SRP_1',
5403            'PortGroup': 'OS-iscsi-PG'}
5404
5405        self.common.configuration.vmax_service_level = None
5406        self.common.configuration.vmax_workload = 'DSS'
5407        response3 = self.common.get_attributes_from_cinder_config()
5408        self.assertEqual(expected_response, response3)
5409
5410        self.common.configuration.vmax_service_level = None
5411        self.common.configuration.vmax_workload = None
5412        response4 = self.common.get_attributes_from_cinder_config()
5413        self.assertEqual(expected_response, response4)
5414
5415
5416class VMAXFCTest(test.TestCase):
5417    def setUp(self):
5418        self.data = VMAXCommonData()
5419
5420        super(VMAXFCTest, self).setUp()
5421        config_group = 'FCTests'
5422        volume_utils.get_max_over_subscription_ratio = mock.Mock()
5423        self.fake_xml = FakeXML().create_fake_config_file(
5424            config_group, self.data.port_group_name_f)
5425        self.configuration = FakeConfiguration(self.fake_xml, config_group)
5426        rest.VMAXRest._establish_rest_session = mock.Mock(
5427            return_value=FakeRequestsSession())
5428        driver = fc.VMAXFCDriver(configuration=self.configuration)
5429        self.driver = driver
5430        self.common = self.driver.common
5431        self.masking = self.common.masking
5432        self.utils = self.common.utils
5433        self.utils.get_volumetype_extra_specs = (
5434            mock.Mock(return_value=self.data.vol_type_extra_specs))
5435
5436    def test_create_volume(self):
5437        with mock.patch.object(self.common, 'create_volume'):
5438            self.driver.create_volume(self.data.test_volume)
5439            self.common.create_volume.assert_called_once_with(
5440                self.data.test_volume)
5441
5442    def test_create_volume_from_snapshot(self):
5443        volume = self.data.test_clone_volume
5444        snapshot = self.data.test_snapshot
5445        with mock.patch.object(self.common, 'create_volume_from_snapshot'):
5446            self.driver.create_volume_from_snapshot(volume, snapshot)
5447            self.common.create_volume_from_snapshot.assert_called_once_with(
5448                volume, snapshot)
5449
5450    def test_create_cloned_volume(self):
5451        volume = self.data.test_clone_volume
5452        src_volume = self.data.test_volume
5453        with mock.patch.object(self.common, 'create_cloned_volume'):
5454            self.driver.create_cloned_volume(volume, src_volume)
5455            self.common.create_cloned_volume.assert_called_once_with(
5456                volume, src_volume)
5457
5458    def test_delete_volume(self):
5459        with mock.patch.object(self.common, 'delete_volume'):
5460            self.driver.delete_volume(self.data.test_volume)
5461            self.common.delete_volume.assert_called_once_with(
5462                self.data.test_volume)
5463
5464    def test_create_snapshot(self):
5465        with mock.patch.object(self.common, 'create_snapshot'):
5466            self.driver.create_snapshot(self.data.test_snapshot)
5467            self.common.create_snapshot.assert_called_once_with(
5468                self.data.test_snapshot, self.data.test_snapshot.volume)
5469
5470    def test_delete_snapshot(self):
5471        with mock.patch.object(self.common, 'delete_snapshot'):
5472            self.driver.delete_snapshot(self.data.test_snapshot)
5473            self.common.delete_snapshot.assert_called_once_with(
5474                self.data.test_snapshot, self.data.test_snapshot.volume)
5475
5476    def test_initialize_connection(self):
5477        with mock.patch.object(self.common, 'initialize_connection',
5478                               return_value=self.data.fc_device_info):
5479            with mock.patch.object(self.driver, 'populate_data'):
5480                self.driver.initialize_connection(self.data.test_volume,
5481                                                  self.data.connector)
5482                self.common.initialize_connection.assert_called_once_with(
5483                    self.data.test_volume, self.data.connector)
5484                self.driver.populate_data.assert_called_once_with(
5485                    self.data.fc_device_info, self.data.test_volume,
5486                    self.data.connector)
5487
5488    def test_populate_data(self):
5489        with mock.patch.object(self.driver, '_build_initiator_target_map',
5490                               return_value=([], {})):
5491            ref_data = {
5492                'driver_volume_type': 'fibre_channel',
5493                'data': {'target_lun': self.data.fc_device_info['hostlunid'],
5494                         'target_discovered': True,
5495                         'target_wwn': [],
5496                         'initiator_target_map': {}}}
5497            data = self.driver.populate_data(self.data.fc_device_info,
5498                                             self.data.test_volume,
5499                                             self.data.connector)
5500            self.assertEqual(ref_data, data)
5501            self.driver._build_initiator_target_map.assert_called_once_with(
5502                self.data.test_volume, self.data.connector)
5503
5504    def test_terminate_connection(self):
5505        with mock.patch.object(self.common, 'terminate_connection'):
5506            self.driver.terminate_connection(self.data.test_volume,
5507                                             self.data.connector)
5508            self.common.terminate_connection.assert_called_once_with(
5509                self.data.test_volume, self.data.connector)
5510
5511    def test_terminate_connection_no_zoning_mappings(self):
5512        with mock.patch.object(self.driver, '_get_zoning_mappings',
5513                               return_value=None):
5514            with mock.patch.object(self.common, 'terminate_connection'):
5515                self.driver.terminate_connection(self.data.test_volume,
5516                                                 self.data.connector)
5517                self.common.terminate_connection.assert_not_called()
5518
5519    def test_get_zoning_mappings(self):
5520        ref_mappings = self.data.zoning_mappings
5521        zoning_mappings = self.driver._get_zoning_mappings(
5522            self.data.test_volume, self.data.connector)
5523        self.assertEqual(ref_mappings, zoning_mappings)
5524        # Legacy vol
5525        zoning_mappings2 = self.driver._get_zoning_mappings(
5526            self.data.test_legacy_vol, self.data.connector)
5527        self.assertEqual(ref_mappings, zoning_mappings2)
5528
5529    def test_get_zoning_mappings_no_mv(self):
5530        with mock.patch.object(self.common, 'get_masking_views_from_volume',
5531                               return_value=(None, False)):
5532            zoning_mappings = self.driver._get_zoning_mappings(
5533                self.data.test_volume, self.data.connector)
5534            self.assertEqual({}, zoning_mappings)
5535
5536    @mock.patch.object(
5537        common.VMAXCommon, 'get_masking_views_from_volume',
5538        return_value=([VMAXCommonData.masking_view_name_f], True))
5539    def test_get_zoning_mappings_metro(self, mock_mv):
5540        ref_mappings = self.data.zoning_mappings_metro
5541        zoning_mappings = self.driver._get_zoning_mappings(
5542            self.data.test_volume, self.data.connector)
5543        self.assertEqual(ref_mappings, zoning_mappings)
5544
5545    def test_cleanup_zones_other_vols_mapped(self):
5546        ref_data = {'driver_volume_type': 'fibre_channel',
5547                    'data': {}}
5548        data = self.driver._cleanup_zones(self.data.zoning_mappings)
5549        self.assertEqual(ref_data, data)
5550
5551    def test_cleanup_zones_no_vols_mapped(self):
5552        zoning_mappings = self.data.zoning_mappings
5553        ref_data = {'driver_volume_type': 'fibre_channel',
5554                    'data': {'target_wwn': zoning_mappings['target_wwns'],
5555                             'initiator_target_map':
5556                                 zoning_mappings['init_targ_map']}}
5557        with mock.patch.object(self.common, 'get_common_masking_views',
5558                               return_value=[]):
5559            data = self.driver._cleanup_zones(self.data.zoning_mappings)
5560            self.assertEqual(ref_data, data)
5561
5562    def test_build_initiator_target_map(self):
5563        ref_target_map = {'123456789012345': ['543210987654321'],
5564                          '123456789054321': ['123450987654321']}
5565        with mock.patch.object(fczm_utils, 'create_lookup_service',
5566                               return_value=FakeLookupService()):
5567            driver = fc.VMAXFCDriver(configuration=self.configuration)
5568            with mock.patch.object(driver.common,
5569                                   'get_target_wwns_from_masking_view',
5570                                   return_value=(self.data.target_wwns, [])):
5571                targets, target_map = driver._build_initiator_target_map(
5572                    self.data.test_volume, self.data.connector)
5573                self.assertEqual(ref_target_map, target_map)
5574
5575    def test_extend_volume(self):
5576        with mock.patch.object(self.common, 'extend_volume'):
5577            self.driver.extend_volume(self.data.test_volume, '3')
5578            self.common.extend_volume.assert_called_once_with(
5579                self.data.test_volume, '3')
5580
5581    def test_get_volume_stats(self):
5582        with mock.patch.object(self.driver, 'update_volume_stats'):
5583            # no refresh
5584            self.driver.get_volume_stats()
5585            self.driver.update_volume_stats.assert_not_called()
5586            # with refresh
5587            self.driver.get_volume_stats(True)
5588            self.driver.update_volume_stats.assert_called_once_with()
5589
5590    def test_update_volume_stats(self):
5591        with mock.patch.object(self.common, 'update_volume_stats',
5592                               return_value={}):
5593            self.driver.update_volume_stats()
5594            self.common.update_volume_stats.assert_called_once_with()
5595
5596    def test_check_for_setup_error(self):
5597        self.driver.check_for_setup_error()
5598
5599    def test_ensure_export(self):
5600        self.driver.ensure_export('context', 'volume')
5601
5602    def test_create_export(self):
5603        self.driver.create_export('context', 'volume', 'connector')
5604
5605    def test_remove_export(self):
5606        self.driver.remove_export('context', 'volume')
5607
5608    def test_check_for_export(self):
5609        self.driver.check_for_export('context', 'volume_id')
5610
5611    def test_manage_existing(self):
5612        with mock.patch.object(self.common, 'manage_existing',
5613                               return_value={}):
5614            external_ref = {u'source-name': u'00002'}
5615            self.driver.manage_existing(self.data.test_volume, external_ref)
5616            self.common.manage_existing.assert_called_once_with(
5617                self.data.test_volume, external_ref)
5618
5619    def test_manage_existing_get_size(self):
5620        with mock.patch.object(self.common, 'manage_existing_get_size',
5621                               return_value='1'):
5622            external_ref = {u'source-name': u'00002'}
5623            self.driver.manage_existing_get_size(
5624                self.data.test_volume, external_ref)
5625            self.common.manage_existing_get_size.assert_called_once_with(
5626                self.data.test_volume, external_ref)
5627
5628    def test_unmanage_volume(self):
5629        with mock.patch.object(self.common, 'unmanage',
5630                               return_value={}):
5631            self.driver.unmanage(self.data.test_volume)
5632            self.common.unmanage.assert_called_once_with(
5633                self.data.test_volume)
5634
5635    def test_retype(self):
5636        host = {'host': self.data.new_host}
5637        new_type = {'extra_specs': {}}
5638        with mock.patch.object(self.common, 'retype',
5639                               return_value=True):
5640            self.driver.retype({}, self.data.test_volume, new_type, '', host)
5641            self.common.retype.assert_called_once_with(
5642                self.data.test_volume, new_type, host)
5643
5644    def test_failover_host(self):
5645        with mock.patch.object(
5646                self.common, 'failover_host',
5647                return_value=(self.data.remote_array, [], [])) as mock_fo:
5648            self.driver.failover_host(self.data.ctx, [self.data.test_volume])
5649            mock_fo.assert_called_once_with([self.data.test_volume], None,
5650                                            None)
5651
5652    def test_enable_replication(self):
5653        with mock.patch.object(
5654                self.common, 'enable_replication') as mock_er:
5655            self.driver.enable_replication(
5656                self.data.ctx, self.data.test_group, [self.data.test_volume])
5657            mock_er.assert_called_once()
5658
5659    def test_disable_replication(self):
5660        with mock.patch.object(
5661                self.common, 'disable_replication') as mock_dr:
5662            self.driver.disable_replication(
5663                self.data.ctx, self.data.test_group, [self.data.test_volume])
5664            mock_dr.assert_called_once()
5665
5666    def test_failover_replication(self):
5667        with mock.patch.object(
5668                self.common, 'failover_replication') as mock_fo:
5669            self.driver.failover_replication(
5670                self.data.ctx, self.data.test_group, [self.data.test_volume])
5671            mock_fo.assert_called_once()
5672
5673
5674class VMAXISCSITest(test.TestCase):
5675    def setUp(self):
5676        self.data = VMAXCommonData()
5677
5678        super(VMAXISCSITest, self).setUp()
5679        config_group = 'ISCSITests'
5680        self.fake_xml = FakeXML().create_fake_config_file(
5681            config_group, self.data.port_group_name_i)
5682        volume_utils.get_max_over_subscription_ratio = mock.Mock()
5683        configuration = FakeConfiguration(self.fake_xml, config_group)
5684        rest.VMAXRest._establish_rest_session = mock.Mock(
5685            return_value=FakeRequestsSession())
5686        driver = iscsi.VMAXISCSIDriver(configuration=configuration)
5687        self.driver = driver
5688        self.common = self.driver.common
5689        self.masking = self.common.masking
5690        self.utils = self.common.utils
5691        self.utils.get_volumetype_extra_specs = (
5692            mock.Mock(return_value=self.data.vol_type_extra_specs))
5693
5694    def test_create_volume(self):
5695        with mock.patch.object(self.common, 'create_volume'):
5696            self.driver.create_volume(self.data.test_volume)
5697            self.common.create_volume.assert_called_once_with(
5698                self.data.test_volume)
5699
5700    def test_create_volume_from_snapshot(self):
5701        volume = self.data.test_clone_volume
5702        snapshot = self.data.test_snapshot
5703        with mock.patch.object(self.common, 'create_volume_from_snapshot'):
5704            self.driver.create_volume_from_snapshot(volume, snapshot)
5705            self.common.create_volume_from_snapshot.assert_called_once_with(
5706                volume, snapshot)
5707
5708    def test_create_cloned_volume(self):
5709        volume = self.data.test_clone_volume
5710        src_volume = self.data.test_volume
5711        with mock.patch.object(self.common, 'create_cloned_volume'):
5712            self.driver.create_cloned_volume(volume, src_volume)
5713            self.common.create_cloned_volume.assert_called_once_with(
5714                volume, src_volume)
5715
5716    def test_delete_volume(self):
5717        with mock.patch.object(self.common, 'delete_volume'):
5718            self.driver.delete_volume(self.data.test_volume)
5719            self.common.delete_volume.assert_called_once_with(
5720                self.data.test_volume)
5721
5722    def test_create_snapshot(self):
5723        with mock.patch.object(self.common, 'create_snapshot'):
5724            self.driver.create_snapshot(self.data.test_snapshot)
5725            self.common.create_snapshot.assert_called_once_with(
5726                self.data.test_snapshot, self.data.test_snapshot.volume)
5727
5728    def test_delete_snapshot(self):
5729        with mock.patch.object(self.common, 'delete_snapshot'):
5730            self.driver.delete_snapshot(self.data.test_snapshot)
5731            self.common.delete_snapshot.assert_called_once_with(
5732                self.data.test_snapshot, self.data.test_snapshot.volume)
5733
5734    def test_initialize_connection(self):
5735        ref_dict = {'maskingview': self.data.masking_view_name_f,
5736                    'array': self.data.array,
5737                    'hostlunid': 3,
5738                    'device_id': self.data.device_id,
5739                    'ip_and_iqn': [{'ip': self.data.ip,
5740                                    'iqn': self.data.initiator}],
5741                    'is_multipath': False}
5742        with mock.patch.object(self.driver, 'get_iscsi_dict'):
5743            with mock.patch.object(
5744                self.common, 'get_port_group_from_masking_view',
5745                    return_value=self.data.port_group_name_i):
5746                self.driver.initialize_connection(self.data.test_volume,
5747                                                  self.data.connector)
5748                self.driver.get_iscsi_dict.assert_called_once_with(
5749                    ref_dict, self.data.test_volume)
5750
5751    def test_get_iscsi_dict_success(self):
5752        ip_and_iqn = self.common._find_ip_and_iqns(
5753            self.data.array, self.data.port_group_name_i)
5754        host_lun_id = self.data.iscsi_device_info['hostlunid']
5755        volume = self.data.test_volume
5756        device_info = self.data.iscsi_device_info
5757        ref_data = {'driver_volume_type': 'iscsi', 'data': {}}
5758        with mock.patch.object(
5759                self.driver, 'vmax_get_iscsi_properties', return_value={}):
5760            data = self.driver.get_iscsi_dict(device_info, volume)
5761            self.assertEqual(ref_data, data)
5762            self.driver.vmax_get_iscsi_properties.assert_called_once_with(
5763                volume, ip_and_iqn, True, host_lun_id, None, None)
5764
5765    def test_get_iscsi_dict_exception(self):
5766        device_info = {'ip_and_iqn': ''}
5767        self.assertRaises(exception.VolumeBackendAPIException,
5768                          self.driver.get_iscsi_dict,
5769                          device_info, self.data.test_volume)
5770
5771    def test_get_iscsi_dict_metro(self):
5772        ip_and_iqn = self.common._find_ip_and_iqns(
5773            self.data.array, self.data.port_group_name_i)
5774        host_lun_id = self.data.iscsi_device_info_metro['hostlunid']
5775        volume = self.data.test_volume
5776        device_info = self.data.iscsi_device_info_metro
5777        ref_data = {'driver_volume_type': 'iscsi', 'data': {}}
5778        with mock.patch.object(
5779                self.driver, 'vmax_get_iscsi_properties', return_value={}):
5780            data = self.driver.get_iscsi_dict(device_info, volume)
5781            self.assertEqual(ref_data, data)
5782            self.driver.vmax_get_iscsi_properties.assert_called_once_with(
5783                volume, ip_and_iqn, True, host_lun_id,
5784                self.data.iscsi_device_info_metro['metro_ip_and_iqn'],
5785                self.data.iscsi_device_info_metro['metro_hostlunid'])
5786
5787    def test_vmax_get_iscsi_properties_one_target_no_auth(self):
5788        vol = deepcopy(self.data.test_volume)
5789        ip_and_iqn = self.common._find_ip_and_iqns(
5790            self.data.array, self.data.port_group_name_i)
5791        host_lun_id = self.data.iscsi_device_info['hostlunid']
5792        ref_properties = {
5793            'target_discovered': True,
5794            'target_iqn': ip_and_iqn[0]['iqn'].split(",")[0],
5795            'target_portal': ip_and_iqn[0]['ip'] + ":3260",
5796            'target_lun': host_lun_id,
5797            'volume_id': self.data.test_volume.id}
5798        iscsi_properties = self.driver.vmax_get_iscsi_properties(
5799            vol, ip_and_iqn, True, host_lun_id, [], None)
5800        self.assertEqual(type(ref_properties), type(iscsi_properties))
5801        self.assertEqual(ref_properties, iscsi_properties)
5802
5803    def test_vmax_get_iscsi_properties_multiple_targets(self):
5804        ip_and_iqn = [{'ip': self.data.ip, 'iqn': self.data.initiator},
5805                      {'ip': self.data.ip, 'iqn': self.data.iqn}]
5806        host_lun_id = self.data.iscsi_device_info['hostlunid']
5807        ref_properties = {
5808            'target_portals': (
5809                [t['ip'] + ":3260" for t in ip_and_iqn]),
5810            'target_iqns': (
5811                [t['iqn'].split(",")[0] for t in ip_and_iqn]),
5812            'target_luns': [host_lun_id] * len(ip_and_iqn),
5813            'target_discovered': True,
5814            'target_iqn': ip_and_iqn[0]['iqn'].split(",")[0],
5815            'target_portal': ip_and_iqn[0]['ip'] + ":3260",
5816            'target_lun': host_lun_id,
5817            'volume_id': self.data.test_volume.id}
5818        iscsi_properties = self.driver.vmax_get_iscsi_properties(
5819            self.data.test_volume, ip_and_iqn, True, host_lun_id, [], None)
5820        self.assertEqual(ref_properties, iscsi_properties)
5821
5822    def test_vmax_get_iscsi_properties_auth(self):
5823        vol = deepcopy(self.data.test_volume)
5824        backup_conf = self.common.configuration
5825        configuration = FakeConfiguration(
5826            None, 'ISCSITests', 1, 1, san_ip='1.1.1.1', san_login='smc',
5827            vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
5828            san_rest_port=8443, use_chap_auth=True,
5829            chap_username='auth_username', chap_password='auth_secret',
5830            vmax_port_groups=[self.data.port_group_name_i])
5831        self.driver.configuration = configuration
5832        ip_and_iqn = [{'ip': self.data.ip, 'iqn': self.data.initiator},
5833                      {'ip': self.data.ip, 'iqn': self.data.iqn}]
5834        host_lun_id = self.data.iscsi_device_info['hostlunid']
5835        ref_properties = {
5836            'target_portals': (
5837                [t['ip'] + ":3260" for t in ip_and_iqn]),
5838            'target_iqns': (
5839                [t['iqn'].split(",")[0] for t in ip_and_iqn]),
5840            'target_luns': [host_lun_id] * len(ip_and_iqn),
5841            'target_discovered': True,
5842            'target_iqn': ip_and_iqn[0]['iqn'].split(",")[0],
5843            'target_portal': ip_and_iqn[0]['ip'] + ":3260",
5844            'target_lun': host_lun_id,
5845            'volume_id': self.data.test_volume.id,
5846            'auth_method': 'CHAP',
5847            'auth_username': 'auth_username',
5848            'auth_password': 'auth_secret'}
5849        iscsi_properties = self.driver.vmax_get_iscsi_properties(
5850            vol, ip_and_iqn, True, host_lun_id, None, None)
5851        self.assertEqual(ref_properties, iscsi_properties)
5852        self.driver.configuration = backup_conf
5853
5854    def test_vmax_get_iscsi_properties_metro(self):
5855        ip_and_iqn = [{'ip': self.data.ip, 'iqn': self.data.iqn}]
5856        total_ip_list = [{'ip': self.data.ip, 'iqn': self.data.iqn},
5857                         {'ip': self.data.ip2, 'iqn': self.data.iqn2}]
5858        host_lun_id = self.data.iscsi_device_info['hostlunid']
5859        host_lun_id2 = self.data.iscsi_device_info_metro['metro_hostlunid']
5860        ref_properties = {
5861            'target_portals': (
5862                [t['ip'] + ":3260" for t in total_ip_list]),
5863            'target_iqns': (
5864                [t['iqn'].split(",")[0] for t in total_ip_list]),
5865            'target_luns': [host_lun_id, host_lun_id2],
5866            'target_discovered': True,
5867            'target_iqn': ip_and_iqn[0]['iqn'].split(",")[0],
5868            'target_portal': ip_and_iqn[0]['ip'] + ":3260",
5869            'target_lun': host_lun_id,
5870            'volume_id': self.data.test_volume.id}
5871        iscsi_properties = self.driver.vmax_get_iscsi_properties(
5872            self.data.test_volume, ip_and_iqn, True, host_lun_id,
5873            self.data.iscsi_device_info_metro['metro_ip_and_iqn'],
5874            self.data.iscsi_device_info_metro['metro_hostlunid'])
5875        self.assertEqual(ref_properties, iscsi_properties)
5876
5877    def test_terminate_connection(self):
5878        with mock.patch.object(self.common, 'terminate_connection'):
5879            self.driver.terminate_connection(self.data.test_volume,
5880                                             self.data.connector)
5881            self.common.terminate_connection.assert_called_once_with(
5882                self.data.test_volume, self.data.connector)
5883
5884    def test_extend_volume(self):
5885        with mock.patch.object(self.common, 'extend_volume'):
5886            self.driver.extend_volume(self.data.test_volume, '3')
5887            self.common.extend_volume.assert_called_once_with(
5888                self.data.test_volume, '3')
5889
5890    def test_get_volume_stats(self):
5891        with mock.patch.object(self.driver, 'update_volume_stats'):
5892            # no refresh
5893            self.driver.get_volume_stats()
5894            self.driver.update_volume_stats.assert_not_called()
5895            # with refresh
5896            self.driver.get_volume_stats(True)
5897            self.driver.update_volume_stats.assert_called_once_with()
5898
5899    def test_update_volume_stats(self):
5900        with mock.patch.object(self.common, 'update_volume_stats',
5901                               return_value={}):
5902            self.driver.update_volume_stats()
5903            self.common.update_volume_stats.assert_called_once_with()
5904
5905    def test_check_for_setup_error(self):
5906        self.driver.check_for_setup_error()
5907
5908    def test_ensure_export(self):
5909        self.driver.ensure_export('context', 'volume')
5910
5911    def test_create_export(self):
5912        self.driver.create_export('context', 'volume', 'connector')
5913
5914    def test_remove_export(self):
5915        self.driver.remove_export('context', 'volume')
5916
5917    def test_check_for_export(self):
5918        self.driver.check_for_export('context', 'volume_id')
5919
5920    def test_manage_existing(self):
5921        with mock.patch.object(self.common, 'manage_existing',
5922                               return_value={}):
5923            external_ref = {u'source-name': u'00002'}
5924            self.driver.manage_existing(self.data.test_volume, external_ref)
5925            self.common.manage_existing.assert_called_once_with(
5926                self.data.test_volume, external_ref)
5927
5928    def test_manage_existing_get_size(self):
5929        with mock.patch.object(self.common, 'manage_existing_get_size',
5930                               return_value='1'):
5931            external_ref = {u'source-name': u'00002'}
5932            self.driver.manage_existing_get_size(
5933                self.data.test_volume, external_ref)
5934            self.common.manage_existing_get_size.assert_called_once_with(
5935                self.data.test_volume, external_ref)
5936
5937    def test_unmanage_volume(self):
5938        with mock.patch.object(self.common, 'unmanage',
5939                               return_value={}):
5940            self.driver.unmanage(self.data.test_volume)
5941            self.common.unmanage.assert_called_once_with(
5942                self.data.test_volume)
5943
5944    def test_retype(self):
5945        host = {'host': self.data.new_host}
5946        new_type = {'extra_specs': {}}
5947        with mock.patch.object(self.common, 'retype',
5948                               return_value=True):
5949            self.driver.retype({}, self.data.test_volume, new_type, '', host)
5950            self.common.retype.assert_called_once_with(
5951                self.data.test_volume, new_type, host)
5952
5953    def test_failover_host(self):
5954        with mock.patch.object(self.common, 'failover_host',
5955                               return_value={}) as mock_fo:
5956            self.driver.failover_host({}, [self.data.test_volume])
5957            mock_fo.assert_called_once_with([self.data.test_volume], None,
5958                                            None)
5959
5960    def test_enable_replication(self):
5961        with mock.patch.object(
5962                self.common, 'enable_replication') as mock_er:
5963            self.driver.enable_replication(
5964                self.data.ctx, self.data.test_group, [self.data.test_volume])
5965            mock_er.assert_called_once()
5966
5967    def test_disable_replication(self):
5968        with mock.patch.object(
5969                self.common, 'disable_replication') as mock_dr:
5970            self.driver.disable_replication(
5971                self.data.ctx, self.data.test_group, [self.data.test_volume])
5972            mock_dr.assert_called_once()
5973
5974    def test_failover_replication(self):
5975        with mock.patch.object(
5976                self.common, 'failover_replication') as mock_fo:
5977            self.driver.failover_replication(
5978                self.data.ctx, self.data.test_group, [self.data.test_volume])
5979            mock_fo.assert_called_once()
5980
5981
5982class VMAXMaskingTest(test.TestCase):
5983    def setUp(self):
5984        self.data = VMAXCommonData()
5985
5986        super(VMAXMaskingTest, self).setUp()
5987
5988        volume_utils.get_max_over_subscription_ratio = mock.Mock()
5989        configuration = mock.Mock()
5990        configuration.safe_get.return_value = 'MaskingTests'
5991        configuration.config_group = 'MaskingTests'
5992        self._gather_info = common.VMAXCommon._gather_info
5993        common.VMAXCommon._gather_info = mock.Mock()
5994        rest.VMAXRest._establish_rest_session = mock.Mock(
5995            return_value=FakeRequestsSession())
5996        driver = common.VMAXCommon(
5997            'iSCSI', self.data.version, configuration=configuration)
5998        driver_fc = common.VMAXCommon(
5999            'FC', self.data.version, configuration=configuration)
6000        self.driver = driver
6001        self.driver_fc = driver_fc
6002        self.mask = self.driver.masking
6003        self.extra_specs = self.data.extra_specs
6004        self.extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_i
6005        self.maskingviewdict = self.driver._populate_masking_dict(
6006            self.data.test_volume, self.data.connector, self.extra_specs)
6007        self.maskingviewdict['extra_specs'] = self.extra_specs
6008        self.device_id = self.data.device_id
6009        self.volume_name = self.data.volume_details[0]['volume_identifier']
6010
6011    def tearDown(self):
6012        super(VMAXMaskingTest, self).tearDown()
6013        common.VMAXCommon._gather_info = self._gather_info
6014
6015    @mock.patch.object(
6016        masking.VMAXMasking,
6017        'get_or_create_masking_view_and_map_lun')
6018    def test_setup_masking_view(self, mock_get_or_create_mv):
6019        self.driver.masking.setup_masking_view(
6020            self.data.array, self.data.test_volume,
6021            self.maskingviewdict, self.extra_specs)
6022        mock_get_or_create_mv.assert_called_once()
6023
6024    @mock.patch.object(
6025        masking.VMAXMasking,
6026        '_check_adding_volume_to_storage_group')
6027    @mock.patch.object(
6028        masking.VMAXMasking,
6029        '_move_vol_from_default_sg',
6030        return_value=None)
6031    @mock.patch.object(
6032        masking.VMAXMasking,
6033        '_get_or_create_masking_view',
6034        side_effect=[None, "Error in masking view retrieval",
6035                     exception.VolumeBackendAPIException])
6036    @mock.patch.object(
6037        rest.VMAXRest,
6038        'get_element_from_masking_view',
6039        side_effect=[VMAXCommonData.port_group_name_i,
6040                     Exception('Exception')])
6041    def test_get_or_create_masking_view_and_map_lun(
6042            self, mock_masking_view_element, mock_masking, mock_move,
6043            mock_add_volume):
6044        rollback_dict = (
6045            self.driver.masking.get_or_create_masking_view_and_map_lun(
6046                self.data.array, self.data.test_volume,
6047                self.maskingviewdict['maskingview_name'],
6048                self.maskingviewdict, self.extra_specs))
6049        self.assertEqual(self.maskingviewdict, rollback_dict)
6050        self.assertRaises(
6051            exception.VolumeBackendAPIException,
6052            self.driver.masking.get_or_create_masking_view_and_map_lun,
6053            self.data.array, self.data.test_volume,
6054            self.maskingviewdict['maskingview_name'],
6055            self.maskingviewdict, self.extra_specs)
6056        self.maskingviewdict['slo'] = None
6057        self.assertRaises(
6058            exception.VolumeBackendAPIException,
6059            self.driver.masking.get_or_create_masking_view_and_map_lun,
6060            self.data.array, self.data.test_volume,
6061            self.maskingviewdict['maskingview_name'],
6062            self.maskingviewdict, self.extra_specs)
6063
6064    @mock.patch.object(
6065        masking.VMAXMasking,
6066        '_check_adding_volume_to_storage_group',
6067        return_value=None)
6068    @mock.patch.object(
6069        rest.VMAXRest,
6070        'move_volume_between_storage_groups',
6071        side_effect=[None, exception.VolumeBackendAPIException(data='')])
6072    @mock.patch.object(
6073        rest.VMAXRest,
6074        'is_volume_in_storagegroup',
6075        side_effect=[True, False, True])
6076    def test_move_vol_from_default_sg(
6077            self, mock_volume_in_sg, mock_move_volume, mock_add):
6078        msg = None
6079        for x in range(0, 2):
6080            msg = self.driver.masking._move_vol_from_default_sg(
6081                self.data.array, self.device_id, self.volume_name,
6082                self.data.defaultstoragegroup_name,
6083                self.data.storagegroup_name_i, self.extra_specs)
6084        mock_move_volume.assert_called_once()
6085        mock_add.assert_called_once()
6086        self.assertIsNone(msg)
6087        msg = self.driver.masking._move_vol_from_default_sg(
6088            self.data.array, self.device_id, self.volume_name,
6089            self.data.defaultstoragegroup_name,
6090            self.data.storagegroup_name_i, self.extra_specs)
6091        self.assertIsNotNone(msg)
6092
6093    @mock.patch.object(
6094        rest.VMAXRest,
6095        'get_masking_view',
6096        side_effect=[VMAXCommonData.maskingview,
6097                     VMAXCommonData.maskingview, None])
6098    @mock.patch.object(
6099        masking.VMAXMasking,
6100        '_validate_existing_masking_view',
6101        side_effect=[(VMAXCommonData.maskingview[1]['storageGroupId'],
6102                      None), (None, "Error Message")])
6103    @mock.patch.object(
6104        masking.VMAXMasking,
6105        '_create_new_masking_view',
6106        return_value=None)
6107    def test_get_or_create_masking_view(
6108            self, mock_create_mv, mock_validate_mv,
6109            mock_get_mv):
6110        for x in range(0, 3):
6111            self.driver.masking._get_or_create_masking_view(
6112                self.data.array, self.maskingviewdict,
6113                self.data.defaultstoragegroup_name, self.extra_specs)
6114        mock_create_mv.assert_called_once()
6115
6116    @mock.patch.object(
6117        masking.VMAXMasking,
6118        '_get_or_create_storage_group',
6119        side_effect=["Storage group not found", None,
6120                     "Storage group not found", None, None, None,
6121                     None, None, None, None, None])
6122    @mock.patch.object(
6123        masking.VMAXMasking,
6124        '_check_port_group',
6125        side_effect=[(None, "Port group error"), (None, None), (None, None),
6126                     (None, None)])
6127    @mock.patch.object(
6128        masking.VMAXMasking,
6129        '_get_or_create_initiator_group',
6130        side_effect=[(None, "Initiator group error"), (None, None),
6131                     (None, None)])
6132    @mock.patch.object(
6133        masking.VMAXMasking,
6134        '_move_vol_from_default_sg',
6135        side_effect=["Storage group error", None])
6136    @mock.patch.object(
6137        masking.VMAXMasking,
6138        'create_masking_view',
6139        return_value=None)
6140    def test_create_new_masking_view(
6141            self, mock_create_mv, mock_move, mock_create_IG,
6142            mock_check_PG, mock_create_SG):
6143        for x in range(0, 6):
6144            self.driver.masking._create_new_masking_view(
6145                self.data.array, self.maskingviewdict,
6146                self.maskingviewdict['maskingview_name'],
6147                self.data.defaultstoragegroup_name, self.extra_specs)
6148        mock_create_mv.assert_called_once()
6149
6150    @mock.patch.object(
6151        masking.VMAXMasking,
6152        '_check_existing_storage_group',
6153        side_effect=[(VMAXCommonData.storagegroup_name_i, None),
6154                     (VMAXCommonData.storagegroup_name_i, None),
6155                     (None, "Error Checking existing storage group")])
6156    @mock.patch.object(
6157        rest.VMAXRest,
6158        'get_element_from_masking_view',
6159        return_value=VMAXCommonData.port_group_name_i)
6160    @mock.patch.object(
6161        masking.VMAXMasking,
6162        '_check_port_group',
6163        side_effect=[(None, None), (None, "Error checking pg")])
6164    @mock.patch.object(
6165        masking.VMAXMasking,
6166        '_check_existing_initiator_group',
6167        return_value=(VMAXCommonData.initiatorgroup_name_i, None))
6168    def test_validate_existing_masking_view(
6169            self, mock_check_ig, mock_check_pg, mock_get_mv_element,
6170            mock_check_sg):
6171        for x in range(0, 3):
6172            self.driver.masking._validate_existing_masking_view(
6173                self.data.array, self.maskingviewdict,
6174                self.maskingviewdict['maskingview_name'],
6175                self.data.defaultstoragegroup_name, self.extra_specs)
6176        self.assertEqual(3, mock_check_sg.call_count)
6177        mock_get_mv_element.assert_called_with(
6178            self.data.array, self.maskingviewdict['maskingview_name'],
6179            portgroup=True)
6180        mock_check_ig.assert_called_once()
6181
6182    @mock.patch.object(
6183        rest.VMAXRest,
6184        'get_storage_group',
6185        side_effect=[VMAXCommonData.storagegroup_name_i, None, None])
6186    @mock.patch.object(
6187        provision.VMAXProvision,
6188        'create_storage_group',
6189        side_effect=[VMAXCommonData.storagegroup_name_i, None])
6190    def test_get_or_create_storage_group(self, mock_sg, mock_get_sg):
6191        for x in range(0, 2):
6192            self.driver.masking._get_or_create_storage_group(
6193                self.data.array, self.maskingviewdict,
6194                self.data.storagegroup_name_i, self.extra_specs)
6195        self.driver.masking._get_or_create_storage_group(
6196            self.data.array, self.maskingviewdict,
6197            self.data.storagegroup_name_i, self.extra_specs, True)
6198        self.assertEqual(3, mock_get_sg.call_count)
6199        self.assertEqual(2, mock_sg.call_count)
6200
6201    @mock.patch.object(
6202        masking.VMAXMasking,
6203        '_move_vol_from_default_sg',
6204        return_value=None)
6205    @mock.patch.object(
6206        masking.VMAXMasking,
6207        '_get_or_create_storage_group',
6208        return_value=None)
6209    @mock.patch.object(
6210        rest.VMAXRest,
6211        'get_element_from_masking_view',
6212        return_value=VMAXCommonData.parent_sg_i)
6213    @mock.patch.object(
6214        rest.VMAXRest,
6215        'is_child_sg_in_parent_sg',
6216        side_effect=[True, False])
6217    @mock.patch.object(
6218        masking.VMAXMasking,
6219        '_check_add_child_sg_to_parent_sg',
6220        return_value=None)
6221    def test_check_existing_storage_group_success(
6222            self, mock_add_sg, mock_is_child, mock_get_mv_element,
6223            mock_create_sg, mock_move):
6224        masking_view_dict = deepcopy(self.data.masking_view_dict)
6225        masking_view_dict['extra_specs'] = self.data.extra_specs
6226        with mock.patch.object(self.driver.rest, 'get_storage_group',
6227                               side_effect=[
6228                                   VMAXCommonData.parent_sg_i,
6229                                   VMAXCommonData.storagegroup_name_i]):
6230            _, msg = (
6231                self.driver.masking._check_existing_storage_group(
6232                    self.data.array, self.maskingviewdict['maskingview_name'],
6233                    self.data.defaultstoragegroup_name, masking_view_dict))
6234            self.assertIsNone(msg)
6235            mock_create_sg.assert_not_called()
6236        with mock.patch.object(self.driver.rest, 'get_storage_group',
6237                               side_effect=[
6238                                   VMAXCommonData.parent_sg_i, None]):
6239            _, msg = (
6240                self.driver.masking._check_existing_storage_group(
6241                    self.data.array, self.maskingviewdict['maskingview_name'],
6242                    self.data.defaultstoragegroup_name, masking_view_dict))
6243            self.assertIsNone(msg)
6244            mock_create_sg.assert_called_once_with(
6245                self.data.array, masking_view_dict,
6246                VMAXCommonData.storagegroup_name_f,
6247                self.data.extra_specs)
6248
6249    @mock.patch.object(
6250        masking.VMAXMasking,
6251        '_move_vol_from_default_sg',
6252        side_effect=[None, "Error Message"])
6253    @mock.patch.object(
6254        rest.VMAXRest,
6255        'is_child_sg_in_parent_sg',
6256        side_effect=[True, False, False])
6257    @mock.patch.object(
6258        rest.VMAXRest,
6259        'get_element_from_masking_view',
6260        return_value=VMAXCommonData.parent_sg_i)
6261    @mock.patch.object(
6262        rest.VMAXRest,
6263        'get_storage_group',
6264        side_effect=[None, VMAXCommonData.parent_sg_i, None,
6265                     VMAXCommonData.parent_sg_i, None,
6266                     VMAXCommonData.parent_sg_i, None])
6267    def test_check_existing_storage_group_failed(
6268            self, mock_get_sg, mock_get_mv_element, mock_child, mock_move):
6269        masking_view_dict = deepcopy(self.data.masking_view_dict)
6270        masking_view_dict['extra_specs'] = self.data.extra_specs
6271        for x in range(0, 4):
6272            _, msg = (
6273                self.driver.masking._check_existing_storage_group(
6274                    self.data.array, self.maskingviewdict['maskingview_name'],
6275                    self.data.defaultstoragegroup_name, masking_view_dict))
6276            self.assertIsNotNone(msg)
6277        self.assertEqual(7, mock_get_sg.call_count)
6278        self.assertEqual(1, mock_move.call_count)
6279
6280    @mock.patch.object(rest.VMAXRest, 'get_portgroup',
6281                       side_effect=[VMAXCommonData.port_group_name_i, None])
6282    def test_check_port_group(
6283            self, mock_get_pg):
6284        for x in range(0, 2):
6285            _, msg = self.driver.masking._check_port_group(
6286                self.data.array, self.maskingviewdict['maskingview_name'])
6287        self.assertIsNotNone(msg)
6288        self.assertEqual(2, mock_get_pg.call_count)
6289
6290    @mock.patch.object(
6291        masking.VMAXMasking, '_find_initiator_group',
6292        side_effect=[VMAXCommonData.initiatorgroup_name_i, None, None])
6293    @mock.patch.object(masking.VMAXMasking, '_create_initiator_group',
6294                       side_effect=[VMAXCommonData.initiatorgroup_name_i, None]
6295                       )
6296    def test_get_or_create_initiator_group(self, mock_create_ig, mock_find_ig):
6297        self.driver.masking._get_or_create_initiator_group(
6298            self.data.array, self.data.initiatorgroup_name_i,
6299            self.data.connector, self.extra_specs)
6300        mock_create_ig.assert_not_called()
6301        found_init_group, msg = (
6302            self.driver.masking._get_or_create_initiator_group(
6303                self.data.array, self.data.initiatorgroup_name_i,
6304                self.data.connector, self.extra_specs))
6305        self.assertIsNone(msg)
6306        found_init_group, msg = (
6307            self.driver.masking._get_or_create_initiator_group(
6308                self.data.array, self.data.initiatorgroup_name_i,
6309                self.data.connector, self.extra_specs))
6310        self.assertIsNotNone(msg)
6311
6312    def test_check_existing_initiator_group(self):
6313        with mock.patch.object(
6314                rest.VMAXRest, 'get_element_from_masking_view',
6315                return_value=VMAXCommonData.inititiatorgroup):
6316            ig_from_mv, msg = (
6317                self.driver.masking._check_existing_initiator_group(
6318                    self.data.array, self.maskingviewdict['maskingview_name'],
6319                    self.maskingviewdict, self.data.storagegroup_name_i,
6320                    self.data.port_group_name_i, self.extra_specs))
6321            self.assertEqual(self.data.inititiatorgroup, ig_from_mv)
6322
6323    def test_check_adding_volume_to_storage_group(self):
6324        with mock.patch.object(
6325                masking.VMAXMasking, '_create_initiator_group'):
6326            with mock.patch.object(
6327                rest.VMAXRest, 'is_volume_in_storagegroup',
6328                    side_effect=[True, False]):
6329                msg = (
6330                    self.driver.masking._check_adding_volume_to_storage_group(
6331                        self.data.array, self.device_id,
6332                        self.data.storagegroup_name_i,
6333                        self.maskingviewdict[utils.VOL_NAME],
6334                        self.maskingviewdict[utils.EXTRA_SPECS]))
6335                self.assertIsNone(msg)
6336                msg = (
6337                    self.driver.masking._check_adding_volume_to_storage_group(
6338                        self.data.array, self.device_id,
6339                        self.data.storagegroup_name_i,
6340                        self.maskingviewdict[utils.VOL_NAME],
6341                        self.maskingviewdict[utils.EXTRA_SPECS]))
6342
6343    @mock.patch.object(rest.VMAXRest, 'add_vol_to_sg')
6344    def test_add_volume_to_storage_group(self, mock_add_volume):
6345        self.driver.masking.add_volume_to_storage_group(
6346            self.data.array, self.device_id, self.data.storagegroup_name_i,
6347            self.volume_name, self.extra_specs)
6348        mock_add_volume.assert_called_once()
6349
6350    @mock.patch.object(rest.VMAXRest, 'remove_vol_from_sg')
6351    def test_remove_vol_from_storage_group(self, mock_remove_volume):
6352        with mock.patch.object(
6353                rest.VMAXRest, 'is_volume_in_storagegroup',
6354                side_effect=[False, True]):
6355            self.driver.masking.remove_vol_from_storage_group(
6356                self.data.array, self.device_id, self.data.storagegroup_name_i,
6357                self.volume_name, self.extra_specs)
6358            mock_remove_volume.assert_called_once()
6359            self.assertRaises(
6360                exception.VolumeBackendAPIException,
6361                self.driver.masking.remove_vol_from_storage_group,
6362                self.data.array, self.device_id, self.data.storagegroup_name_i,
6363                self.volume_name, self.extra_specs)
6364
6365    def test_find_initiator_names(self):
6366        foundinitiatornames = self.driver.masking.find_initiator_names(
6367            self.data.connector)
6368        self.assertEqual(self.data.connector['initiator'],
6369                         foundinitiatornames[0])
6370        foundinitiatornames = self.driver_fc.masking.find_initiator_names(
6371            self.data.connector)
6372        self.assertEqual(self.data.connector['wwpns'][0],
6373                         foundinitiatornames[0])
6374        connector = {'ip': self.data.ip, 'initiator': None, 'host': 'HostX'}
6375        self.assertRaises(
6376            exception.VolumeBackendAPIException,
6377            self.driver.masking.find_initiator_names, connector)
6378        self.assertRaises(
6379            exception.VolumeBackendAPIException,
6380            self.driver_fc.masking.find_initiator_names, connector)
6381
6382    def test_find_initiator_group_found(self):
6383        with mock.patch.object(
6384                rest.VMAXRest, 'get_initiator_list',
6385                return_value=self.data.initiator_list[2]['initiatorId']):
6386            with mock.patch.object(
6387                    rest.VMAXRest, 'get_initiator_group_from_initiator',
6388                    return_value=self.data.initiator_list):
6389                found_init_group_nam = (
6390                    self.driver.masking._find_initiator_group(
6391                        self.data.array, ['FA-1D:4:123456789012345']))
6392                self.assertEqual(self.data.initiator_list,
6393                                 found_init_group_nam)
6394
6395    def test_find_initiator_group_not_found(self):
6396        with mock.patch.object(
6397                rest.VMAXRest, 'get_initiator_list',
6398                return_value=self.data.initiator_list[2]['initiatorId']):
6399            with mock.patch.object(
6400                    rest.VMAXRest, 'get_initiator_group_from_initiator',
6401                    return_value=None):
6402                found_init_group_nam = (
6403                    self.driver.masking._find_initiator_group(
6404                        self.data.array, ['Error']))
6405                self.assertIsNone(found_init_group_nam)
6406
6407    def test_create_masking_view(self):
6408        with mock.patch.object(rest.VMAXRest, 'create_masking_view',
6409                               side_effect=[None, Exception]):
6410            error_message = self.driver.masking.create_masking_view(
6411                self.data.array, self.maskingviewdict['maskingview_name'],
6412                self.data.storagegroup_name_i, self.data.port_group_name_i,
6413                self.data.initiatorgroup_name_i, self.extra_specs)
6414            self.assertIsNone(error_message)
6415            error_message = self.driver.masking.create_masking_view(
6416                self.data.array, self.maskingviewdict['maskingview_name'],
6417                self.data.storagegroup_name_i, self.data.port_group_name_i,
6418                self.data.initiatorgroup_name_i, self.extra_specs)
6419            self.assertIsNotNone(error_message)
6420
6421    @mock.patch.object(masking.VMAXMasking, '_check_ig_rollback')
6422    def test_check_if_rollback_action_for_masking_required(self,
6423                                                           mock_check_ig):
6424        with mock.patch.object(rest.VMAXRest,
6425                               'get_storage_groups_from_volume',
6426                               side_effect=[
6427                                   exception.VolumeBackendAPIException,
6428                                   self.data.storagegroup_list,
6429                                   self.data.storagegroup_list, None,
6430                                   None, ]):
6431            self.assertRaises(
6432                exception.VolumeBackendAPIException,
6433                self.mask.check_if_rollback_action_for_masking_required,
6434                self.data.array, self.data.test_volume,
6435                self.device_id, self.maskingviewdict)
6436            with mock.patch.object(masking.VMAXMasking,
6437                                   'remove_and_reset_members'):
6438                self.maskingviewdict[
6439                    'default_sg_name'] = self.data.defaultstoragegroup_name
6440                error_message = (
6441                    self.mask.check_if_rollback_action_for_masking_required(
6442                        self.data.array, self.data.test_volume,
6443                        self.device_id, self.maskingviewdict))
6444                self.assertIsNone(error_message)
6445
6446    @mock.patch.object(rest.VMAXRest, 'delete_masking_view')
6447    @mock.patch.object(rest.VMAXRest, 'delete_initiator_group')
6448    @mock.patch.object(rest.VMAXRest, 'get_initiator_group')
6449    @mock.patch.object(masking.VMAXMasking, '_find_initiator_group',
6450                       return_value=VMAXCommonData.initiatorgroup_name_i)
6451    def test_verify_initiator_group_from_masking_view(
6452            self, mock_find_ig, mock_get_ig, mock_delete_ig, mock_delete_mv):
6453        self.mask._verify_initiator_group_from_masking_view(
6454            self.data.array, self.maskingviewdict['maskingview_name'],
6455            self.maskingviewdict, self.data.initiatorgroup_name_i,
6456            self.data.storagegroup_name_i, self.data.port_group_name_i,
6457            self.extra_specs)
6458        mock_get_ig.assert_not_called()
6459        mock_get_ig.return_value = False
6460        self.mask._verify_initiator_group_from_masking_view(
6461            self.data.array, self.maskingviewdict['maskingview_name'],
6462            self.maskingviewdict, 'OS-Wrong-Host-I-IG',
6463            self.data.storagegroup_name_i, self.data.port_group_name_i,
6464            self.extra_specs)
6465        mock_get_ig.assert_called()
6466
6467    @mock.patch.object(rest.VMAXRest, 'delete_masking_view')
6468    @mock.patch.object(rest.VMAXRest, 'delete_initiator_group')
6469    @mock.patch.object(rest.VMAXRest, 'get_initiator_group',
6470                       return_value=True)
6471    @mock.patch.object(masking.VMAXMasking, '_find_initiator_group',
6472                       return_value=VMAXCommonData.initiatorgroup_name_i)
6473    def test_verify_initiator_group_from_masking_view2(
6474            self, mock_find_ig, mock_get_ig, mock_delete_ig, mock_delete_mv):
6475        mock_delete_mv.side_effect = [None, Exception]
6476        self.mask._verify_initiator_group_from_masking_view(
6477            self.data.array, self.maskingviewdict['maskingview_name'],
6478            self.maskingviewdict, 'OS-Wrong-Host-I-IG',
6479            self.data.storagegroup_name_i, self.data.port_group_name_i,
6480            self.extra_specs)
6481        mock_delete_mv.assert_called()
6482        _, found_ig_from_connector = (
6483            self.mask._verify_initiator_group_from_masking_view(
6484                self.data.array, self.maskingviewdict['maskingview_name'],
6485                self.maskingviewdict, 'OS-Wrong-Host-I-IG',
6486                self.data.storagegroup_name_i, self.data.port_group_name_i,
6487                self.extra_specs))
6488        self.assertEqual(self.data.initiatorgroup_name_i,
6489                         found_ig_from_connector)
6490
6491    @mock.patch.object(rest.VMAXRest, 'create_initiator_group')
6492    def test_create_initiator_group(self, mock_create_ig):
6493        initiator_names = self.mask.find_initiator_names(self.data.connector)
6494        ret_init_group_name = self.mask._create_initiator_group(
6495            self.data.array, self.data.initiatorgroup_name_i, initiator_names,
6496            self.extra_specs)
6497        self.assertEqual(self.data.initiatorgroup_name_i, ret_init_group_name)
6498
6499    @mock.patch.object(masking.VMAXMasking,
6500                       '_last_volume_delete_initiator_group')
6501    def test_check_ig_rollback(self, mock_last_volume):
6502        with mock.patch.object(masking.VMAXMasking, '_find_initiator_group',
6503                               side_effect=[
6504                                   None, 'FAKE-I-IG',
6505                                   self.data.initiatorgroup_name_i]):
6506            for x in range(0, 2):
6507                self.mask._check_ig_rollback(self.data.array,
6508                                             self.data.initiatorgroup_name_i,
6509                                             self.data.connector)
6510            mock_last_volume.assert_not_called()
6511            self.mask._check_ig_rollback(
6512                self.data.array, self.data.initiatorgroup_name_i,
6513                self.data.connector)
6514            mock_last_volume.assert_called()
6515
6516    @mock.patch.object(masking.VMAXMasking, '_cleanup_deletion')
6517    def test_remove_and_reset_members(self, mock_cleanup):
6518        self.mask.remove_and_reset_members(
6519            self.data.array, self.device_id, self.data.test_volume,
6520            self.volume_name, self.extra_specs, reset=False)
6521        mock_cleanup.assert_called_once()
6522
6523    @mock.patch.object(rest.VMAXRest, 'get_storage_groups_from_volume',
6524                       side_effect=[[VMAXCommonData.storagegroup_name_i],
6525                                    [VMAXCommonData.storagegroup_name_i],
6526                                    [VMAXCommonData.storagegroup_name_i,
6527                                     VMAXCommonData.storagegroup_name_f]])
6528    @mock.patch.object(masking.VMAXMasking, 'remove_volume_from_sg')
6529    @mock.patch.object(masking.VMAXMasking,
6530                       'add_volume_to_default_storage_group')
6531    def test_cleanup_deletion(self, mock_add, mock_remove_vol, mock_get_sg):
6532        self.mask._cleanup_deletion(
6533            self.data.array, self.data.test_volume, self.device_id,
6534            self.volume_name, self.extra_specs, None, True, None)
6535        mock_add.assert_not_called()
6536        self.mask._cleanup_deletion(
6537            self.data.array, self.data.test_volume, self.device_id,
6538            self.volume_name, self.extra_specs,
6539            self.data.connector, True, None)
6540        mock_add.assert_not_called()
6541        self.mask._cleanup_deletion(
6542            self.data.array, self.data.test_volume, self.device_id,
6543            self.volume_name, self.extra_specs, None, True, None)
6544        mock_add.assert_called_once_with(
6545            self.data.array, self.device_id,
6546            self.volume_name, self.extra_specs, volume=self.data.test_volume)
6547
6548    @mock.patch.object(masking.VMAXMasking, '_last_vol_in_sg')
6549    @mock.patch.object(masking.VMAXMasking, '_multiple_vols_in_sg')
6550    def test_remove_volume_from_sg(self, mock_multiple_vols, mock_last_vol):
6551        with mock.patch.object(
6552                rest.VMAXRest, 'get_masking_views_from_storage_group',
6553                return_value=None):
6554            with mock.patch.object(
6555                rest.VMAXRest, 'get_num_vols_in_sg',
6556                    side_effect=[2, 1]):
6557                self.mask.remove_volume_from_sg(
6558                    self.data.array, self.device_id, self.volume_name,
6559                    self.data.defaultstoragegroup_name, self.extra_specs)
6560                mock_last_vol.assert_not_called()
6561                self.mask.remove_volume_from_sg(
6562                    self.data.array, self.device_id, self.volume_name,
6563                    self.data.defaultstoragegroup_name, self.extra_specs)
6564                mock_last_vol.assert_called()
6565
6566    @mock.patch.object(masking.VMAXMasking, '_last_vol_in_sg')
6567    @mock.patch.object(masking.VMAXMasking, '_multiple_vols_in_sg')
6568    def test_remove_volume_from_sg_2(self, mock_multiple_vols, mock_last_vol):
6569        with mock.patch.object(
6570                rest.VMAXRest, 'is_volume_in_storagegroup',
6571                return_value=True):
6572            with mock.patch.object(
6573                    rest.VMAXRest, 'get_masking_views_from_storage_group',
6574                    return_value=[self.data.masking_view_name_i]):
6575                with mock.patch.object(
6576                    rest.VMAXRest, 'get_num_vols_in_sg',
6577                        side_effect=[2, 1]):
6578                    self.mask.remove_volume_from_sg(
6579                        self.data.array, self.device_id, self.volume_name,
6580                        self.data.storagegroup_name_i, self.extra_specs)
6581                    mock_last_vol.assert_not_called()
6582                    self.mask.remove_volume_from_sg(
6583                        self.data.array, self.device_id, self.volume_name,
6584                        self.data.storagegroup_name_i, self.extra_specs)
6585                    mock_last_vol.assert_called()
6586
6587    @mock.patch.object(masking.VMAXMasking, '_last_vol_masking_views',
6588                       return_value=True)
6589    @mock.patch.object(masking.VMAXMasking, '_last_vol_no_masking_views',
6590                       return_value=True)
6591    def test_last_vol_in_sg(self, mock_no_mv, mock_mv):
6592        mv_list = [self.data.masking_view_name_i,
6593                   self.data.masking_view_name_f]
6594        with mock.patch.object(rest.VMAXRest,
6595                               'get_masking_views_from_storage_group',
6596                               side_effect=[mv_list, []]):
6597            for x in range(0, 2):
6598                self.mask._last_vol_in_sg(
6599                    self.data.array, self.device_id, self.volume_name,
6600                    self.data.storagegroup_name_i, self.extra_specs,
6601                    self.data.connector)
6602            self.assertEqual(1, mock_mv.call_count)
6603            self.assertEqual(1, mock_no_mv.call_count)
6604
6605    @mock.patch.object(masking.VMAXMasking, '_remove_last_vol_and_delete_sg')
6606    @mock.patch.object(masking.VMAXMasking, '_delete_cascaded_storage_groups')
6607    @mock.patch.object(rest.VMAXRest, 'get_num_vols_in_sg',
6608                       side_effect=[1, 3])
6609    @mock.patch.object(rest.VMAXRest, 'delete_storage_group')
6610    @mock.patch.object(masking.VMAXMasking, 'get_parent_sg_from_child',
6611                       side_effect=[None, 'parent_sg_name', 'parent_sg_name'])
6612    def test_last_vol_no_masking_views(
6613            self, mock_get_parent, mock_delete, mock_num_vols,
6614            mock_delete_casc, mock_remove):
6615        for x in range(0, 3):
6616            self.mask._last_vol_no_masking_views(
6617                self.data.array, self.data.storagegroup_name_i,
6618                self.device_id, self.volume_name, self.extra_specs,
6619                False)
6620        self.assertEqual(1, mock_delete.call_count)
6621        self.assertEqual(1, mock_delete_casc.call_count)
6622        self.assertEqual(1, mock_remove.call_count)
6623
6624    @mock.patch.object(masking.VMAXMasking, '_remove_last_vol_and_delete_sg')
6625    @mock.patch.object(masking.VMAXMasking, '_delete_mv_ig_and_sg')
6626    @mock.patch.object(masking.VMAXMasking, '_get_num_vols_from_mv',
6627                       side_effect=[(1, 'parent_name'), (3, 'parent_name')])
6628    def test_last_vol_masking_views(
6629            self, mock_num_vols, mock_delete_all, mock_remove):
6630        for x in range(0, 2):
6631            self.mask._last_vol_masking_views(
6632                self.data.array, self.data.storagegroup_name_i,
6633                [self.data.masking_view_name_i], self.device_id,
6634                self.volume_name, self.extra_specs, self.data.connector,
6635                True)
6636        self.assertEqual(1, mock_delete_all.call_count)
6637        self.assertEqual(1, mock_remove.call_count)
6638
6639    @mock.patch.object(masking.VMAXMasking,
6640                       'add_volume_to_default_storage_group')
6641    @mock.patch.object(rest.VMAXRest, 'get_num_vols_in_sg')
6642    @mock.patch.object(masking.VMAXMasking, 'remove_vol_from_storage_group')
6643    def test_multiple_vols_in_sg(self, mock_remove_vol, mock_get_volumes,
6644                                 mock_add):
6645        self.mask._multiple_vols_in_sg(
6646            self.data.array, self.device_id, self.data.storagegroup_name_i,
6647            self.volume_name, self.extra_specs, False)
6648        mock_remove_vol.assert_called_once()
6649        self.mask._multiple_vols_in_sg(
6650            self.data.array, self.device_id, self.data.storagegroup_name_i,
6651            self.volume_name, self.extra_specs, True)
6652        mock_add.assert_called_once()
6653
6654    @mock.patch.object(rest.VMAXRest, 'get_element_from_masking_view')
6655    @mock.patch.object(masking.VMAXMasking, '_last_volume_delete_masking_view')
6656    @mock.patch.object(masking.VMAXMasking,
6657                       '_last_volume_delete_initiator_group')
6658    @mock.patch.object(masking.VMAXMasking, '_delete_cascaded_storage_groups')
6659    def test_delete_mv_ig_and_sg(self, mock_delete_sg, mock_delete_ig,
6660                                 mock_delete_mv, mock_get_element):
6661        self.mask._delete_mv_ig_and_sg(
6662            self.data.array, self.data.device_id,
6663            self.data.masking_view_name_i,
6664            self.data.storagegroup_name_i, self.data.parent_sg_i,
6665            self.data.connector, True, self.data.extra_specs)
6666        mock_delete_sg.assert_called_once()
6667
6668    @mock.patch.object(rest.VMAXRest, 'delete_masking_view')
6669    def test_last_volume_delete_masking_view(self, mock_delete_mv):
6670        self.mask._last_volume_delete_masking_view(
6671            self.data.array, self.data.masking_view_name_i)
6672        mock_delete_mv.assert_called_once()
6673
6674    @mock.patch.object(rest.VMAXRest, 'move_volume_between_storage_groups')
6675    @mock.patch.object(masking.VMAXMasking,
6676                       'get_or_create_default_storage_group')
6677    @mock.patch.object(masking.VMAXMasking, 'add_volume_to_storage_group')
6678    def test_add_volume_to_default_storage_group(
6679            self, mock_add_sg, mock_get_sg, mock_move):
6680        self.mask.add_volume_to_default_storage_group(
6681            self.data.array, self.device_id, self.volume_name,
6682            self.extra_specs)
6683        mock_add_sg.assert_called_once()
6684        self.mask.add_volume_to_default_storage_group(
6685            self.data.array, self.device_id, self.volume_name,
6686            self.extra_specs, src_sg=self.data.storagegroup_name_i)
6687        mock_move.assert_called_once()
6688        mock_add_sg.reset_mock()
6689        vol_grp_member = deepcopy(self.data.test_volume)
6690        vol_grp_member.group_id = self.data.test_vol_grp_name_id_only
6691        vol_grp_member.group = self.data.test_group
6692        self.mask.add_volume_to_default_storage_group(
6693            self.data.array, self.device_id, self.volume_name,
6694            self.extra_specs, volume=vol_grp_member)
6695        self.assertEqual(2, mock_add_sg.call_count)
6696
6697    def test_add_volume_to_default_storage_group_next_gen(self):
6698        with mock.patch.object(rest.VMAXRest, 'is_next_gen_array',
6699                               return_value=True):
6700            with mock.patch.object(
6701                    self.mask, 'get_or_create_default_storage_group'):
6702                self.mask.add_volume_to_default_storage_group(
6703                    self.data.array, self.device_id, self.volume_name,
6704                    self.extra_specs)
6705                (self.mask.get_or_create_default_storage_group
6706                    .assert_called_once_with(self.data.array, self.data.srp,
6707                                             self.extra_specs[utils.SLO],
6708                                             'NONE', self.extra_specs, False,
6709                                             False, None))
6710
6711    @mock.patch.object(provision.VMAXProvision, 'create_storage_group')
6712    def test_get_or_create_default_storage_group(self, mock_create_sg):
6713        with mock.patch.object(
6714                rest.VMAXRest, 'get_vmax_default_storage_group',
6715                return_value=(None, self.data.storagegroup_name_i)):
6716            storage_group_name = self.mask.get_or_create_default_storage_group(
6717                self.data.array, self.data.srp, self.data.slo,
6718                self.data.workload, self.extra_specs)
6719            self.assertEqual(self.data.storagegroup_name_i, storage_group_name)
6720        with mock.patch.object(
6721                rest.VMAXRest, 'get_vmax_default_storage_group',
6722                return_value=("test_sg", self.data.storagegroup_name_i)):
6723            with mock.patch.object(
6724                rest.VMAXRest, 'get_masking_views_from_storage_group',
6725                    return_value=self.data.masking_view_name_i):
6726                self.assertRaises(
6727                    exception.VolumeBackendAPIException,
6728                    self.mask.get_or_create_default_storage_group,
6729                    self.data.array, self.data.srp, self.data.slo,
6730                    self.data.workload, self.extra_specs)
6731
6732    @mock.patch.object(masking.VMAXMasking,
6733                       'add_volume_to_default_storage_group')
6734    @mock.patch.object(rest.VMAXRest, 'remove_child_sg_from_parent_sg')
6735    @mock.patch.object(rest.VMAXRest, 'delete_storage_group')
6736    @mock.patch.object(masking.VMAXMasking, 'remove_vol_from_storage_group')
6737    def test_remove_last_vol_and_delete_sg(self, mock_vol_sg,
6738                                           mock_delete_sg, mock_rm, mock_add):
6739        self.mask._remove_last_vol_and_delete_sg(
6740            self.data.array, self.device_id, self.volume_name,
6741            self.data.storagegroup_name_i, self.extra_specs)
6742        self.mask._remove_last_vol_and_delete_sg(
6743            self.data.array, self.device_id, self.volume_name,
6744            self.data.storagegroup_name_i, self.extra_specs,
6745            self.data.parent_sg_i, True)
6746        self.assertEqual(2, mock_delete_sg.call_count)
6747        self.assertEqual(1, mock_vol_sg.call_count)
6748        self.assertEqual(1, mock_rm.call_count)
6749        self.assertEqual(1, mock_add.call_count)
6750
6751    @mock.patch.object(rest.VMAXRest, 'delete_initiator_group')
6752    def test_last_volume_delete_initiator_group(self, mock_delete_ig):
6753        self.mask._last_volume_delete_initiator_group(
6754            self.data.array, self.data.initiatorgroup_name_f, 'Wrong_Host')
6755        mock_delete_ig.assert_not_called()
6756        self.mask._last_volume_delete_initiator_group(
6757            self.data.array, self.data.initiatorgroup_name_f, None)
6758        mock_delete_ig.assert_not_called()
6759        mv_list = [self.data.masking_view_name_i,
6760                   self.data.masking_view_name_f]
6761        with mock.patch.object(rest.VMAXRest,
6762                               'get_masking_views_by_initiator_group',
6763                               side_effect=[mv_list, []]):
6764            self.mask._last_volume_delete_initiator_group(
6765                self.data.array, self.data.initiatorgroup_name_i,
6766                self.data.connector['host'])
6767            mock_delete_ig.assert_not_called()
6768            self.mask._last_volume_delete_initiator_group(
6769                self.data.array, self.data.initiatorgroup_name_i,
6770                self.data.connector['host'])
6771            mock_delete_ig.assert_called_once()
6772
6773    def test_populate_masking_dict_init_check_false(self):
6774        extra_specs = self.data.extra_specs
6775        connector = self.data.connector
6776        with mock.patch.object(self.driver, '_get_initiator_check_flag',
6777                               return_value=False):
6778            masking_view_dict = self.driver._populate_masking_dict(
6779                self.data.test_volume, connector, extra_specs)
6780            self.assertFalse(masking_view_dict['initiator_check'])
6781
6782    def test_populate_masking_dict_init_check_true(self):
6783        extra_specs = self.data.extra_specs
6784        connector = self.data.connector
6785        with mock.patch.object(self.driver, '_get_initiator_check_flag',
6786                               return_value=True):
6787            masking_view_dict = self.driver._populate_masking_dict(
6788                self.data.test_volume, connector, extra_specs)
6789            self.assertTrue(masking_view_dict['initiator_check'])
6790
6791    def test_check_existing_initiator_group_verify_true(self):
6792        mv_dict = deepcopy(self.data.masking_view_dict)
6793        mv_dict['initiator_check'] = True
6794        with mock.patch.object(
6795                rest.VMAXRest, 'get_element_from_masking_view',
6796                return_value=VMAXCommonData.initiatorgroup_name_f):
6797            with mock.patch.object(
6798                    self.mask, '_verify_initiator_group_from_masking_view',
6799                    return_value=(True, self.data.initiatorgroup_name_f)):
6800                self.mask._check_existing_initiator_group(
6801                    self.data.array, self.data.masking_view_name_f,
6802                    mv_dict, self.data.storagegroup_name_f,
6803                    self.data.port_group_name_f, self.data.extra_specs)
6804                (self.mask._verify_initiator_group_from_masking_view.
6805                    assert_called_once_with(
6806                        self.data.array, self.data.masking_view_name_f,
6807                        mv_dict, self.data.initiatorgroup_name_f,
6808                        self.data.storagegroup_name_f,
6809                        self.data.port_group_name_f, self.data.extra_specs))
6810
6811    @mock.patch.object(masking.VMAXMasking, 'add_child_sg_to_parent_sg',
6812                       side_effect=[
6813                           None, exception.VolumeBackendAPIException])
6814    @mock.patch.object(rest.VMAXRest, 'is_child_sg_in_parent_sg',
6815                       side_effect=[True, False, False])
6816    def test_check_add_child_sg_to_parent_sg(self, mock_is_child, mock_add):
6817        for x in range(0, 3):
6818            message = self.mask._check_add_child_sg_to_parent_sg(
6819                self.data.array, self.data.storagegroup_name_i,
6820                self.data.parent_sg_i, self.data.extra_specs)
6821        self.assertIsNotNone(message)
6822
6823    @mock.patch.object(rest.VMAXRest, 'add_child_sg_to_parent_sg')
6824    @mock.patch.object(rest.VMAXRest, 'is_child_sg_in_parent_sg',
6825                       side_effect=[True, False])
6826    def test_add_child_sg_to_parent_sg(self, mock_is_child, mock_add):
6827        for x in range(0, 2):
6828            self.mask.add_child_sg_to_parent_sg(
6829                self.data.array, self.data.storagegroup_name_i,
6830                self.data.parent_sg_i, self.data.extra_specs)
6831        self.assertEqual(1, mock_add.call_count)
6832
6833    def test_get_parent_sg_from_child(self):
6834        with mock.patch.object(self.driver.rest, 'get_storage_group',
6835                               side_effect=[None, self.data.sg_details[1]]):
6836            sg_name = self.mask.get_parent_sg_from_child(
6837                self.data.array, self.data.storagegroup_name_i)
6838            self.assertIsNone(sg_name)
6839            sg_name2 = self.mask.get_parent_sg_from_child(
6840                self.data.array, self.data.storagegroup_name_f)
6841            self.assertEqual(self.data.parent_sg_f, sg_name2)
6842
6843    @mock.patch.object(rest.VMAXRest, 'get_element_from_masking_view',
6844                       return_value='parent_sg')
6845    @mock.patch.object(rest.VMAXRest, 'get_num_vols_in_sg',
6846                       return_value=2)
6847    def test_get_num_vols_from_mv(self, mock_num, mock_element):
6848        num_vols, sg = self.mask._get_num_vols_from_mv(
6849            self.data.array, self.data.masking_view_name_f)
6850        self.assertEqual(2, num_vols)
6851
6852    @mock.patch.object(masking.VMAXMasking,
6853                       'add_volume_to_default_storage_group')
6854    @mock.patch.object(rest.VMAXRest, 'delete_storage_group')
6855    def test_delete_cascaded(self, mock_delete, mock_add):
6856        self.mask._delete_cascaded_storage_groups(
6857            self.data.array, self.data.masking_view_name_f,
6858            self.data.parent_sg_f, self.data.extra_specs,
6859            self.data.device_id, False)
6860        self.assertEqual(2, mock_delete.call_count)
6861        mock_add.assert_not_called()
6862        # Delete legacy masking view, parent sg = child sg
6863        mock_delete.reset_mock()
6864        self.mask._delete_cascaded_storage_groups(
6865            self.data.array, self.data.masking_view_name_f,
6866            self.data.masking_view_name_f, self.data.extra_specs,
6867            self.data.device_id, True)
6868        self.assertEqual(1, mock_delete.call_count)
6869        mock_add.assert_called_once()
6870
6871    @mock.patch.object(masking.VMAXMasking, 'add_child_sg_to_parent_sg')
6872    @mock.patch.object(masking.VMAXMasking,
6873                       'move_volume_between_storage_groups')
6874    @mock.patch.object(provision.VMAXProvision, 'create_storage_group')
6875    def test_pre_live_migration(self, mock_create_sg, mock_move, mock_add):
6876        with mock.patch.object(
6877                rest.VMAXRest, 'get_storage_group',
6878                side_effect=[None, self.data.sg_details[1]["storageGroupId"]]
6879        ):
6880            source_sg = self.data.sg_details[2]["storageGroupId"]
6881            source_parent_sg = self.data.sg_details[4]["storageGroupId"]
6882            source_nf_sg = source_parent_sg[:-2] + 'NONFAST'
6883            self.data.iscsi_device_info['device_id'] = self.data.device_id
6884            self.mask.pre_live_migration(
6885                source_nf_sg, source_sg, source_parent_sg, False,
6886                self.data.iscsi_device_info, None)
6887            mock_create_sg.assert_called_once()
6888
6889    @mock.patch.object(rest.VMAXRest, 'delete_storage_group')
6890    @mock.patch.object(rest.VMAXRest, 'remove_child_sg_from_parent_sg')
6891    def test_post_live_migration(self, mock_remove_child_sg, mock_delete_sg):
6892        self.data.iscsi_device_info['source_sg'] = self.data.sg_details[2][
6893            "storageGroupId"]
6894        self.data.iscsi_device_info['source_parent_sg'] = self.data.sg_details[
6895            4]["storageGroupId"]
6896        with mock.patch.object(
6897                rest.VMAXRest, 'get_num_vols_in_sg', side_effect=[0, 1]):
6898            self.mask.post_live_migration(self.data.iscsi_device_info, None)
6899            mock_remove_child_sg.assert_called_once()
6900            mock_delete_sg.assert_called_once()
6901
6902    @mock.patch.object(masking.VMAXMasking,
6903                       'move_volume_between_storage_groups')
6904    @mock.patch.object(rest.VMAXRest, 'delete_storage_group')
6905    @mock.patch.object(rest.VMAXRest, 'remove_child_sg_from_parent_sg')
6906    @mock.patch.object(masking.VMAXMasking, 'remove_volume_from_sg')
6907    def test_failed_live_migration(
6908            self, mock_remove_volume, mock_remove_child_sg, mock_delete_sg,
6909            mock_move):
6910        device_dict = self.data.iscsi_device_info
6911        device_dict['device_id'] = self.data.device_id
6912        device_dict['source_sg'] = self.data.sg_details[2]["storageGroupId"]
6913        device_dict['source_parent_sg'] = self.data.sg_details[4][
6914            "storageGroupId"]
6915        device_dict['source_nf_sg'] = (
6916            self.data.sg_details[4]["storageGroupId"][:-2] + 'NONFAST')
6917        sg_list = [device_dict['source_nf_sg']]
6918        with mock.patch.object(
6919                rest.VMAXRest, 'is_child_sg_in_parent_sg',
6920                side_effect=[True, False]):
6921            self.mask.failed_live_migration(device_dict, sg_list, None)
6922            mock_remove_volume.assert_not_called()
6923            mock_remove_child_sg.assert_called_once()
6924
6925
6926class VMAXCommonReplicationTest(test.TestCase):
6927    def setUp(self):
6928        self.data = VMAXCommonData()
6929
6930        super(VMAXCommonReplicationTest, self).setUp()
6931        config_group = 'CommonReplicationTests'
6932        self.fake_xml = FakeXML().create_fake_config_file(
6933            config_group, self.data.port_group_name_f)
6934        self.replication_device = {
6935            'target_device_id': self.data.remote_array,
6936            'remote_port_group': self.data.port_group_name_f,
6937            'remote_pool': self.data.srp2,
6938            'rdf_group_label': self.data.rdf_group_name,
6939            'allow_extend': 'True'}
6940        volume_utils.get_max_over_subscription_ratio = mock.Mock()
6941        configuration = FakeConfiguration(
6942            self.fake_xml, config_group,
6943            replication_device=self.replication_device)
6944        rest.VMAXRest._establish_rest_session = mock.Mock(
6945            return_value=FakeRequestsSession())
6946        driver = fc.VMAXFCDriver(configuration=configuration)
6947        iscsi_fake_xml = FakeXML().create_fake_config_file(
6948            config_group, self.data.port_group_name_i)
6949        iscsi_config = FakeConfiguration(
6950            iscsi_fake_xml, config_group,
6951            replication_device=self.replication_device)
6952        iscsi_driver = iscsi.VMAXISCSIDriver(configuration=iscsi_config)
6953        self.iscsi_common = iscsi_driver.common
6954        self.driver = driver
6955        self.common = self.driver.common
6956        self.masking = self.common.masking
6957        self.provision = self.common.provision
6958        self.rest = self.common.rest
6959        self.utils = self.common.utils
6960        self.utils.get_volumetype_extra_specs = (
6961            mock.Mock(
6962                return_value=self.data.vol_type_extra_specs_rep_enabled))
6963        self.extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
6964        self.extra_specs['retries'] = 0
6965        self.extra_specs['interval'] = 0
6966        self.extra_specs['rep_mode'] = 'Synchronous'
6967        self.async_rep_device = {
6968            'target_device_id': self.data.remote_array,
6969            'remote_port_group': self.data.port_group_name_f,
6970            'remote_pool': self.data.srp2,
6971            'rdf_group_label': self.data.rdf_group_name,
6972            'allow_extend': 'True', 'mode': 'async'}
6973        async_configuration = FakeConfiguration(
6974            self.fake_xml, config_group,
6975            replication_device=self.async_rep_device)
6976        self.async_driver = fc.VMAXFCDriver(configuration=async_configuration)
6977        self.metro_rep_device = {
6978            'target_device_id': self.data.remote_array,
6979            'remote_port_group': self.data.port_group_name_f,
6980            'remote_pool': self.data.srp2,
6981            'rdf_group_label': self.data.rdf_group_name,
6982            'allow_extend': 'True', 'mode': 'metro'}
6983        metro_configuration = FakeConfiguration(
6984            self.fake_xml, config_group,
6985            replication_device=self.metro_rep_device)
6986        self.metro_driver = fc.VMAXFCDriver(configuration=metro_configuration)
6987
6988    def test_get_replication_info(self):
6989        self.common._get_replication_info()
6990        self.assertTrue(self.common.replication_enabled)
6991
6992    @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
6993                       return_value=False)
6994    @mock.patch.object(objects.Group, 'get_by_id',
6995                       return_value=VMAXCommonData.test_rep_group)
6996    @mock.patch.object(volume_utils, 'is_group_a_type', return_value=True)
6997    @mock.patch.object(utils.VMAXUtils, 'check_replication_matched',
6998                       return_value=True)
6999    @mock.patch.object(masking.VMAXMasking, 'add_volume_to_storage_group')
7000    @mock.patch.object(
7001        common.VMAXCommon, '_replicate_volume',
7002        return_value={
7003            'replication_driver_data':
7004                VMAXCommonData.test_volume.replication_driver_data})
7005    def test_create_replicated_volume(self, mock_rep, mock_add, mock_match,
7006                                      mock_check, mock_get, mock_cg):
7007        extra_specs = deepcopy(self.extra_specs)
7008        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7009        vol_identifier = self.utils.get_volume_element_name(
7010            self.data.test_volume.id)
7011        self.common.create_volume(self.data.test_volume)
7012        volume_dict = self.data.provider_location
7013        mock_rep.assert_called_once_with(
7014            self.data.test_volume, vol_identifier, volume_dict,
7015            extra_specs)
7016        # Add volume to replication group
7017        self.common.create_volume(self.data.test_volume_group_member)
7018        mock_add.assert_called_once()
7019
7020    def test_create_cloned_replicated_volume(self):
7021        extra_specs = deepcopy(self.extra_specs)
7022        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7023        with mock.patch.object(self.common, '_replicate_volume',
7024                               return_value={}) as mock_rep:
7025            self.common.create_cloned_volume(
7026                self.data.test_clone_volume, self.data.test_volume)
7027            volume_dict = self.data.provider_location
7028            mock_rep.assert_called_once_with(
7029                self.data.test_clone_volume,
7030                self.data.test_clone_volume.name, volume_dict, extra_specs)
7031
7032    def test_create_replicated_volume_from_snap(self):
7033        extra_specs = deepcopy(self.extra_specs)
7034        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7035        with mock.patch.object(self.common, '_replicate_volume',
7036                               return_value={}) as mock_rep:
7037            self.common.create_volume_from_snapshot(
7038                self.data.test_clone_volume, self.data.test_snapshot)
7039            volume_dict = self.data.provider_location
7040            mock_rep.assert_called_once_with(
7041                self.data.test_clone_volume,
7042                "snapshot-%s" % self.data.snapshot_id,
7043                volume_dict,
7044                extra_specs)
7045
7046    def test_replicate_volume(self):
7047        volume_dict = self.data.provider_location
7048        rs_enabled = fields.ReplicationStatus.ENABLED
7049        with mock.patch.object(self.common, 'setup_volume_replication',
7050                               return_value=(rs_enabled, {})) as mock_setup:
7051            self.common._replicate_volume(
7052                self.data.test_volume, "1", volume_dict, self.extra_specs)
7053            mock_setup.assert_called_once_with(
7054                self.data.array, self.data.test_volume,
7055                self.data.device_id, self.extra_specs)
7056
7057    def test_replicate_volume_exception(self):
7058        volume_dict = self.data.provider_location
7059        with mock.patch.object(
7060                self.common, 'setup_volume_replication',
7061                side_effect=exception.VolumeBackendAPIException(data='')):
7062            with mock.patch.object(
7063                    self.common, '_cleanup_replication_source') as mock_clean:
7064                self.assertRaises(exception.VolumeBackendAPIException,
7065                                  self.common._replicate_volume,
7066                                  self.data.test_volume,
7067                                  "1", volume_dict, self.extra_specs)
7068                mock_clean.assert_called_once_with(
7069                    self.data.array, self.data.test_volume, "1",
7070                    volume_dict, self.extra_specs)
7071
7072    @mock.patch.object(common.VMAXCommon, '_remove_members')
7073    @mock.patch.object(common.VMAXCommon,
7074                       '_get_replication_extra_specs',
7075                       return_value=VMAXCommonData.rep_extra_specs)
7076    @mock.patch.object(utils.VMAXUtils, 'is_volume_failed_over',
7077                       return_value=True)
7078    def test_unmap_lun_volume_failed_over(self, mock_fo, mock_es, mock_rm):
7079        extra_specs = deepcopy(self.extra_specs)
7080        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7081        rep_config = self.utils.get_replication_config(
7082            [self.replication_device])
7083        self.common._unmap_lun(self.data.test_volume, self.data.connector)
7084        mock_es.assert_called_once_with(extra_specs, rep_config)
7085
7086    @mock.patch.object(common.VMAXCommon, '_remove_members')
7087    @mock.patch.object(common.VMAXCommon,
7088                       '_get_replication_extra_specs',
7089                       return_value=VMAXCommonData.rep_extra_specs)
7090    @mock.patch.object(utils.VMAXUtils, 'is_metro_device', return_value=True)
7091    def test_unmap_lun_metro(self, mock_md, mock_es, mock_rm):
7092        extra_specs = deepcopy(self.extra_specs)
7093        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7094        self.common._unmap_lun(self.data.test_volume, self.data.connector)
7095        self.assertEqual(2, mock_rm.call_count)
7096
7097    @mock.patch.object(utils.VMAXUtils, 'is_volume_failed_over',
7098                       return_value=True)
7099    def test_initialize_connection_vol_failed_over(self, mock_fo):
7100        extra_specs = deepcopy(self.extra_specs)
7101        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7102        rep_extra_specs = deepcopy(VMAXCommonData.rep_extra_specs)
7103        rep_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7104        rep_config = self.utils.get_replication_config(
7105            [self.replication_device])
7106        with mock.patch.object(self.common, '_get_replication_extra_specs',
7107                               return_value=rep_extra_specs) as mock_es:
7108            self.common.initialize_connection(
7109                self.data.test_volume, self.data.connector)
7110            mock_es.assert_called_once_with(extra_specs, rep_config)
7111
7112    @mock.patch.object(utils.VMAXUtils, 'is_metro_device', return_value=True)
7113    def test_initialize_connection_vol_metro(self, mock_md):
7114        metro_connector = deepcopy(self.data.connector)
7115        metro_connector['multipath'] = True
7116        info_dict = self.common.initialize_connection(
7117            self.data.test_volume, metro_connector)
7118        ref_dict = {'array': self.data.array,
7119                    'device_id': self.data.device_id,
7120                    'hostlunid': 3,
7121                    'maskingview': self.data.masking_view_name_f,
7122                    'metro_hostlunid': 3}
7123        self.assertEqual(ref_dict, info_dict)
7124
7125    @mock.patch.object(rest.VMAXRest, 'get_iscsi_ip_address_and_iqn',
7126                       return_value=([VMAXCommonData.ip],
7127                                     VMAXCommonData.initiator))
7128    @mock.patch.object(common.VMAXCommon, '_get_replication_extra_specs',
7129                       return_value=VMAXCommonData.rep_extra_specs)
7130    @mock.patch.object(utils.VMAXUtils, 'is_metro_device', return_value=True)
7131    def test_initialize_connection_vol_metro_iscsi(self, mock_md, mock_es,
7132                                                   mock_ip):
7133        metro_connector = deepcopy(self.data.connector)
7134        metro_connector['multipath'] = True
7135        info_dict = self.iscsi_common.initialize_connection(
7136            self.data.test_volume, metro_connector)
7137        ref_dict = {'array': self.data.array,
7138                    'device_id': self.data.device_id,
7139                    'hostlunid': 3,
7140                    'maskingview': self.data.masking_view_name_f,
7141                    'ip_and_iqn': [{'ip': self.data.ip,
7142                                    'iqn': self.data.initiator}],
7143                    'metro_hostlunid': 3,
7144                    'is_multipath': True,
7145                    'metro_ip_and_iqn': [{'ip': self.data.ip,
7146                                          'iqn': self.data.initiator}]}
7147        self.assertEqual(ref_dict, info_dict)
7148
7149    @mock.patch.object(utils.VMAXUtils, 'is_metro_device', return_value=True)
7150    def test_initialize_connection_no_multipath_iscsi(self, mock_md):
7151        info_dict = self.iscsi_common.initialize_connection(
7152            self.data.test_volume, self.data.connector)
7153        self.assertIsNone(info_dict)
7154
7155    def test_attach_metro_volume(self):
7156        rep_extra_specs = deepcopy(VMAXCommonData.rep_extra_specs)
7157        rep_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7158        hostlunid, remote_port_group = self.common._attach_metro_volume(
7159            self.data.test_volume, self.data.connector,
7160            self.data.extra_specs, rep_extra_specs)
7161        self.assertEqual(self.data.port_group_name_f, remote_port_group)
7162
7163    @mock.patch.object(rest.VMAXRest, 'is_vol_in_rep_session',
7164                       return_value=(False, False, None))
7165    @mock.patch.object(common.VMAXCommon, 'extend_volume_is_replicated')
7166    @mock.patch.object(common.VMAXCommon, '_sync_check')
7167    def test_extend_volume_rep_enabled(self, mock_sync, mock_ex_re,
7168                                       mock_is_re):
7169        extra_specs = deepcopy(self.extra_specs)
7170        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7171        volume_name = self.data.test_volume.name
7172        self.common.extend_volume(self.data.test_volume, '5')
7173        mock_ex_re.assert_called_once_with(
7174            self.data.array, self.data.test_volume,
7175            self.data.device_id, volume_name, "5", extra_specs)
7176
7177    def test_set_config_file_get_extra_specs_rep_enabled(self):
7178        extra_specs, _, _ = self.common._set_config_file_and_get_extra_specs(
7179            self.data.test_volume)
7180        self.assertTrue(extra_specs['replication_enabled'])
7181
7182    def test_populate_masking_dict_is_re(self):
7183        extra_specs = deepcopy(self.extra_specs)
7184        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7185        masking_dict = self.common._populate_masking_dict(
7186            self.data.test_volume, self.data.connector, extra_specs)
7187        self.assertTrue(masking_dict['replication_enabled'])
7188        self.assertEqual('OS-HostX-SRP_1-DiamondDSS-OS-fibre-PG-RE',
7189                         masking_dict[utils.SG_NAME])
7190
7191    @mock.patch.object(common.VMAXCommon,
7192                       '_replicate_volume',
7193                       return_value={})
7194    def test_manage_existing_is_replicated(self, mock_rep):
7195        extra_specs = deepcopy(self.extra_specs)
7196        extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7197        external_ref = {u'source-name': u'00002'}
7198        volume_name = self.utils.get_volume_element_name(
7199            self.data.test_volume.id)
7200        provider_location = {'device_id': u'00002', 'array': self.data.array}
7201        with mock.patch.object(
7202                self.common, '_check_lun_valid_for_cinder_management'):
7203            self.common.manage_existing(
7204                self.data.test_volume, external_ref)
7205            mock_rep.assert_called_once_with(
7206                self.data.test_volume, volume_name, provider_location,
7207                extra_specs, delete_src=False)
7208
7209    @mock.patch.object(masking.VMAXMasking, 'remove_and_reset_members')
7210    def test_setup_volume_replication(self, mock_rm):
7211        rep_status, rep_data = self.common.setup_volume_replication(
7212            self.data.array, self.data.test_volume, self.data.device_id,
7213            self.extra_specs)
7214        self.assertEqual(fields.ReplicationStatus.ENABLED, rep_status)
7215        self.assertEqual({'array': self.data.remote_array,
7216                          'device_id': self.data.device_id}, rep_data)
7217
7218    @mock.patch.object(masking.VMAXMasking, 'remove_and_reset_members')
7219    @mock.patch.object(common.VMAXCommon, '_create_volume')
7220    def test_setup_volume_replication_target(self, mock_create, mock_rm):
7221        rep_status, rep_data = self.common.setup_volume_replication(
7222            self.data.array, self.data.test_volume, self.data.device_id,
7223            self.extra_specs, self.data.device_id2)
7224        self.assertEqual(fields.ReplicationStatus.ENABLED, rep_status)
7225        self.assertEqual({'array': self.data.remote_array,
7226                          'device_id': self.data.device_id2}, rep_data)
7227        mock_create.assert_not_called()
7228
7229    @mock.patch.object(common.VMAXCommon, '_cleanup_remote_target')
7230    def test_cleanup_lun_replication_success(self, mock_clean):
7231        rep_extra_specs = deepcopy(self.data.rep_extra_specs)
7232        rep_extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
7233        self.common.cleanup_lun_replication(
7234            self.data.test_volume, "1", self.data.device_id,
7235            self.extra_specs)
7236        mock_clean.assert_called_once_with(
7237            self.data.array, self.data.test_volume,
7238            self.data.remote_array, self.data.device_id,
7239            self.data.device_id2, self.data.rdf_group_no, "1",
7240            rep_extra_specs)
7241        # Cleanup legacy replication
7242        self.common.cleanup_lun_replication(
7243            self.data.test_legacy_vol, "1", self.data.device_id,
7244            self.extra_specs)
7245        mock_clean.assert_called_once_with(
7246            self.data.array, self.data.test_volume,
7247            self.data.remote_array, self.data.device_id,
7248            self.data.device_id2, self.data.rdf_group_no, "1",
7249            rep_extra_specs)
7250
7251    @mock.patch.object(common.VMAXCommon, '_cleanup_remote_target')
7252    def test_cleanup_lun_replication_no_target(self, mock_clean):
7253        with mock.patch.object(self.common, 'get_remote_target_device',
7254                               return_value=(None, '', '', '', '')):
7255            self.common.cleanup_lun_replication(
7256                self.data.test_volume, "1", self.data.device_id,
7257                self.extra_specs)
7258            mock_clean.assert_not_called()
7259
7260    @mock.patch.object(
7261        common.VMAXCommon, 'get_remote_target_device',
7262        return_value=(VMAXCommonData.device_id2, '', '', '', ''))
7263    @mock.patch.object(common.VMAXCommon,
7264                       '_add_volume_to_async_rdf_managed_grp')
7265    def test_cleanup_lun_replication_exception(self, mock_add, mock_tgt):
7266        self.assertRaises(exception.VolumeBackendAPIException,
7267                          self.common.cleanup_lun_replication,
7268                          self.data.test_volume, "1", self.data.device_id,
7269                          self.extra_specs)
7270        # is metro or async volume
7271        extra_specs = deepcopy(self.extra_specs)
7272        extra_specs[utils.REP_MODE] = utils.REP_METRO
7273        self.assertRaises(exception.VolumeBackendAPIException,
7274                          self.common.cleanup_lun_replication,
7275                          self.data.test_volume, "1", self.data.device_id,
7276                          extra_specs)
7277        mock_add.assert_called_once()
7278
7279    @mock.patch.object(common.VMAXCommon, '_cleanup_metro_target')
7280    @mock.patch.object(masking.VMAXMasking, 'remove_vol_from_storage_group')
7281    @mock.patch.object(common.VMAXCommon, '_delete_from_srp')
7282    @mock.patch.object(provision.VMAXProvision, 'break_rdf_relationship')
7283    def test_cleanup_remote_target(self, mock_break, mock_del,
7284                                   mock_rm, mock_clean_metro):
7285        with mock.patch.object(self.rest, 'are_vols_rdf_paired',
7286                               return_value=(False, '', '')):
7287            self.common._cleanup_remote_target(
7288                self.data.array, self.data.test_volume,
7289                self.data.remote_array, self.data.device_id,
7290                self.data.device_id2, self.data.rdf_group_name,
7291                "vol1", self.data.rep_extra_specs)
7292            mock_break.assert_not_called()
7293        self.common._cleanup_remote_target(
7294            self.data.array, self.data.test_volume,
7295            self.data.remote_array, self.data.device_id,
7296            self.data.device_id2, self.data.rdf_group_name,
7297            "vol1", self.data.rep_extra_specs)
7298        mock_break.assert_called_once_with(
7299            self.data.array, self.data.device_id,
7300            self.data.device_id2, self.data.rdf_group_name,
7301            self.data.rep_extra_specs, "Synchronized")
7302        # is metro volume
7303        with mock.patch.object(self.utils, 'is_metro_device',
7304                               return_value=True):
7305            self.common._cleanup_remote_target(
7306                self.data.array, self.data.test_volume,
7307                self.data.remote_array, self.data.device_id,
7308                self.data.device_id2, self.data.rdf_group_name,
7309                "vol1", self.data.rep_extra_specs)
7310            mock_clean_metro.assert_called_once()
7311
7312    def test_cleanup_remote_target_exception(self):
7313        extra_specs = deepcopy(self.data.rep_extra_specs)
7314        extra_specs['mode'] = utils.REP_METRO
7315        self.assertRaises(exception.VolumeBackendAPIException,
7316                          self.metro_driver.common._cleanup_remote_target,
7317                          self.data.array, self.data.test_volume,
7318                          self.data.remote_array,
7319                          self.data.device_id, self.data.device_id2,
7320                          self.data.rdf_group_name, "vol1", extra_specs)
7321
7322    @mock.patch.object(provision.VMAXProvision, 'enable_group_replication')
7323    @mock.patch.object(rest.VMAXRest, 'get_num_vols_in_sg',
7324                       side_effect=[2, 0])
7325    def test_cleanup_metro_target(self, mock_vols, mock_enable):
7326        # allow delete is True
7327        specs = {'allow_del_metro': True}
7328        for x in range(0, 2):
7329            self.common._cleanup_metro_target(
7330                self.data.array, self.data.device_id, self.data.device_id2,
7331                self.data.rdf_group_no, specs)
7332            mock_enable.assert_called_once()
7333        # allow delete is False
7334        specs['allow_del_metro'] = False
7335        self.assertRaises(exception.VolumeBackendAPIException,
7336                          self.common._cleanup_metro_target,
7337                          self.data.array, self.data.device_id,
7338                          self.data.device_id2,
7339                          self.data.rdf_group_no, specs)
7340
7341    @mock.patch.object(common.VMAXCommon,
7342                       '_remove_vol_and_cleanup_replication')
7343    @mock.patch.object(masking.VMAXMasking, 'remove_vol_from_storage_group')
7344    @mock.patch.object(common.VMAXCommon, '_delete_from_srp')
7345    def test_cleanup_replication_source(self, mock_del, mock_rm, mock_clean):
7346        self.common._cleanup_replication_source(
7347            self.data.array, self.data.test_volume, "vol1",
7348            {'device_id': self.data.device_id}, self.extra_specs)
7349        mock_del.assert_called_once_with(
7350            self.data.array, self.data.device_id, "vol1", self.extra_specs)
7351
7352    def test_get_rdf_details(self):
7353        rdf_group_no, remote_array = self.common.get_rdf_details(
7354            self.data.array)
7355        self.assertEqual(self.data.rdf_group_no, rdf_group_no)
7356        self.assertEqual(self.data.remote_array, remote_array)
7357
7358    def test_get_rdf_details_exception(self):
7359        with mock.patch.object(self.rest, 'get_rdf_group_number',
7360                               return_value=None):
7361            self.assertRaises(exception.VolumeBackendAPIException,
7362                              self.common.get_rdf_details, self.data.array)
7363
7364    def test_failover_host(self):
7365        volumes = [self.data.test_volume, self.data.test_clone_volume]
7366        with mock.patch.object(self.common, '_failover_volume',
7367                               return_value={}) as mock_fo:
7368            self.common.failover_host(volumes)
7369            self.assertEqual(2, mock_fo.call_count)
7370
7371    def test_failover_host_exception(self):
7372        volumes = [self.data.test_volume, self.data.test_clone_volume]
7373        self.assertRaises(exception.VolumeBackendAPIException,
7374                          self.common.failover_host,
7375                          volumes, secondary_id="default")
7376
7377    @mock.patch.object(common.VMAXCommon, 'failover_replication',
7378                       return_value=({}, {}))
7379    @mock.patch.object(common.VMAXCommon, '_failover_volume',
7380                       return_value={})
7381    def test_failover_host_groups(self, mock_fv, mock_fg):
7382        volumes = [self.data.test_volume_group_member]
7383        group1 = self.data.test_group
7384        self.common.failover_host(volumes, None, [group1])
7385        mock_fv.assert_not_called()
7386        mock_fg.assert_called_once()
7387
7388    def test_failover_volume(self):
7389        ref_model_update = {
7390            'volume_id': self.data.test_volume.id,
7391            'updates':
7392                {'replication_status': fields.ReplicationStatus.FAILED_OVER,
7393                 'replication_driver_data': six.text_type(
7394                     self.data.provider_location),
7395                 'provider_location': six.text_type(
7396                     self.data.provider_location3)}}
7397        model_update = self.common._failover_volume(
7398            self.data.test_volume, True, self.extra_specs)
7399        self.assertEqual(ref_model_update, model_update)
7400        ref_model_update2 = {
7401            'volume_id': self.data.test_volume.id,
7402            'updates':
7403                {'replication_status': fields.ReplicationStatus.ENABLED,
7404                 'replication_driver_data': six.text_type(
7405                     self.data.provider_location),
7406                 'provider_location': six.text_type(
7407                     self.data.provider_location3)}}
7408        model_update2 = self.common._failover_volume(
7409            self.data.test_volume, False, self.extra_specs)
7410        self.assertEqual(ref_model_update2, model_update2)
7411
7412    def test_failover_legacy_volume(self):
7413        ref_model_update = {
7414            'volume_id': self.data.test_volume.id,
7415            'updates':
7416                {'replication_status': fields.ReplicationStatus.FAILED_OVER,
7417                 'replication_driver_data': six.text_type(
7418                     self.data.legacy_provider_location),
7419                 'provider_location': six.text_type(
7420                     self.data.legacy_provider_location2)}}
7421        model_update = self.common._failover_volume(
7422            self.data.test_legacy_vol, True, self.extra_specs)
7423        self.assertEqual(ref_model_update, model_update)
7424
7425    def test_failover_volume_exception(self):
7426        with mock.patch.object(
7427                self.provision, 'failover_volume',
7428                side_effect=exception.VolumeBackendAPIException):
7429            ref_model_update = {
7430                'volume_id': self.data.test_volume.id,
7431                'updates': {'replication_status':
7432                            fields.ReplicationStatus.FAILOVER_ERROR,
7433                            'replication_driver_data': six.text_type(
7434                                self.data.provider_location3),
7435                            'provider_location': six.text_type(
7436                                self.data.provider_location)}}
7437            model_update = self.common._failover_volume(
7438                self.data.test_volume, True, self.extra_specs)
7439            self.assertEqual(ref_model_update, model_update)
7440
7441    @mock.patch.object(
7442        common.VMAXCommon, '_find_device_on_array',
7443        side_effect=[None, VMAXCommonData.device_id,
7444                     VMAXCommonData.device_id, VMAXCommonData.device_id])
7445    @mock.patch.object(
7446        common.VMAXCommon, '_get_masking_views_from_volume',
7447        side_effect=['OS-host-MV', None, exception.VolumeBackendAPIException])
7448    def test_recover_volumes_on_failback(self, mock_mv, mock_dev):
7449        recovery1 = self.common.recover_volumes_on_failback(
7450            self.data.test_volume, self.extra_specs)
7451        self.assertEqual('error', recovery1['updates']['status'])
7452        recovery2 = self.common.recover_volumes_on_failback(
7453            self.data.test_volume, self.extra_specs)
7454        self.assertEqual('in-use', recovery2['updates']['status'])
7455        recovery3 = self.common.recover_volumes_on_failback(
7456            self.data.test_volume, self.extra_specs)
7457        self.assertEqual('available', recovery3['updates']['status'])
7458        recovery4 = self.common.recover_volumes_on_failback(
7459            self.data.test_volume, self.extra_specs)
7460        self.assertEqual('available', recovery4['updates']['status'])
7461
7462    def test_get_remote_target_device(self):
7463        target_device1, _, _, _, _ = (
7464            self.common.get_remote_target_device(
7465                self.data.array, self.data.test_volume, self.data.device_id))
7466        self.assertEqual(self.data.device_id2, target_device1)
7467        target_device2, _, _, _, _ = (
7468            self.common.get_remote_target_device(
7469                self.data.array, self.data.test_clone_volume,
7470                self.data.device_id))
7471        self.assertIsNone(target_device2)
7472        with mock.patch.object(self.rest, 'are_vols_rdf_paired',
7473                               return_value=(False, '')):
7474            target_device3, _, _, _, _ = (
7475                self.common.get_remote_target_device(
7476                    self.data.array, self.data.test_volume,
7477                    self.data.device_id))
7478            self.assertIsNone(target_device3)
7479        with mock.patch.object(self.rest, 'get_volume',
7480                               return_value=None):
7481            target_device4, _, _, _, _ = (
7482                self.common.get_remote_target_device(
7483                    self.data.array, self.data.test_volume,
7484                    self.data.device_id))
7485            self.assertIsNone(target_device4)
7486
7487    @mock.patch.object(common.VMAXCommon, 'setup_volume_replication')
7488    @mock.patch.object(provision.VMAXProvision, 'extend_volume')
7489    @mock.patch.object(provision.VMAXProvision, 'break_rdf_relationship')
7490    @mock.patch.object(masking.VMAXMasking, 'remove_and_reset_members')
7491    def test_extend_volume_is_replicated(self, mock_remove,
7492                                         mock_break, mock_extend, mock_setup):
7493        self.common.extend_volume_is_replicated(
7494            self.data.array, self.data.test_volume, self.data.device_id,
7495            'vol1', '5', self.data.extra_specs_rep_enabled)
7496        self.assertEqual(2, mock_remove.call_count)
7497        self.assertEqual(2, mock_extend.call_count)
7498        mock_remove.reset_mock()
7499        mock_extend.reset_mock()
7500        with mock.patch.object(self.rest, 'is_next_gen_array',
7501                               return_value=True):
7502            self.common.extend_volume_is_replicated(
7503                self.data.array, self.data.test_volume, self.data.device_id,
7504                'vol1', '5', self.data.extra_specs_rep_enabled)
7505            mock_remove.assert_not_called()
7506            self.assertEqual(2, mock_extend.call_count)
7507
7508    def test_extend_volume_is_replicated_exception(self):
7509        self.assertRaises(exception.VolumeBackendAPIException,
7510                          self.common.extend_volume_is_replicated,
7511                          self.data.failed_resource, self.data.test_volume,
7512                          self.data.device_id, 'vol1', '1',
7513                          self.data.extra_specs_rep_enabled)
7514        with mock.patch.object(self.utils, 'is_metro_device',
7515                               return_value=True):
7516            self.assertRaises(exception.VolumeBackendAPIException,
7517                              self.common.extend_volume_is_replicated,
7518                              self.data.array, self.data.test_volume,
7519                              self.data.device_id, 'vol1', '1',
7520                              self.data.extra_specs_rep_enabled)
7521
7522    @mock.patch.object(common.VMAXCommon, 'add_volume_to_replication_group')
7523    @mock.patch.object(masking.VMAXMasking, 'remove_and_reset_members')
7524    def test_enable_rdf(self, mock_remove, mock_add):
7525        rep_config = self.utils.get_replication_config(
7526            [self.replication_device])
7527        self.common.enable_rdf(
7528            self.data.array, self.data.test_volume, self.data.device_id,
7529            self.data.rdf_group_no, rep_config, 'OS-1',
7530            self.data.remote_array, self.data.device_id2, self.extra_specs)
7531        self.assertEqual(2, mock_remove.call_count)
7532        self.assertEqual(2, mock_add.call_count)
7533
7534    @mock.patch.object(masking.VMAXMasking, 'remove_vol_from_storage_group')
7535    @mock.patch.object(common.VMAXCommon, '_cleanup_remote_target')
7536    def test_enable_rdf_exception(self, mock_cleanup, mock_rm):
7537        rep_config = self.utils.get_replication_config(
7538            [self.replication_device])
7539        self.assertRaises(
7540            exception.VolumeBackendAPIException, self.common.enable_rdf,
7541            self.data.array, self.data.test_volume, self.data.device_id,
7542            self.data.failed_resource, rep_config, 'OS-1',
7543            self.data.remote_array, self.data.device_id2, self.extra_specs)
7544        self.assertEqual(1, mock_cleanup.call_count)
7545
7546    def test_add_volume_to_replication_group(self):
7547        sg_name = self.common.add_volume_to_replication_group(
7548            self.data.array, self.data.device_id, 'vol1',
7549            self.extra_specs)
7550        self.assertEqual(self.data.default_sg_re_enabled, sg_name)
7551
7552    @mock.patch.object(masking.VMAXMasking,
7553                       'get_or_create_default_storage_group',
7554                       side_effect=exception.VolumeBackendAPIException)
7555    def test_add_volume_to_replication_group_exception(self, mock_get):
7556        self.assertRaises(
7557            exception.VolumeBackendAPIException,
7558            self.common.add_volume_to_replication_group,
7559            self.data.array, self.data.device_id, 'vol1',
7560            self.extra_specs)
7561
7562    def test_get_replication_extra_specs(self):
7563        rep_config = self.utils.get_replication_config(
7564            [self.replication_device])
7565        # Path one - disable compression
7566        extra_specs1 = deepcopy(self.extra_specs)
7567        extra_specs1[utils.DISABLECOMPRESSION] = "true"
7568        ref_specs1 = deepcopy(self.data.rep_extra_specs2)
7569        rep_extra_specs1 = self.common._get_replication_extra_specs(
7570            extra_specs1, rep_config)
7571        self.assertEqual(ref_specs1, rep_extra_specs1)
7572        # Path two - disable compression, not all flash
7573        ref_specs2 = deepcopy(self.data.rep_extra_specs2)
7574        with mock.patch.object(self.rest, 'is_compression_capable',
7575                               return_value=False):
7576            rep_extra_specs2 = self.common._get_replication_extra_specs(
7577                extra_specs1, rep_config)
7578        self.assertEqual(ref_specs2, rep_extra_specs2)
7579        # Path three - slo not valid
7580        extra_specs3 = deepcopy(self.extra_specs)
7581        ref_specs3 = deepcopy(ref_specs1)
7582        ref_specs3['slo'] = None
7583        ref_specs3['workload'] = None
7584        with mock.patch.object(self.provision, 'verify_slo_workload',
7585                               return_value=(False, False)):
7586            rep_extra_specs3 = self.common._get_replication_extra_specs(
7587                extra_specs3, rep_config)
7588        self.assertEqual(ref_specs3, rep_extra_specs3)
7589
7590    def test_get_secondary_stats(self):
7591        rep_config = self.utils.get_replication_config(
7592            [self.replication_device])
7593        array_map = self.utils.parse_file_to_get_array_map(
7594            self.common.pool_info['config_file'])
7595        finalarrayinfolist = self.common._get_slo_workload_combinations(
7596            array_map)
7597        array_info = finalarrayinfolist[0]
7598        ref_info = deepcopy(array_info)
7599        ref_info['SerialNumber'] = six.text_type(rep_config['array'])
7600        ref_info['srpName'] = rep_config['srp']
7601        secondary_info = self.common.get_secondary_stats_info(
7602            rep_config, array_info)
7603        self.assertEqual(ref_info, secondary_info)
7604
7605    def test_replicate_group(self):
7606        volume_model_update = {
7607            'id': self.data.test_volume.id,
7608            'provider_location': self.data.test_volume.provider_location}
7609        vols_model_update = self.common._replicate_group(
7610            self.data.array, [volume_model_update],
7611            self.data.test_vol_grp_name, self.extra_specs)
7612        ref_rep_data = six.text_type({'array': self.data.remote_array,
7613                                      'device_id': self.data.device_id2})
7614        ref_vol_update = {
7615            'id': self.data.test_volume.id,
7616            'provider_location': self.data.test_volume.provider_location,
7617            'replication_driver_data': ref_rep_data,
7618            'replication_status': fields.ReplicationStatus.ENABLED}
7619        self.assertEqual(ref_vol_update, vols_model_update[0])
7620
7621    @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
7622                       return_value=False)
7623    @mock.patch.object(volume_utils, 'is_group_a_type', return_value=True)
7624    def test_create_replicaton_group(self, mock_type, mock_cg_type):
7625        ref_model_update = {
7626            'status': fields.GroupStatus.AVAILABLE,
7627            'replication_status': fields.ReplicationStatus.ENABLED}
7628        model_update = self.common.create_group(None, self.data.test_group_1)
7629        self.assertEqual(ref_model_update, model_update)
7630        # Replication mode is async
7631        self.assertRaises(exception.InvalidInput,
7632                          self.async_driver.common.create_group,
7633                          None, self.data.test_group_1)
7634
7635    def test_enable_replication(self):
7636        # Case 1: Group not replicated
7637        with mock.patch.object(volume_utils, 'is_group_a_type',
7638                               return_value=False):
7639            self.assertRaises(NotImplementedError,
7640                              self.common.enable_replication,
7641                              None, self.data.test_group,
7642                              [self.data.test_volume])
7643        with mock.patch.object(volume_utils, 'is_group_a_type',
7644                               return_value=True):
7645            # Case 2: Empty group
7646            model_update, __ = self.common.enable_replication(
7647                None, self.data.test_group, [])
7648            self.assertEqual({}, model_update)
7649            # Case 3: Successfully enabled
7650            model_update, __ = self.common.enable_replication(
7651                None, self.data.test_group, [self.data.test_volume])
7652            self.assertEqual(fields.ReplicationStatus.ENABLED,
7653                             model_update['replication_status'])
7654            # Case 4: Exception
7655            model_update, __ = self.common.enable_replication(
7656                None, self.data.test_group_failed, [self.data.test_volume])
7657            self.assertEqual(fields.ReplicationStatus.ERROR,
7658                             model_update['replication_status'])
7659
7660    def test_disable_replication(self):
7661        # Case 1: Group not replicated
7662        with mock.patch.object(volume_utils, 'is_group_a_type',
7663                               return_value=False):
7664            self.assertRaises(NotImplementedError,
7665                              self.common.disable_replication,
7666                              None, self.data.test_group,
7667                              [self.data.test_volume])
7668        with mock.patch.object(volume_utils, 'is_group_a_type',
7669                               return_value=True):
7670            # Case 2: Empty group
7671            model_update, __ = self.common.disable_replication(
7672                None, self.data.test_group, [])
7673            self.assertEqual({}, model_update)
7674            # Case 3: Successfully disabled
7675            model_update, __ = self.common.disable_replication(
7676                None, self.data.test_group, [self.data.test_volume])
7677            self.assertEqual(fields.ReplicationStatus.DISABLED,
7678                             model_update['replication_status'])
7679            # Case 4: Exception
7680            model_update, __ = self.common.disable_replication(
7681                None, self.data.test_group_failed, [self.data.test_volume])
7682            self.assertEqual(fields.ReplicationStatus.ERROR,
7683                             model_update['replication_status'])
7684
7685    def test_failover_replication(self):
7686        with mock.patch.object(volume_utils, 'is_group_a_type',
7687                               return_value=True):
7688            # Case 1: Empty group
7689            model_update, __ = self.common.failover_replication(
7690                None, self.data.test_group, [])
7691            self.assertEqual({}, model_update)
7692            # Case 2: Successfully failed over
7693            model_update, __ = self.common.failover_replication(
7694                None, self.data.test_group, [self.data.test_volume])
7695            self.assertEqual(fields.ReplicationStatus.FAILED_OVER,
7696                             model_update['replication_status'])
7697            # Case 3: Successfully failed back
7698            model_update, __ = self.common.failover_replication(
7699                None, self.data.test_group, [self.data.test_volume],
7700                secondary_backend_id='default')
7701            self.assertEqual(fields.ReplicationStatus.ENABLED,
7702                             model_update['replication_status'])
7703            # Case 4: Exception
7704            model_update, __ = self.common.failover_replication(
7705                None, self.data.test_group_failed, [self.data.test_volume])
7706            self.assertEqual(fields.ReplicationStatus.ERROR,
7707                             model_update['replication_status'])
7708
7709    @mock.patch.object(utils.VMAXUtils, 'get_volume_group_utils',
7710                       return_value=(VMAXCommonData.array, {}))
7711    @mock.patch.object(common.VMAXCommon, '_cleanup_group_replication')
7712    @mock.patch.object(volume_utils, 'is_group_a_type', return_value=True)
7713    def test_delete_replication_group(self, mock_check,
7714                                      mock_cleanup, mock_utils):
7715        self.common._delete_group(self.data.test_rep_group, [])
7716        mock_cleanup.assert_called_once()
7717
7718    @mock.patch.object(masking.VMAXMasking,
7719                       'remove_volumes_from_storage_group')
7720    @mock.patch.object(utils.VMAXUtils, 'check_rep_status_enabled')
7721    @mock.patch.object(common.VMAXCommon,
7722                       '_remove_remote_vols_from_volume_group')
7723    @mock.patch.object(common.VMAXCommon, '_add_remote_vols_to_volume_group')
7724    @mock.patch.object(volume_utils, 'is_group_a_type', return_value=True)
7725    @mock.patch.object(volume_utils, 'is_group_a_cg_snapshot_type',
7726                       return_value=True)
7727    def test_update_replicated_group(self, mock_cg_type, mock_type_check,
7728                                     mock_add, mock_remove, mock_check,
7729                                     mock_rm):
7730        add_vols = [self.data.test_volume]
7731        remove_vols = [self.data.test_clone_volume]
7732        self.common.update_group(
7733            self.data.test_group_1, add_vols, remove_vols)
7734        mock_add.assert_called_once()
7735        mock_remove.assert_called_once()
7736
7737    @mock.patch.object(masking.VMAXMasking,
7738                       'add_volumes_to_storage_group')
7739    def test_add_remote_vols_to_volume_group(self, mock_add):
7740        self.common._add_remote_vols_to_volume_group(
7741            self.data.remote_array, [self.data.test_volume],
7742            self.data.test_rep_group, self.data.rep_extra_specs)
7743        mock_add.assert_called_once()
7744
7745    @mock.patch.object(masking.VMAXMasking,
7746                       'remove_volumes_from_storage_group')
7747    def test_remove_remote_vols_from_volume_group(self, mock_rm):
7748        self.common._remove_remote_vols_from_volume_group(
7749            self.data.remote_array, [self.data.test_volume],
7750            self.data.test_rep_group, self.data.rep_extra_specs)
7751        mock_rm.assert_called_once()
7752
7753    @mock.patch.object(masking.VMAXMasking, 'remove_and_reset_members')
7754    @mock.patch.object(masking.VMAXMasking,
7755                       'remove_volumes_from_storage_group')
7756    def test_cleanup_group_replication(self, mock_rm, mock_rm_reset):
7757        self.common._cleanup_group_replication(
7758            self.data.array, self.data.test_vol_grp_name,
7759            [self.data.device_id], self.extra_specs)
7760        mock_rm.assert_called_once()
7761
7762    @mock.patch.object(masking.VMAXMasking, 'add_volume_to_storage_group')
7763    def test_add_volume_to_async_group(self, mock_add):
7764        extra_specs = deepcopy(self.extra_specs)
7765        extra_specs['rep_mode'] = utils.REP_ASYNC
7766        self.async_driver.common._add_volume_to_async_rdf_managed_grp(
7767            self.data.array, self.data.device_id, 'name',
7768            self.data.remote_array, self.data.device_id2, extra_specs)
7769        self.assertEqual(2, mock_add.call_count)
7770
7771    def test_add_volume_to_async_group_exception(self):
7772        extra_specs = deepcopy(self.extra_specs)
7773        extra_specs['rep_mode'] = utils.REP_ASYNC
7774        self.assertRaises(
7775            exception.VolumeBackendAPIException,
7776            self.async_driver.common._add_volume_to_async_rdf_managed_grp,
7777            self.data.failed_resource, self.data.device_id, 'name',
7778            self.data.remote_array, self.data.device_id2, extra_specs)
7779
7780    @mock.patch.object(common.VMAXCommon,
7781                       '_add_volume_to_async_rdf_managed_grp')
7782    @mock.patch.object(masking.VMAXMasking, 'remove_and_reset_members')
7783    def test_setup_volume_replication_async(self, mock_rm, mock_add):
7784        extra_specs = deepcopy(self.extra_specs)
7785        extra_specs['rep_mode'] = utils.REP_ASYNC
7786        rep_status, rep_data = (
7787            self.async_driver.common.setup_volume_replication(
7788                self.data.array, self.data.test_volume,
7789                self.data.device_id, extra_specs))
7790        self.assertEqual(fields.ReplicationStatus.ENABLED, rep_status)
7791        self.assertEqual({'array': self.data.remote_array,
7792                          'device_id': self.data.device_id}, rep_data)
7793        mock_add.assert_called_once()
7794
7795    @mock.patch.object(common.VMAXCommon, '_failover_replication',
7796                       return_value=({}, {}))
7797    @mock.patch.object(common.VMAXCommon, '_failover_volume',
7798                       return_value={})
7799    def test_failover_host_async(self, mock_fv, mock_fg):
7800        volumes = [self.data.test_volume]
7801        extra_specs = deepcopy(self.extra_specs)
7802        extra_specs['rep_mode'] = utils.REP_ASYNC
7803        with mock.patch.object(common.VMAXCommon, '_initial_setup',
7804                               return_value=extra_specs):
7805            self.async_driver.common.failover_host(volumes, None, [])
7806        mock_fv.assert_not_called()
7807        mock_fg.assert_called_once()
7808