diff --git a/rsd_lib/resources/v2_4/__init__.py b/rsd_lib/resources/v2_4/__init__.py index f9d556d..68475db 100644 --- a/rsd_lib/resources/v2_4/__init__.py +++ b/rsd_lib/resources/v2_4/__init__.py @@ -14,10 +14,28 @@ # under the License. from rsd_lib.resources import v2_3 +from rsd_lib.resources.v2_4.storage_service import storage_service class RSDLibV2_4(v2_3.RSDLibV2_3): - # TODO(lin.yang): Inherit 2.3 module for RSD 2.4 dummy module, - # should add 2.4 new functionalities into this module. - pass + def get_storage_service_collection(self): + """Get the StorageServiceCollection object + + :raises: MissingAttributeError, if the collection attribute is + not found + :returns: a StorageServiceCollection object + """ + return storage_service.StorageServiceCollection( + self._conn, self._storage_service_path, + redfish_version=self.redfish_version) + + def get_storage_service(self, identity): + """Given the identity return a StorageService object + + :param identity: The identity of the StorageService resource + :returns: The StorageService object + """ + return storage_service.StorageService( + self._conn, identity, + redfish_version=self.redfish_version) diff --git a/rsd_lib/resources/v2_4/storage_service/__init__.py b/rsd_lib/resources/v2_4/storage_service/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rsd_lib/resources/v2_4/storage_service/storage_service.py b/rsd_lib/resources/v2_4/storage_service/storage_service.py new file mode 100644 index 0000000..4bafd5d --- /dev/null +++ b/rsd_lib/resources/v2_4/storage_service/storage_service.py @@ -0,0 +1,54 @@ +# Copyright 2018 Intel, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from sushy.resources import base +from sushy import utils + +from rsd_lib.resources.v2_3.storage_service import storage_service +from rsd_lib.resources.v2_4.storage_service import volume + + +class StorageService(storage_service.StorageService): + + @property + @utils.cache_it + def volumes(self): + """Property to provide reference to `VolumeCollection` instance + + It is calculated once when it is queried for the first time. On + refresh, this property is reset. + """ + return volume.VolumeCollection( + self._conn, self._get_volume_collection_path(), + redfish_version=self.redfish_version) + + +class StorageServiceCollection(base.ResourceCollectionBase): + + @property + def _resource_type(self): + return StorageService + + def __init__(self, connector, path, redfish_version=None): + """A class representing a StorageServiceCollection + + :param connector: A Connector instance + :param path: The canonical path to the StorageService collection + resource + :param redfish_version: The version of RedFish. Used to construct + the object according to schema of the given version. + """ + super(StorageServiceCollection, self).__init__(connector, path, + redfish_version) diff --git a/rsd_lib/resources/v2_4/storage_service/volume.py b/rsd_lib/resources/v2_4/storage_service/volume.py new file mode 100644 index 0000000..515a91f --- /dev/null +++ b/rsd_lib/resources/v2_4/storage_service/volume.py @@ -0,0 +1,58 @@ +# Copyright 2018 Intel, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from sushy import exceptions +from sushy.resources import base + +from rsd_lib.resources.v2_3.storage_service import volume + + +class Volume(volume.Volume): + + def resize(self, num_bytes): + """Update volume properties + + :param num_bytes: size in bytes of new resized volume + """ + if not isinstance(num_bytes, int): + raise exceptions.InvalidParameterValueError( + parameter='num_bytes', value=num_bytes, + valid_values='integer') + + if self.capacity_bytes and num_bytes <= self.capacity_bytes: + raise exceptions.InvalidParameterValueError( + parameter='num_bytes', value=num_bytes, + valid_values='> {0}'.format(self.capacity_bytes)) + + data = {"Capacity": {"Data": {'AllocatedBytes': num_bytes}}} + self._conn.patch(self.path, data=data) + + +class VolumeCollection(base.ResourceCollectionBase): + + @property + def _resource_type(self): + return Volume + + def __init__(self, connector, path, redfish_version=None): + """A class representing a VolumeCollection + + :param connector: A Connector instance + :param path: The canonical path to the Volume collection resource + :param redfish_version: The version of RedFish. Used to construct + the object according to schema of the given version. + """ + super(VolumeCollection, self).__init__(connector, path, + redfish_version) diff --git a/rsd_lib/tests/unit/json_samples/v2_4/storage_service.json b/rsd_lib/tests/unit/json_samples/v2_4/storage_service.json new file mode 100644 index 0000000..be4eb5e --- /dev/null +++ b/rsd_lib/tests/unit/json_samples/v2_4/storage_service.json @@ -0,0 +1,41 @@ +{ + "@odata.context": "/redfish/v1/$metadata#StorageService.StorageService", + "@odata.id": "/redfish/v1/StorageServices/NVMeoE1", + "@odata.type": "#StorageService.v1_0_0.StorageService", + "Id": "NVMeoE1", + "Name": "Storage Service", + "Description": "Storage Service description", + "Drives": { + "@odata.id": "/redfish/v1/StorageServices/NVMeoE1/Drives" + }, + "Endpoints": { + "@odata.id": "/redfish/v1/Fabrics/1/Endpoints" + }, + "Links": { + "HostingSystem": { + "@odata.id": "/redfish/v1/Systems/Target" + }, + "Oem": { + "Intel_RackScale": { + "@odata.type": "#Intel.Oem.StorageServicesLinks", + "ManagedBy": [ + { + "@odata.id": "/redfish/v1/Managers/1" + } + ] + } + } + }, + "Oem": {}, + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Enabled" + }, + "StoragePools": { + "@odata.id": "/redfish/v1/StorageServices/1/StoragePools" + }, + "Volumes": { + "@odata.id": "/redfish/v1/StorageServices/1/Volumes" + } +} \ No newline at end of file diff --git a/rsd_lib/tests/unit/json_samples/v2_4/storage_service_collection.json b/rsd_lib/tests/unit/json_samples/v2_4/storage_service_collection.json new file mode 100644 index 0000000..0bd0eb1 --- /dev/null +++ b/rsd_lib/tests/unit/json_samples/v2_4/storage_service_collection.json @@ -0,0 +1,11 @@ +{ + "@odata.context": "/redfish/v1/$metadata#StorageService.StorageService", + "@odata.id": "/redfish/v1/StorageServices", + "@odata.type": "#StorageServiceCollection.StorageServiceCollection", + "Name": "Storage Services Collection", + "Description": "Storage Service Collection", + "Members@odata.count": 1, + "Members": [ + { "@odata.id": "/redfish/v1/StorageServices/NVMeoE1" } + ] +} \ No newline at end of file diff --git a/rsd_lib/tests/unit/json_samples/v2_4/volume.json b/rsd_lib/tests/unit/json_samples/v2_4/volume.json new file mode 100644 index 0000000..7d580ac --- /dev/null +++ b/rsd_lib/tests/unit/json_samples/v2_4/volume.json @@ -0,0 +1,90 @@ +{ + "@odata.context": "/redfish/v1/$metadata#Volume.Volume", + "@odata.id": "/redfish/v1/StorageServices/NVMeoE1/Volumes/1", + "@odata.type": "#Volume.v1_1_0.Volume", + "Description": "Volume description", + "Id": "1", + "Model": null, + "Manufacturer": null, + "Name": "NVMe remote storage", + "AccessCapabilities": [ + "Read", + "Write" + ], + "CapacityBytes": 3071983104, + "Actions": { + "#Volume.Initialize": { + "target": + "/redfish/v1/StorageServices/NVMeoE1/Volumes/1/Actions/Volume.Initialize" + }, + "Oem": {} + }, + "Capacity": { + "Data": { + "AllocatedBytes": 3071983104 + } + }, + "CapacitySources": [ + { + "ProvidingPools": [ + { + "@odata.id": "/redfish/v1/StorageServices/1/StoragePools/2" + } + ], + "ProvidedCapacity": { + "Data": { + "AllocatedBytes": 3071983104 + } + } + } + ], + "Identifiers": [ + { + "DurableName": "/dev/nvme1n1p1", + "DurableNameFormat": "SystemPath" + }, + { + "DurableName": "iqn.2001-04.com.example:diskarrays-sn-a8675309", + "DurableNameFormat": "iQN" + } + ], + "Links": { + "Oem": { + "Intel_RackScale": { + "@odata.type": "#Intel.Oem.VolumeLinks", + "Endpoints": [ + { + "@odata.id": "/redfish/v1/Fabrics/NVMeoE/Endpoints/1" + } + ], + "Metrics": { + "@odata.id": "/redfish/v1/StorageServices/NVMeoE1/Volumes/1/Metrics" + } + } + }, + "Drives": [] + }, + "ReplicaInfos": [ + { + "ReplicaReadOnlyAccess": "SourceElement", + "ReplicaType": "Snapshot", + "ReplicaRole": "Target", + "Replica": { + "@odata.id": "/redfish/v1/StorageServices/NVMeoE1/Volumes/2" + } + } + ], + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Enabled" + }, + "Oem": { + "Intel_RackScale": { + "@odata.type": "#Intel.Oem.Volume", + "Bootable": false, + "Erased": null, + "EraseOnDetach": true + } + } +} \ No newline at end of file diff --git a/rsd_lib/tests/unit/json_samples/v2_4/volume_collection.json b/rsd_lib/tests/unit/json_samples/v2_4/volume_collection.json new file mode 100644 index 0000000..e9bcd38 --- /dev/null +++ b/rsd_lib/tests/unit/json_samples/v2_4/volume_collection.json @@ -0,0 +1,13 @@ +{ + "@odata.context": "/redfish/v1/$metadata#VolumeCollection.VolumeCollection", + "@odata.id": "/redfish/v1/StorageServices/1/Volumes", + "@odata.type": "#VolumeCollection.VolumeCollection", + "Description": "Volume Collection", + "Members": [ + { + "@odata.id": "/redfish/v1/StorageServices/NVMeoE1/Volumes/1" + } + ], + "Members@odata.count": 1, + "Name": "Volume Collection" +} \ No newline at end of file diff --git a/rsd_lib/tests/unit/resources/v2_4/storage_service/__init__.py b/rsd_lib/tests/unit/resources/v2_4/storage_service/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rsd_lib/tests/unit/resources/v2_4/storage_service/test_storage_service.py b/rsd_lib/tests/unit/resources/v2_4/storage_service/test_storage_service.py new file mode 100644 index 0000000..01d333c --- /dev/null +++ b/rsd_lib/tests/unit/resources/v2_4/storage_service/test_storage_service.py @@ -0,0 +1,144 @@ +# Copyright 2018 Intel, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json +import mock +import testtools + +from sushy import exceptions + +from rsd_lib.resources.v2_4.storage_service import storage_service +from rsd_lib.resources.v2_4.storage_service import volume + + +class StorageServiceTestCase(testtools.TestCase): + + def setUp(self): + super(StorageServiceTestCase, self).setUp() + self.conn = mock.Mock() + with open('rsd_lib/tests/unit/json_samples/v2_4/storage_service.json', + 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + + self.storage_service_inst = storage_service.StorageService( + self.conn, '/redfish/v1/StorageServices/NVMeoE1', + redfish_version='1.0.2') + + def test__parse_attributes(self): + self.storage_service_inst._parse_attributes() + self.assertEqual('1.0.2', self.storage_service_inst.redfish_version) + self.assertEqual('Storage Service description', + self.storage_service_inst.description) + self.assertEqual('NVMeoE1', self.storage_service_inst.identity) + self.assertEqual('Storage Service', self.storage_service_inst.name) + self.assertEqual('Enabled', self.storage_service_inst.status.state) + self.assertEqual('OK', self.storage_service_inst.status.health) + self.assertEqual('OK', self.storage_service_inst.status.health_rollup) + + def test__get_volume_collection_path(self): + expected = '/redfish/v1/StorageServices/1/Volumes' + result = self.storage_service_inst._get_volume_collection_path() + self.assertEqual(expected, result) + + def test__get_volume_collection_path_missing_processors_attr(self): + self.storage_service_inst._json.pop('Volumes') + self.assertRaisesRegex( + exceptions.MissingAttributeError, 'attribute Volumes', + self.storage_service_inst._get_volume_collection_path) + + def test_volumes(self): + # | GIVEN | + self.conn.get.return_value.json.reset_mock() + with open('rsd_lib/tests/unit/json_samples/v2_4/' + 'volume_collection.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + # | WHEN | + actual_volumes = self.storage_service_inst.volumes + # | THEN | + self.assertIsInstance(actual_volumes, + volume.VolumeCollection) + self.conn.get.return_value.json.assert_called_once_with() + + # reset mock + self.conn.get.return_value.json.reset_mock() + # | WHEN & THEN | + # tests for same object on invoking subsequently + self.assertIs(actual_volumes, + self.storage_service_inst.volumes) + self.conn.get.return_value.json.assert_not_called() + + def test_volumes_on_refresh(self): + # | GIVEN | + with open('rsd_lib/tests/unit/json_samples/v2_4/' + 'volume_collection.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + # | WHEN & THEN | + self.assertIsInstance(self.storage_service_inst.volumes, + volume.VolumeCollection) + + # On refreshing the storage service instance... + with open('rsd_lib/tests/unit/json_samples/v2_4/' + 'storage_service.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + + self.storage_service_inst.invalidate() + self.storage_service_inst.refresh(force=False) + + # | GIVEN | + with open('rsd_lib/tests/unit/json_samples/v2_4/' + 'volume_collection.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + # | WHEN & THEN | + self.assertIsInstance(self.storage_service_inst.volumes, + volume.VolumeCollection) + + +class StorageServiceCollectionTestCase(testtools.TestCase): + + def setUp(self): + super(StorageServiceCollectionTestCase, self).setUp() + self.conn = mock.Mock() + with open('rsd_lib/tests/unit/json_samples/v2_4/' + 'storage_service_collection.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + self.storage_service_col = storage_service.StorageServiceCollection( + self.conn, '/redfish/v1/StorageServices', redfish_version='1.0.2') + + def test__parse_attributes(self): + self.storage_service_col._parse_attributes() + self.assertEqual('1.0.2', self.storage_service_col.redfish_version) + self.assertEqual('Storage Services Collection', + self.storage_service_col.name) + self.assertEqual(('/redfish/v1/StorageServices/NVMeoE1',), + self.storage_service_col.members_identities) + + @mock.patch.object(storage_service, 'StorageService', autospec=True) + def test_get_member(self, mock_storage_service): + self.storage_service_col.get_member( + '/redfish/v1/StorageServices/NVMeoE1') + mock_storage_service.assert_called_once_with( + self.storage_service_col._conn, + '/redfish/v1/StorageServices/NVMeoE1', + redfish_version=self.storage_service_col.redfish_version) + + @mock.patch.object(storage_service, 'StorageService', autospec=True) + def test_get_members(self, mock_storage_service): + members = self.storage_service_col.get_members() + mock_storage_service.assert_called_once_with( + self.storage_service_col._conn, + '/redfish/v1/StorageServices/NVMeoE1', + redfish_version=self.storage_service_col.redfish_version) + self.assertIsInstance(members, list) + self.assertEqual(1, len(members)) diff --git a/rsd_lib/tests/unit/resources/v2_4/storage_service/test_volume.py b/rsd_lib/tests/unit/resources/v2_4/storage_service/test_volume.py new file mode 100644 index 0000000..7930452 --- /dev/null +++ b/rsd_lib/tests/unit/resources/v2_4/storage_service/test_volume.py @@ -0,0 +1,143 @@ +# Copyright 2018 Intel, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json +import mock +import testtools + +from sushy import exceptions + +from rsd_lib.resources.v2_4.storage_service import volume + + +class StorageServiceTestCase(testtools.TestCase): + + def setUp(self): + super(StorageServiceTestCase, self).setUp() + self.conn = mock.Mock() + with open('rsd_lib/tests/unit/json_samples/v2_3/volume.json', + 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + + self.volume_inst = volume.Volume( + self.conn, '/redfish/v1/StorageServices/NVMeoE1/Volumes/1', + redfish_version='1.0.2') + + def test__parse_attributes(self): + self.volume_inst._parse_attributes() + self.assertEqual('1.0.2', self.volume_inst.redfish_version) + self.assertEqual('Volume description', self.volume_inst.description) + self.assertEqual('1', self.volume_inst.identity) + self.assertEqual('NVMe remote storage', self.volume_inst.name) + self.assertEqual('Enabled', self.volume_inst.status.state) + self.assertEqual('OK', self.volume_inst.status.health) + self.assertEqual('OK', self.volume_inst.status.health_rollup) + self.assertIsNone(self.volume_inst.model) + self.assertIsNone(self.volume_inst.manufacturer) + self.assertEqual(['Read', 'Write'], + self.volume_inst.access_capabilities) + self.assertEqual(3071983104, self.volume_inst.capacity_bytes) + self.assertEqual(3071983104, self.volume_inst.allocated_Bytes) + self.assertEqual(('/redfish/v1/StorageServices/1/StoragePools/2',), + self.volume_inst.capacity_sources[0].providing_pools) + self.assertEqual(3071983104, + self.volume_inst.capacity_sources[0].allocated_Bytes) + self.assertEqual( + '/dev/nvme1n1p1', + self.volume_inst.identifiers[0].durable_name) + self.assertEqual( + 'SystemPath', + self.volume_inst.identifiers[0].durable_name_format) + self.assertEqual( + 'iqn.2001-04.com.example:diskarrays-sn-a8675309', + self.volume_inst.identifiers[1].durable_name) + self.assertEqual( + 'iQN', + self.volume_inst.identifiers[1].durable_name_format) + self.assertEqual(('/redfish/v1/Fabrics/NVMeoE/Endpoints/1',), + self.volume_inst.links.endpoints) + self.assertEqual( + '/redfish/v1/StorageServices/NVMeoE1/Volumes/1/Metrics', + self.volume_inst.links.metrics) + self.assertEqual( + 'SourceElement', + self.volume_inst.replica_infos[0].replica_readonly_access) + self.assertEqual('Snapshot', + self.volume_inst.replica_infos[0].replica_type) + self.assertEqual('Target', + self.volume_inst.replica_infos[0].replica_role) + self.assertEqual('/redfish/v1/StorageServices/NVMeoE1/Volumes/2', + self.volume_inst.replica_infos[0].replica) + self.assertEqual(False, self.volume_inst.bootable) + self.assertIsNone(self.volume_inst.erased) + self.assertEqual(True, self.volume_inst.erase_on_detach) + + def test_resize_volume(self): + self.volume_inst.resize(3071983105) + self.volume_inst._conn.patch.assert_called_once_with( + '/redfish/v1/StorageServices/NVMeoE1/Volumes/1', + data={"Capacity": {"Data": {'AllocatedBytes': 3071983105}}}) + + def test_update_volume_with_invalid_parameter(self): + with self.assertRaisesRegex( + exceptions.InvalidParameterValueError, + 'The parameter "num_bytes" value "fake-value" is invalid'): + self.volume_inst.resize('fake-value') + + with self.assertRaisesRegex( + exceptions.InvalidParameterValueError, + 'The parameter "num_bytes" value "1024" is invalid'): + self.volume_inst.resize(1024) + + +class VolumeCollectionTestCase(testtools.TestCase): + + def setUp(self): + super(VolumeCollectionTestCase, self).setUp() + self.conn = mock.Mock() + with open('rsd_lib/tests/unit/json_samples/v2_4/' + 'volume_collection.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + + self.volume_col = volume.VolumeCollection( + self.conn, '/redfish/v1/StorageServices/NVMeoE1/Volumes', + redfish_version='1.0.2') + + def test__parse_attributes(self): + self.volume_col._parse_attributes() + self.assertEqual('1.0.2', self.volume_col.redfish_version) + self.assertEqual('Volume Collection', + self.volume_col.name) + self.assertEqual(('/redfish/v1/StorageServices/NVMeoE1/Volumes/1',), + self.volume_col.members_identities) + + @mock.patch.object(volume, 'Volume', autospec=True) + def test_get_member(self, mock_volume): + self.volume_col.get_member( + '/redfish/v1/StorageServices/NVMeoE1/Volumes/1') + mock_volume.assert_called_once_with( + self.volume_col._conn, + '/redfish/v1/StorageServices/NVMeoE1/Volumes/1', + redfish_version=self.volume_col.redfish_version) + + @mock.patch.object(volume, 'Volume', autospec=True) + def test_get_members(self, mock_volume): + members = self.volume_col.get_members() + mock_volume.assert_called_once_with( + self.volume_col._conn, + '/redfish/v1/StorageServices/NVMeoE1/Volumes/1', + redfish_version=self.volume_col.redfish_version) + self.assertIsInstance(members, list) + self.assertEqual(1, len(members)) diff --git a/rsd_lib/tests/unit/resources/v2_4/test_rsdlib_v2_4.py b/rsd_lib/tests/unit/resources/v2_4/test_rsdlib_v2_4.py index b4112ef..ac07380 100644 --- a/rsd_lib/tests/unit/resources/v2_4/test_rsdlib_v2_4.py +++ b/rsd_lib/tests/unit/resources/v2_4/test_rsdlib_v2_4.py @@ -24,9 +24,9 @@ from rsd_lib.resources.v2_3.ethernet_switch import ethernet_switch \ as v2_3_ethernet_switch from rsd_lib.resources.v2_3.fabric import fabric as v2_3_fabric from rsd_lib.resources.v2_3.node import node as v2_3_node -from rsd_lib.resources.v2_3.storage_service import storage_service \ - as v2_3_storage_service from rsd_lib.resources import v2_4 +from rsd_lib.resources.v2_4.storage_service import storage_service \ + as v2_4_storage_service class RSDLibV2_3TestCase(testtools.TestCase): @@ -106,7 +106,7 @@ class RSDLibV2_3TestCase(testtools.TestCase): self.rsd._conn, 'fake-chassis-id', redfish_version=self.rsd.redfish_version) - @mock.patch.object(v2_3_storage_service, 'StorageServiceCollection', + @mock.patch.object(v2_4_storage_service, 'StorageServiceCollection', autospec=True) def test_get_storage_service_collection(self, mock_storage_service_collection): @@ -115,7 +115,7 @@ class RSDLibV2_3TestCase(testtools.TestCase): self.rsd._conn, '/redfish/v1/StorageServices', redfish_version=self.rsd.redfish_version) - @mock.patch.object(v2_3_storage_service, 'StorageService', autospec=True) + @mock.patch.object(v2_4_storage_service, 'StorageService', autospec=True) def test_get_storage_service(self, mock_storage_service): self.rsd.get_storage_service('fake-storage-service-id') mock_storage_service.assert_called_once_with(