From 5dab85a2a48efebcefe28f9d8c5d1d6233b2cada Mon Sep 17 00:00:00 2001 From: Anshul Jain Date: Tue, 13 Jun 2017 07:21:29 +0000 Subject: [PATCH] Redfish: Adds manager support for redfish API's. This commit enables the support for all redfish API's to make use of Manager features. This patch also includes a temporary hack for manager as 'manager_mock.py' file which needs to be removed once new Sushy version is released with manager feature. Added the 'utils' file containing the utility function, ``get_subresource_path_by``. Co-Authored-By: Aparna Vikraman Co-Authored-By: Debayan Ray Partial-Bug: 1691955 Change-Id: Iffec7e2e459455dba3b5bac817faa89341b4b9d3 --- proliantutils/redfish/main.py | 20 +- proliantutils/redfish/redfish.py | 28 ++- .../redfish/resources/manager/__init__.py | 0 .../redfish/resources/manager/manager.py | 25 +++ proliantutils/redfish/utils.py | 51 +++++ proliantutils/tests/__init__.py | 17 ++ .../tests/redfish/json_samples/manager.json | 196 ++++++++++++++++++ .../tests/redfish/json_samples/system.json | 2 +- proliantutils/tests/redfish/manager_mock.py | 39 ++++ .../tests/redfish/resources/test_system.py | 2 +- proliantutils/tests/redfish/test_main.py | 40 ++++ proliantutils/tests/redfish/test_redfish.py | 27 +-- proliantutils/tests/redfish/test_utils.py | 71 +++++++ 13 files changed, 493 insertions(+), 25 deletions(-) create mode 100644 proliantutils/redfish/resources/manager/__init__.py create mode 100644 proliantutils/redfish/resources/manager/manager.py create mode 100644 proliantutils/redfish/utils.py create mode 100644 proliantutils/tests/redfish/json_samples/manager.json create mode 100644 proliantutils/tests/redfish/manager_mock.py create mode 100644 proliantutils/tests/redfish/test_utils.py diff --git a/proliantutils/redfish/main.py b/proliantutils/redfish/main.py index b670345..992a649 100644 --- a/proliantutils/redfish/main.py +++ b/proliantutils/redfish/main.py @@ -14,9 +14,12 @@ __author__ = 'HPE' -from proliantutils.redfish.resources.system import system import sushy +from proliantutils.redfish.resources.manager import manager +from proliantutils.redfish.resources.system import system +from proliantutils.redfish import utils + class HPESushy(sushy.Sushy): """Class that extends base Sushy class @@ -25,6 +28,9 @@ class HPESushy(sushy.Sushy): required to customize the functionality of different resources """ + def get_system_collection_path(self): + return utils.get_subresource_path_by(self, 'Systems') + def get_system(self, identity): """Given the identity return a HPESystem object @@ -33,3 +39,15 @@ class HPESushy(sushy.Sushy): """ return system.HPESystem(self._conn, identity, redfish_version=self.redfish_version) + + def get_manager_collection_path(self): + return utils.get_subresource_path_by(self, 'Managers') + + def get_manager(self, identity): + """Given the identity return a HPEManager object + + :param identity: The identity of the Manager resource + :returns: The Manager object + """ + return manager.HPEManager(self._conn, identity, + redfish_version=self.redfish_version) diff --git a/proliantutils/redfish/redfish.py b/proliantutils/redfish/redfish.py index af7ce08..fdce653 100644 --- a/proliantutils/redfish/redfish.py +++ b/proliantutils/redfish/redfish.py @@ -103,14 +103,6 @@ class RedfishOperations(operations.IloOperations): LOG.debug(msg) raise exception.IloConnectionError(msg) - def _get_system_collection_path(self): - """Helper function to find the SystemCollection path""" - systems_col = self._sushy.json.get('Systems') - if not systems_col: - raise exception.MissingAttributeError(attribute='Systems', - resource=self._root_prefix) - return systems_col.get('@odata.id') - def _get_sushy_system(self, system_id): """Get the sushy system for system_id @@ -118,7 +110,7 @@ class RedfishOperations(operations.IloOperations): :returns: the Sushy system instance :raises: IloError """ - system_url = parse.urljoin(self._get_system_collection_path(), + system_url = parse.urljoin(self._sushy.get_system_collection_path(), system_id) try: return self._sushy.get_system(system_url) @@ -129,6 +121,24 @@ class RedfishOperations(operations.IloOperations): LOG.debug(msg) raise exception.IloError(msg) + def _get_sushy_manager(self, manager_id): + """Get the sushy Manager for manager_id + + :param manager_id: The identity of the Manager resource + :returns: the Sushy Manager instance + :raises: IloError + """ + manager_url = parse.urljoin(self._sushy.get_manager_collection_path(), + manager_id) + try: + return self._sushy.get_manager(manager_url) + except sushy.exceptions.SushyError as e: + msg = (self._('The Redfish Manager "%(manager)s" was not found. ' + 'Error %(error)s') % + {'manager': manager_id, 'error': str(e)}) + LOG.debug(msg) + raise exception.IloError(msg) + def get_product_name(self): """Gets the product name of the server. diff --git a/proliantutils/redfish/resources/manager/__init__.py b/proliantutils/redfish/resources/manager/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/proliantutils/redfish/resources/manager/manager.py b/proliantutils/redfish/resources/manager/manager.py new file mode 100644 index 0000000..94c6c61 --- /dev/null +++ b/proliantutils/redfish/resources/manager/manager.py @@ -0,0 +1,25 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# +# 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. + +__author__ = 'HPE' + +from sushy.resources.manager import manager + + +class HPEManager(manager.Manager): + """Class that extends the functionality of Manager resource class + + This class extends the functionality of Manager resource class + from sushy + """ diff --git a/proliantutils/redfish/utils.py b/proliantutils/redfish/utils.py new file mode 100644 index 0000000..cca88ea --- /dev/null +++ b/proliantutils/redfish/utils.py @@ -0,0 +1,51 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# +# 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. + +__author__ = 'HPE' + +import six + +from proliantutils import exception + + +def get_subresource_path_by(resource, subresource_path): + """Helper function to find the resource path + + :param resource: ResourceBase instance from which the path is loaded. + :param subresource_path: JSON field to fetch the value from. + Either a string, or a list of strings in case of a nested field. + It should also include the '@odata.id' + :raises: MissingAttributeError, if required path is missing. + :raises: ValueError, if path is empty. + :raises: AttributeError, if json attr not found in resource + """ + if isinstance(subresource_path, six.string_types): + subresource_path = [subresource_path] + elif not subresource_path: + raise ValueError('"subresource_path" cannot be empty') + + body = resource.json + for path_item in subresource_path: + body = body.get(path_item, {}) + + if not body: + raise exception.MissingAttributeError( + attribute='/'.join(subresource_path), resource=resource.path) + + if '@odata.id' not in body: + raise exception.MissingAttributeError( + attribute='/'.join(subresource_path)+'/@odata.id', + resource=resource.path) + + return body['@odata.id'] diff --git a/proliantutils/tests/__init__.py b/proliantutils/tests/__init__.py index e69de29..c83fcab 100644 --- a/proliantutils/tests/__init__.py +++ b/proliantutils/tests/__init__.py @@ -0,0 +1,17 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# 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. + +# TODO(deray): Need to remove this hack sooner +from proliantutils.tests.redfish import manager_mock # noqa diff --git a/proliantutils/tests/redfish/json_samples/manager.json b/proliantutils/tests/redfish/json_samples/manager.json new file mode 100644 index 0000000..1c51b50 --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/manager.json @@ -0,0 +1,196 @@ +{ + "@odata.context": "/redfish/v1/$metadata#Managers/Members/$entity", + "@odata.etag": "W/\"FD28A1E2\"", + "@odata.id": "/redfish/v1/Managers/1/", + "@odata.type": "#Manager.v1_1_0.Manager", + "Actions": { + "#Manager.Reset": { + "target": "/redfish/v1/Managers/1/Actions/Manager.Reset/" + } + }, + "CommandShell": { + "ConnectTypesSupported": [ + "SSH", + "Oem" + ], + "MaxConcurrentSessions": 9, + "ServiceEnabled": true + }, + "EthernetInterfaces": { + "@odata.id": "/redfish/v1/Managers/1/EthernetInterfaces/" + }, + "FirmwareVersion": "iLO 5 v1.15", + "GraphicalConsole": { + "ConnectTypesSupported": [ + "KVMIP" + ], + "MaxConcurrentSessions": 10, + "ServiceEnabled": true + }, + "Id": "1", + "Links": { + "ManagerForChassis": [ + { + "@odata.id": "/redfish/v1/Chassis/1/" + } + ], + "ManagerForServers": [ + { + "@odata.id": "/redfish/v1/Systems/1/" + } + ], + "ManagerInChassis": { + "@odata.id": "/redfish/v1/Chassis/1/" + } + }, + "LogServices": { + "@odata.id": "/redfish/v1/Managers/1/LogServices/" + }, + "ManagerType": "BMC", + "Name": "Manager", + "NetworkProtocol": { + "@odata.id": "/redfish/v1/Managers/1/NetworkService/" + }, + "Oem": { + "Hpe": { + "@odata.type": "#HpeiLO.v2_1_0.HpeiLO", + "Actions": { + "#HpeiLO.ClearRestApiState": { + "target": "/redfish/v1/Managers/1/Actions/Oem/Hpe/HpeiLO.ClearRestApiState/" + }, + "#HpeiLO.DisableiLOFunctionality": { + "target": "/redfish/v1/Managers/1/Actions/Oem/Hpe/HpeiLO.DisableiLOFunctionality/" + }, + "#HpeiLO.ResetToFactoryDefaults": { + "ResetType@Redfish.AllowableValues": [ + "Default" + ], + "target": "/redfish/v1/Managers/1/Actions/Oem/Hpe/HpeiLO.ResetToFactoryDefaults/" + } + }, + "ClearRestApiStatus": "DataPresent", + "ConfigurationSettings": "Current", + "FederationConfig": { + "IPv6MulticastScope": "Site", + "MulticastAnnouncementInterval": 600, + "MulticastDiscovery": "Enabled", + "MulticastTimeToLive": 5, + "iLOFederationManagement": "Enabled" + }, + "Firmware": { + "Current": { + "Date": "Jun 05 2017", + "DebugBuild": false, + "MajorVersion": 1, + "MinorVersion": 15, + "VersionString": "iLO 5 v1.15" + } + }, + "FrontPanelUSB": { + "State": "Ready" + }, + "IdleConnectionTimeoutMinutes": 30, + "License": { + "LicenseKey": "XXXXX-XXXXX-XXXXX-XXXXX-456N6", + "LicenseString": "iLO Advanced limited-distribution test", + "LicenseType": "Internal" + }, + "Links": { + "ActiveHealthSystem": { + "@odata.id": "/redfish/v1/Managers/1/ActiveHealthSystem/" + }, + "DateTimeService": { + "@odata.id": "/redfish/v1/Managers/1/DateTime/" + }, + "EmbeddedMediaService": { + "@odata.id": "/redfish/v1/Managers/1/EmbeddedMedia/" + }, + "FederationDispatch": { + "extref": "/dispatch" + }, + "FederationGroups": { + "@odata.id": "/redfish/v1/Managers/1/FederationGroups/" + }, + "FederationPeers": { + "@odata.id": "/redfish/v1/Managers/1/FederationPeers/" + }, + "LicenseService": { + "@odata.id": "/redfish/v1/Managers/1/LicenseService/" + }, + "SecurityService": { + "@odata.id": "/redfish/v1/Managers/1/SecurityService/" + }, + "Thumbnail": { + "extref": "/images/thumbnail.bmp" + }, + "VSPLogLocation": { + "extref": "/sol.log.gz" + } + }, + "PersistentMouseKeyboardEnabled": false, + "RIBCLEnabled": true, + "RequiredLoginForiLORBSU": false, + "SerialCLISpeed": 9600, + "SerialCLIStatus": "EnabledAuthReq", + "VSPDlLoggingEnabled": false, + "VSPLogDownloadEnabled": false, + "WebGuiEnabled": true, + "iLOFunctionalityRequired": false, + "iLORBSUEnabled": true, + "iLOSelfTestResults": [ + { + "Notes": "", + "SelfTestName": "NVRAMData", + "Status": "OK" + }, + { + "Notes": "Controller firmware revision 2.10.00 ", + "SelfTestName": "EmbeddedFlash", + "Status": "OK" + }, + { + "Notes": "", + "SelfTestName": "HostRom", + "Status": "OK" + }, + { + "Notes": "", + "SelfTestName": "SupportedHost", + "Status": "OK" + }, + { + "Notes": "Version 1.0.2", + "SelfTestName": "PowerManagementController", + "Status": "Informational" + }, + { + "Notes": "ProLiant DL180 Gen10 System Programmable Logic Device 0x07", + "SelfTestName": "CPLDPAL0", + "Status": "Informational" + } + ], + "iLOServicePort": { + "MassStorageAuthenticationRequired": false, + "USBEthernetAdaptersEnabled": true, + "USBFlashDriveEnabled": true, + "iLOServicePortEnabled": true + } + } + }, + "SerialConsole": { + "ConnectTypesSupported": [ + "SSH", + "IPMI", + "Oem" + ], + "MaxConcurrentSessions": 13, + "ServiceEnabled": true + }, + "Status": { + "State": "Enabled" + }, + "UUID": null, + "VirtualMedia": { + "@odata.id": "/redfish/v1/Managers/1/VirtualMedia/" + } +} diff --git a/proliantutils/tests/redfish/json_samples/system.json b/proliantutils/tests/redfish/json_samples/system.json index c59ab1c..6ff5fef 100644 --- a/proliantutils/tests/redfish/json_samples/system.json +++ b/proliantutils/tests/redfish/json_samples/system.json @@ -1,5 +1,5 @@ { - "Default": { + "default": { "@odata.context": "/redfish/v1/$metadata#Systems/Members/$entity", "@odata.etag": "W/\"0E79655D\"", "@odata.id": "/redfish/v1/Systems/1/", diff --git a/proliantutils/tests/redfish/manager_mock.py b/proliantutils/tests/redfish/manager_mock.py new file mode 100644 index 0000000..e884a33 --- /dev/null +++ b/proliantutils/tests/redfish/manager_mock.py @@ -0,0 +1,39 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# 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. + +# TODO(deray): Need to remove this hack sooner + +import sys + +import mock +from oslo_utils import importutils +import six + + +SUSHY_MANAGER_PACKAGE_SPEC = ('manager',) + +sushy = importutils.try_import('sushy') +if sushy: + sushy_resources_manager = mock.MagicMock( + spec_set=SUSHY_MANAGER_PACKAGE_SPEC) + sys.modules['sushy.resources.manager'] = sushy_resources_manager + sushy.resources.common = mock.MagicMock() + sushy_resources_manager.manager.Manager = type( + 'Manager', (sushy.resources.base.ResourceBase,), {}) + sushy.resources.common.ResetActionField = type( + 'ResetActionField', (sushy.resources.base.CompositeField,), + {"target_uri": sushy.resources.base.Field('target', required=True)}) + if 'proliantutils.redfish' in sys.modules: + six.moves.reload_module(sys.modules['proliantutils.redfish']) diff --git a/proliantutils/tests/redfish/resources/test_system.py b/proliantutils/tests/redfish/resources/test_system.py index fba8c7b..e2d1d13 100644 --- a/proliantutils/tests/redfish/resources/test_system.py +++ b/proliantutils/tests/redfish/resources/test_system.py @@ -31,7 +31,7 @@ class HPESystemTestCase(testtools.TestCase): with open('proliantutils/tests/redfish/' 'json_samples/system.json', 'r') as f: system_json = json.loads(f.read()) - self.conn.get.return_value.json.return_value = system_json['Default'] + self.conn.get.return_value.json.return_value = system_json['default'] self.sys_inst = system.HPESystem( self.conn, '/redfish/v1/Systems/1', diff --git a/proliantutils/tests/redfish/test_main.py b/proliantutils/tests/redfish/test_main.py index 779d2a5..2172191 100644 --- a/proliantutils/tests/redfish/test_main.py +++ b/proliantutils/tests/redfish/test_main.py @@ -13,11 +13,15 @@ # License for the specific language governing permissions and limitations # under the License. +import json + import mock from sushy import connector import testtools +from proliantutils import exception from proliantutils.redfish import main +from proliantutils.redfish.resources.manager import manager from proliantutils.redfish.resources.system import system @@ -26,10 +30,26 @@ class HPESushyTestCase(testtools.TestCase): @mock.patch.object(connector, 'Connector', autospec=True) def setUp(self, connector_mock): super(HPESushyTestCase, self).setUp() + with open('proliantutils/tests/redfish/' + 'json_samples/root.json', 'r') as f: + root_json = json.loads(f.read()) + connector_mock.return_value.get.return_value.json.return_value = ( + root_json) self.hpe_sushy = main.HPESushy('https://1.2.3.4', username='foo', password='bar') + def test_get_system_collection_path(self): + self.assertEqual('/redfish/v1/Systems/', + self.hpe_sushy.get_system_collection_path()) + + def test_get_system_collection_path_missing_systems_attr(self): + self.hpe_sushy.json.pop('Systems') + self.assertRaisesRegex( + exception.MissingAttributeError, + 'The attribute Systems is missing', + self.hpe_sushy.get_system_collection_path) + @mock.patch.object(system, 'HPESystem', autospec=True) def test_get_system(self, mock_system): sys_inst = self.hpe_sushy.get_system('1234') @@ -38,3 +58,23 @@ class HPESushyTestCase(testtools.TestCase): mock_system.assert_called_once_with(self.hpe_sushy._conn, '1234', self.hpe_sushy.redfish_version) + + def test_get_manager_collection_path(self): + self.assertEqual('/redfish/v1/Managers/', + self.hpe_sushy.get_manager_collection_path()) + + def test_get_manager_collection_path_missing_systems_attr(self): + self.hpe_sushy.json.pop('Managers') + self.assertRaisesRegex( + exception.MissingAttributeError, + 'The attribute Managers is missing', + self.hpe_sushy.get_manager_collection_path) + + @mock.patch.object(manager, 'HPEManager', autospec=True) + def test_get_manager(self, mock_manager): + sys_inst = self.hpe_sushy.get_manager('1234') + self.assertTrue(isinstance(sys_inst, + manager.HPEManager.__class__)) + mock_manager.assert_called_once_with(self.hpe_sushy._conn, + '1234', + self.hpe_sushy.redfish_version) diff --git a/proliantutils/tests/redfish/test_redfish.py b/proliantutils/tests/redfish/test_redfish.py index 9f7ec59..bd649d4 100644 --- a/proliantutils/tests/redfish/test_redfish.py +++ b/proliantutils/tests/redfish/test_redfish.py @@ -32,6 +32,10 @@ class RedfishOperationsTestCase(testtools.TestCase): def setUp(self, sushy_mock): super(RedfishOperationsTestCase, self).setUp() self.sushy = mock.MagicMock() + self.sushy.get_system_collection_path.return_value = ( + '/redfish/v1/Systems') + self.sushy.get_manager_collection_path.return_value = ( + '/redfish/v1/Managers') sushy_mock.return_value = self.sushy with open('proliantutils/tests/redfish/' 'json_samples/root.json', 'r') as f: @@ -51,17 +55,6 @@ class RedfishOperationsTestCase(testtools.TestCase): redfish.RedfishOperations, '1.2.3.4', username='foo', password='bar') - def test__get_system_collection_path(self): - self.assertEqual('/redfish/v1/Systems/', - self.rf_client._get_system_collection_path()) - - def test__get_system_collection_path_missing_systems_attr(self): - self.rf_client._sushy.json.pop('Systems') - self.assertRaisesRegex( - exception.MissingAttributeError, - 'The attribute Systems is missing', - self.rf_client._get_system_collection_path) - def test__get_sushy_system_fail(self): self.rf_client._sushy.get_system.side_effect = ( sushy.exceptions.SushyError) @@ -70,11 +63,19 @@ class RedfishOperationsTestCase(testtools.TestCase): 'The Redfish System "apple" was not found.', self.rf_client._get_sushy_system, 'apple') + def test__get_sushy_manager_fail(self): + self.rf_client._sushy.get_manager.side_effect = ( + sushy.exceptions.SushyError) + self.assertRaisesRegex( + exception.IloError, + 'The Redfish Manager "banana" was not found.', + self.rf_client._get_sushy_manager, 'banana') + def test_get_product_name(self): with open('proliantutils/tests/redfish/' 'json_samples/system.json', 'r') as f: system_json = json.loads(f.read()) - self.sushy.get_system().json = system_json['Default'] + self.sushy.get_system().json = system_json['default'] product_name = self.rf_client.get_product_name() self.assertEqual('ProLiant DL180 Gen10', product_name) @@ -156,7 +157,7 @@ class RedfishOperationsTestCase(testtools.TestCase): with open('proliantutils/tests/redfish/' 'json_samples/system.json', 'r') as f: system_json = json.loads(f.read()) - self.sushy.get_system().json = system_json['Default'] + self.sushy.get_system().json = system_json['default'] boot = self.rf_client.get_one_time_boot() self.assertEqual('Normal', boot) diff --git a/proliantutils/tests/redfish/test_utils.py b/proliantutils/tests/redfish/test_utils.py new file mode 100644 index 0000000..584ee52 --- /dev/null +++ b/proliantutils/tests/redfish/test_utils.py @@ -0,0 +1,71 @@ +# Copyright 2016 Hewlett Packard Enterprise Company, L.P. +# 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. + +"""Test class for Utils Module.""" + +import json + +import ddt +import mock +import testtools + +from proliantutils import exception +from proliantutils.redfish.resources.system import system +from proliantutils.redfish import utils + + +@ddt.ddt +class UtilsTestCase(testtools.TestCase): + + def setUp(self): + super(UtilsTestCase, self).setUp() + self.conn = mock.MagicMock() + with open('proliantutils/tests/redfish/' + 'json_samples/system.json', 'r') as f: + system_json = json.loads(f.read()) + self.conn.get.return_value.json.return_value = system_json['default'] + + self.sys_inst = system.HPESystem(self.conn, '/redfish/v1/Systems/1', + redfish_version='1.0.2') + + @ddt.data(('SecureBoot', '/redfish/v1/Systems/1/SecureBoot/'), + (['Oem', 'Hpe', 'Links', 'NetworkAdapters'], + '/redfish/v1/Systems/1/NetworkAdapters/'), + ) + @ddt.unpack + def test_get_subresource_path_by(self, subresource_path, expected_result): + value = utils.get_subresource_path_by(self.sys_inst, + subresource_path) + self.assertEqual(expected_result, value) + + @ddt.data(('NonSecureBoot', 'attribute NonSecureBoot is missing'), + (['Links', 'Chassis'], + 'attribute Links/Chassis/@odata.id is missing'), + ) + @ddt.unpack + def test_get_subresource_path_by_when_fails( + self, subresource_path, expected_exception_string_subset): + self.assertRaisesRegex( + exception.MissingAttributeError, + expected_exception_string_subset, + utils.get_subresource_path_by, + self.sys_inst, subresource_path) + + def test_get_subresource_path_by_fails_with_empty_path(self): + self.assertRaisesRegex( + ValueError, + '"subresource_path" cannot be empty', + utils.get_subresource_path_by, + self.sys_inst, [])