From 7fbbfc310220b326a28126e39f973472611f54e6 Mon Sep 17 00:00:00 2001 From: xuweibj Date: Fri, 25 Jan 2019 11:23:10 +0800 Subject: [PATCH] UT cases of functions in redfish_client for redfish python (#5939) * UT cases of login for redfish python and the fixing for found issues --- .../lib/python/agent/hwctl/redfish_client.py | 32 +- .../lib/python/agent/tests/__init__.py | 0 .../lib/python/agent/tests/unit/__init__.py | 0 .../tests/unit/json_data/bmc_action_rsp.json | 19 + .../tests/unit/json_data/chassis_rsp.json | 45 +++ .../unit/json_data/login_no_auth_rsp.json | 18 + .../agent/tests/unit/json_data/login_rsp.json | 10 + .../tests/unit/json_data/manager_rsp.json | 93 +++++ .../tests/unit/json_data/redfish_v1_rsp.json | 42 +++ .../tests/unit/json_data/systems_rsp.json | 86 +++++ .../tests/unit/json_data/with_error_rsp.json | 15 + .../agent/tests/unit/test_hwctl/__init__.py | 0 .../unit/test_hwctl/test_redfish_client.py | 355 ++++++++++++++++++ 13 files changed, 699 insertions(+), 16 deletions(-) create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/__init__.py create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/__init__.py create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/bmc_action_rsp.json create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/chassis_rsp.json create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/login_no_auth_rsp.json create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/login_rsp.json create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/manager_rsp.json create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/redfish_v1_rsp.json create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/systems_rsp.json create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/with_error_rsp.json create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/test_hwctl/__init__.py create mode 100644 xCAT-openbmc-py/lib/python/agent/tests/unit/test_hwctl/test_redfish_client.py diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/redfish_client.py b/xCAT-openbmc-py/lib/python/agent/hwctl/redfish_client.py index 53a35afe1..db9152309 100644 --- a/xCAT-openbmc-py/lib/python/agent/hwctl/redfish_client.py +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/redfish_client.py @@ -32,10 +32,6 @@ POWER_RESET_TYPE = { 'on' : 'ForceOn', } -manager_reset_string = '#Manager.Reset' -system_reset_string = '#ComputerSystem.Reset' -reset_type_string = 'ResetType@Redfish.AllowableValues' - BOOTSOURCE_SET_STATE = { "cd" : "Cd", "def" : "None", @@ -55,6 +51,10 @@ BOOTSOURCE_GET_STATE = { "Pxe" : "Network", } +manager_reset_string = '#Manager.Reset' +system_reset_string = '#ComputerSystem.Reset' +reset_type_string = 'ResetType@Redfish.AllowableValues' + class RedfishRest(object): headers = {'Content-Type': 'application/json'} @@ -101,7 +101,7 @@ class RedfishRest(object): if data: if cmd == 'login': data = data.replace('"Password": "%s"' % self.password, '"Password": "xxxxxx"') - data = '-d \'%s\'' % data + data = '-d \'%s\'' % data msg += '%s %s -v' % (url, data) else: msg += url @@ -170,7 +170,7 @@ class RedfishRest(object): try: return data['Members'] except KeyError as e: - raise SelfServerException('Get KeyError %s' % e.message) + raise SelfServerException('Get KeyError %s' % e.args) def get_bmc_state(self): @@ -180,7 +180,7 @@ class RedfishRest(object): try: return data['PowerState'] except KeyError as e: - raise SelfServerException('Get KeyError %s' % e.message) + raise SelfServerException('Get KeyError %s' % e.args) def get_chassis_power_state(self): @@ -190,7 +190,7 @@ class RedfishRest(object): try: return data['PowerState'] except KeyError as e: - raise SelfServerException('Get KeyError %s' % e.message) + raise SelfServerException('Get KeyError %s' % e.args) def get_systems_power_state(self): @@ -200,7 +200,7 @@ class RedfishRest(object): try: return data['PowerState'] except KeyError as e: - raise SelfServerException('Get KeyError %s' % e.message) + raise SelfServerException('Get KeyError %s' % e.args) def _get_bmc_actions(self): @@ -211,7 +211,7 @@ class RedfishRest(object): actions = data['Actions'][manager_reset_string][reset_type_string] target_url = data['Actions'][manager_reset_string]['target'] except KeyError as e: - raise SelfServerException('Get KeyError %s' % e.message) + raise SelfServerException('Get KeyError %s' % e.args) return (target_url, actions) @@ -219,7 +219,7 @@ class RedfishRest(object): target_url, actions = self._get_bmc_actions() if BMC_RESET_TYPE not in actions: - raise SelfClientException('Unsupported option: %s' % BMC_RESET_TYPE) + raise SelfClientException('Unsupported option: %s' % BMC_RESET_TYPE, 403) data = { "ResetType": BMC_RESET_TYPE } return self.request('POST', target_url, payload=data, cmd='set_bmc_state') @@ -233,7 +233,7 @@ class RedfishRest(object): actions = data['Actions'][system_reset_string][reset_type_string] target_url = data['Actions'][system_reset_string]['target'] except KeyError as e: - raise SelfServerException('Get KeyError %s' % e.message) + raise SelfServerException('Get KeyError %s' % e.args) return (target_url, actions) @@ -241,7 +241,7 @@ class RedfishRest(object): target_url, actions = self._get_power_actions() if POWER_RESET_TYPE[state] not in actions: - raise SelfClientException('Unsupported option: %s' % state) + raise SelfClientException('Unsupported option: %s' % state, 403) data = { "ResetType": POWER_RESET_TYPE[state] } return self.request('POST', target_url, payload=data, cmd='set_power_state') @@ -258,7 +258,7 @@ class RedfishRest(object): bootsource = data['Boot']['BootSourceOverrideTarget'] return BOOTSOURCE_GET_STATE.get(bootsource, bootsource) except KeyError as e: - raise SelfServerException('Get KeyError %s' % e.message) + raise SelfServerException('Get KeyError %s' % e.args) def _get_boot_actions(self): @@ -268,7 +268,7 @@ class RedfishRest(object): try: actions = data['Boot']['BootSourceOverrideTarget@Redfish.AllowableValues'] except KeyError as e: - raise SelfServerException('Get KeyError %s' % e.message) + raise SelfServerException('Get KeyError %s' % e.args) return (target_url, actions) @@ -277,7 +277,7 @@ class RedfishRest(object): target_url, actions = self._get_boot_actions() target_data = BOOTSOURCE_SET_STATE[state] if target_data not in actions: - raise SelfClientException('Unsupported option: %s' % state) + raise SelfClientException('Unsupported option: %s' % state, 403) boot_enable = 'Once' if persistant: diff --git a/xCAT-openbmc-py/lib/python/agent/tests/__init__.py b/xCAT-openbmc-py/lib/python/agent/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/__init__.py b/xCAT-openbmc-py/lib/python/agent/tests/unit/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/bmc_action_rsp.json b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/bmc_action_rsp.json new file mode 100644 index 000000000..32739dada --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/bmc_action_rsp.json @@ -0,0 +1,19 @@ +{ + "@odata.context": "/redfish/v1/$metadata#ActionInfo.ActionInfo", + "@odata.type": "#ActionInfo.v1_1_0.ActionInfo", + "@odata.id": "/redfish/v1/Managers/BMC/ResetActionInfo", + "Id": "ResetActionInfo", + "Name": "Reset Action Info", + "Parameters": [ + { + "Name": "ResetType", + "Required": true, + "DataType": "String", + "AllowableValues": [ + "ForceRestart", + "GracefulRestart" + ] + } + ], + "Oem": {} +} diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/chassis_rsp.json b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/chassis_rsp.json new file mode 100644 index 000000000..0538f74f1 --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/chassis_rsp.json @@ -0,0 +1,45 @@ +{ + "@odata.context": "/redfish/v1/$metadata#Chassis.Chassis", + "@odata.type": "#Chassis.v1_8_0.Chassis", + "@odata.id": "/redfish/v1/Chassis/Chassis0", + "Id": "Chassis0", + "Name": "OpenPOWER System Chassis", + "ChassisType": "RackMount", + "Manufacturer": "IBM", + "Model": "SYSTEM", + "SerialNumber": "C829UAE15A10564", + "PartNumber": "9006-22P", + "AssetTag": "", + "PowerState": "On", + "IndicatorLED": "Off", + "Status": { + "State": "Enabled", + "Health": "OK" + }, + "PhysicalSecurity": { + "IntrusionSensorNumber": 226, + "IntrusionSensor": "HardwareIntrusion", + "IntrusionSensorReArm": "Manual" + }, + "Thermal": { + "@odata.id": "/redfish/v1/Chassis/Chassis0/Thermal" + }, + "Power": { + "@odata.id": "/redfish/v1/Chassis/Chassis0/Power" + }, + "Assembly": { + "@odata.id": "/redfish/v1/Chassis/Chassis0/Assembly" + }, + "Links": { + "ComputerSystems": [ + { + "@odata.id": "/redfish/v1/Systems/Computer" + } + ], + "ManagedBy": [ + { + "@odata.id": "/redfish/v1/Managers/BMC" + } + ] + } +} diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/login_no_auth_rsp.json b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/login_no_auth_rsp.json new file mode 100644 index 000000000..d87bf2998 --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/login_no_auth_rsp.json @@ -0,0 +1,18 @@ +{ + "error": { + "code": "Base.1.4.0.GeneralError", + "message": "A general error has occurred. See Resolution for information on how to resolve the error.", + "@Message.ExtendedInfo": [ + { + "MessageId": "Base.1.4.0.ResourceAtUriUnauthorized", + "Severity": "Critical", + "Resolution": "Ensure that the appropriate access is provided for the service in order for it to access the URI.", + "Message": "While accessing the resource at /redfish/v1/SessionService/Sessions, the service received an authorization error unauthorized.", + "MessageArgs": [ + "/redfish/v1/SessionService/Sessions", + "unauthorized" + ] + } + ] + } +} diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/login_rsp.json b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/login_rsp.json new file mode 100644 index 000000000..2edae3953 --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/login_rsp.json @@ -0,0 +1,10 @@ +{ + "@odata.type": "#Session.v1_1_1.Session", + "UserName": "ADMIN", + "Description": "Manager User Session", + "@odata.id": "/redfish/v1/SessionService/Sessions/a6cbc1e29e9cd559", + "@odata.context": "/redfish/v1/$metadata#Session.Session", + "Oem": {}, + "Id": "a6cbc1e29e9cd559", + "Name": "User Session" +} diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/manager_rsp.json b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/manager_rsp.json new file mode 100644 index 000000000..1a03cc082 --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/manager_rsp.json @@ -0,0 +1,93 @@ +{ + "@odata.context": "/redfish/v1/$metadata#Manager.Manager", + "@odata.type": "#Manager.v1_5_0.Manager", + "@odata.id": "/redfish/v1/Managers/BMC", + "Id": "BMC", + "Description": "Aspeed BMC", + "Name": "Manager", + "ManagerType": "BMC", + "UUID": "00000000-0000-0000-0000-000000000", + "Model": "P9DSU 9006-22P", + "DateTime": "2019-01-22T06:22:55+00:00", + "DateTimeLocalOffset": "+00:00", + "FirmwareVersion": "2.04", + "Status": { + "State": "Enabled", + "Health": "OK" + }, + "PowerState": "On", + "SerialConsole": { + "ServiceEnabled": true, + "MaxConcurrentSessions": 1, + "ConnectTypesSupported": [ + "IPMI" + ] + }, + "CommandShell": { + "ServiceEnabled": true, + "MaxConcurrentSessions": 0, + "ConnectTypesSupported": [ + "SSH" + ] + }, + "GraphicalConsole": { + "ServiceEnabled": true, + "MaxConcurrentSessions": 4, + "ConnectTypesSupported": [ + "KVMIP" + ] + }, + "EthernetInterfaces": { + "@odata.id": "/redfish/v1/Managers/BMC/EthernetInterfaces" + }, + "SerialInterfaces": { + "@odata.id": "/redfish/v1/Managers/BMC/SerialInterfaces" + }, + "NetworkProtocol": { + "@odata.id": "/redfish/v1/Managers/BMC/NetworkProtocol" + }, + "LogServices": { + "@odata.id": "/redfish/v1/Managers/BMC/LogServices" + }, + "VirtualMedia": { + "@odata.id": "/redfish/v1/Managers/BMC/VirtualMedia" + }, + "Links": { + "ManagerForServers": [ + { + "@odata.id": "/redfish/v1/Systems/Computer" + } + ], + "ManagerForChassis": [ + { + "@odata.id": "/redfish/v1/Chassis/Chassis0" + } + ], + "ManagerInChassis": { + "@odata.id": "/redfish/v1/Chassis/Chassis0" + } + }, + "Actions": { + "#Manager.Reset": { + "target": "/redfish/v1/Managers/BMC/Actions/Manager.Reset", + "ResetType@Redfish.AllowableValues": [ + "ForceRestart", + "GracefulRestart" + ] + } + }, + "Oem": { + "Supermicro": { + "@odata.type": "#SMCManager.v1_0_1.SMCManager", + "FanMode": { + "@odata.id": "/redfish/v1/Managers/BMC/Oem/Supermicro/FanMode" + }, + "MouseMode": { + "@odata.id": "/redfish/v1/Managers/BMC/Oem/Supermicro/MouseMode" + }, + "SMTP": { + "@odata.id": "/redfish/v1/Managers/BMC/Oem/Supermicro/SMTP" + } + } + } +} diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/redfish_v1_rsp.json b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/redfish_v1_rsp.json new file mode 100644 index 000000000..3f6e2f0ca --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/redfish_v1_rsp.json @@ -0,0 +1,42 @@ +{ + "@odata.context": "/redfish/v1/$metadata#ServiceRoot.ServiceRoot", + "@odata.type": "#ServiceRoot.v1_4_0.ServiceRoot", + "@odata.id": "/redfish/v1", + "Id": "v1", + "Name": "Root Service", + "RedfishVersion": "1.6.0", + "UUID": "00000000-0000-0000-0000-0CC47AD55B4E", + "SessionService": { + "@odata.id": "/redfish/v1/SessionService" + }, + "AccountService": { + "@odata.id": "/redfish/v1/AccountService" + }, + "Registries": { + "@odata.id": "/redfish/v1/Registries" + }, + "JsonSchemas": { + "@odata.id": "/redfish/v1/JsonSchemas" + }, + "Chassis": { + "@odata.id": "/redfish/v1/Chassis" + }, + "Managers": { + "@odata.id": "/redfish/v1/Managers" + }, + "Systems": { + "@odata.id": "/redfish/v1/Systems" + }, + "UpdateService": { + "@odata.id": "/redfish/v1/UpdateService" + }, + "EventService": { + "@odata.id": "/redfish/v1/EventService" + }, + "Links": { + "Sessions": { + "@odata.id": "/redfish/v1/SessionService/Sessions" + } + }, + "Oem": {} +} diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/systems_rsp.json b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/systems_rsp.json new file mode 100644 index 000000000..caee86e6b --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/systems_rsp.json @@ -0,0 +1,86 @@ +{ + "@odata.context": "/redfish/v1/$metadata#ComputerSystem.ComputerSystem", + "@odata.type": "#ComputerSystem.v1_5_0.ComputerSystem", + "@odata.id": "/redfish/v1/Systems/Computer", + "Id": "Computer", + "Name": "OpenPOWER Computer System", + "Description": "OpenPOWER Computer System", + "Status": { + "State": "Enabled", + "Health": "Critical" + }, + "SerialNumber": "C829UAE15A10564", + "PartNumber": "9006-22P", + "Manufacturer": "IBM", + "Model": "SYSTEM", + "SystemType": "Physical", + "BiosVersion": "2.04 20190118", + "UUID": "00000000-0000-0000-0000-0000000000", + "ProcessorSummary": { + "Count": 2, + "Model": "POWER CPU", + "Status": { + "State": "Enabled", + "Health": "OK" + } + }, + "IndicatorLED": "Off", + "PowerState": "On", + "Boot": { + "BootSourceOverrideMode": "Legacy", + "BootSourceOverrideEnabled": "Once", + "BootSourceOverrideTarget": "None", + "BootSourceOverrideTarget@Redfish.AllowableValues": [ + "None", + "Pxe", + "Hdd", + "Diags", + "Cd", + "BiosSetup", + "Usb", + "Floppy" + ] + }, + "HostWatchdogTimer": { + "FunctionEnabled": true, + "WarningAction": "None", + "WarningAction@Redfish.AllowableValues": [ + "None" + ], + "TimeoutAction": "None", + "TimeoutAction@Redfish.AllowableValues": [ + "None", + "ResetSystem", + "PowerDown", + "PowerCycle" + ], + "Status": { + "State": "StandbyOffline" + } + }, + "Links": { + "Chassis": [ + { + "@odata.id": "/redfish/v1/Chassis/chassis0" + } + ], + "ManagedBy": [ + { + "@odata.id": "/redfish/v1/Managers/BMC" + } + ] + }, + "Actions": { + "#ComputerSystem.Reset": { + "target": "/redfish/v1/Systems/Computer/Actions/ComputerSystem.Reset", + "ResetType@Redfish.AllowableValues": [ + "On", + "ForceOff", + "GracefulShutdown", + "GracefulRestart", + "ForceRestart", + "ForceOn" + ] + } + } +} diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/with_error_rsp.json b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/with_error_rsp.json new file mode 100644 index 000000000..e88ecd915 --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/tests/unit/json_data/with_error_rsp.json @@ -0,0 +1,15 @@ +{ + "@odata.context":"/redfish/v1/$metadata#ChassisCollection.ChassisCollection", + "@odata.type":"#ChassisCollection.ChassisCollection", + "@odata.id":"/redfish/v1/Chassis", + "error":{ + "Message": "Chassis Collection" + }, + "Description":"Chassis Collection", + "Members":[ + { + "@odata.id":"/redfish/v1/Chassis/Planar" + } + ], + "Members@odata.count":1 +} diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/test_hwctl/__init__.py b/xCAT-openbmc-py/lib/python/agent/tests/unit/test_hwctl/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/xCAT-openbmc-py/lib/python/agent/tests/unit/test_hwctl/test_redfish_client.py b/xCAT-openbmc-py/lib/python/agent/tests/unit/test_hwctl/test_redfish_client.py new file mode 100644 index 000000000..bc98e66de --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/tests/unit/test_hwctl/test_redfish_client.py @@ -0,0 +1,355 @@ +#!/usr/bin/env python +############################################################################### +# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html +############################################################################### +# -*- coding: utf-8 -*- +# + +import pytest +import mock +import json +import os +import logging +import time +import requests + +from hwctl import redfish_client as rf +from common.utils import Messager +from common.exceptions import SelfClientException, SelfServerException + +DATA_DIR = os.path.dirname(os.path.realpath(__file__)) + '/../json_data' +logging.basicConfig(level=logging.DEBUG) +REDFISH_URL = '/redfish/v1' + +class TestRedfishClient(object): + + nodeinfo_dict = {'bmc': 'testbmc', 'bmcip': '10.0.0.1', 'username': 'username', 'password': 'password'} + log = logging.getLogger('TestRedfishClient') + rf_rest = rf.RedfishRest(name='testnode', nodeinfo=nodeinfo_dict, messager=Messager(), + debugmode=True, verbose=False) + headers = {'Content-Type': 'application/json'} + with open("%s/redfish_v1_rsp.json" % DATA_DIR,'r') as load_f: + rf_v1 = json.load(load_f) + chassis_url = rf_v1['Chassis']['@odata.id'] + manager_url = rf_v1['Managers']['@odata.id'] + systems_url = rf_v1['Systems']['@odata.id'] + session_url = rf_v1['Links']['Sessions']['@odata.id'] + + def test__init__(self): + assert self.rf_rest.name == 'testnode' + assert self.rf_rest.bmc == 'testbmc' + assert self.rf_rest.bmcip == '10.0.0.1' + assert self.rf_rest.username == 'username' + assert self.rf_rest.password == 'password' + assert isinstance(self.rf_rest.messager, Messager) + assert self.rf_rest.verbose == True + assert self.rf_rest.root_url == 'https://10.0.0.1' + + def test__print_record_log(self): + self.rf_rest._print_record_log("test__print_record_log", "test") + assert self.rf_rest.messager.info + assert time.asctime + + def test__print_error_log(self): + self.rf_rest._print_record_log("test__print_error_log", "test") + assert self.rf_rest._print_record_log + + def test__log_request(self): + self.rf_rest._print_record_log = mock.Mock(return_value=True) + login_data = json.dumps({ "UserName": self.rf_rest.username, "Password": self.rf_rest.password }) + msg_data = login_data.replace('"Password": "%s"' % self.rf_rest.password, '"Password": "xxxxxx"') + test_data = json.dumps({ "Test": True }) + login_msg = 'curl -k -X POST -H "Content-Type: application/json" https://10.0.0.1%s -d \'%s\' -v' % (self.session_url, msg_data) + test_data_msg = 'curl -k -X POST -H "Content-Type: application/json" -H "X-Auth-Token: xxxxxx" https://10.0.0.1/redfish/v1/Managers -d \'%s\' -v' % test_data + get_msg = 'curl -k -X GET -H "Content-Type: application/json" -H "X-Auth-Token: xxxxxx" https://10.0.0.1/redfish/v1/Managers' + assert self.rf_rest._log_request('POST', self.rf_rest.root_url + self.session_url, self.headers, data=login_data, cmd='login') == login_msg + assert self.rf_rest._log_request('POST', self.rf_rest.root_url + self.manager_url, self.headers, data=test_data, cmd='test__log_request') == test_data_msg + assert self.rf_rest._log_request('GET', self.rf_rest.root_url + self.manager_url, self.headers, cmd='test__log_request') == get_msg + + def test_handle_response_not_ok(self): + test_rsp = requests.Response() + test_rsp.status_code = 401 + with open("%s/login_no_auth_rsp.json" % DATA_DIR,'r') as load_f: + test_rsp._content = json.dumps(json.load(load_f)) + with pytest.raises(SelfClientException) as excinfo: + data = self.rf_rest.handle_response(test_rsp, cmd='test_handle_response_not_ok') + assert excinfo.type == SelfClientException + assert 'the service received an authorization error unauthorized' in str(excinfo.value) + + def test_handle_response_no_auth(self): + test_rsp = requests.Response() + test_rsp.status_code = 201 + test_rsp.headers = {} + with open("%s/login_rsp.json" % DATA_DIR,'r') as load_f: + test_rsp._content = json.dumps(json.load(load_f)) + with pytest.raises(SelfServerException) as excinfo: + data = self.rf_rest.handle_response(test_rsp, cmd='login') + assert excinfo.type == SelfServerException + assert 'Login Failed: Did not get Session Token from response' in str(excinfo.value) + + def test_handle_response_name(self): + test_rsp = requests.Response() + test_rsp.status_code = 200 + test_rsp.headers = {'X-Auth-Token': 'abcdefghijklmn'} + with open("%s/login_rsp.json" % DATA_DIR,'r') as load_f: + file_data = json.load(load_f) + test_rsp._content = json.dumps(file_data) + data = self.rf_rest.handle_response(test_rsp, cmd='get_information') + assert data == file_data + + def test_handle_response_error(self): + test_rsp = requests.Response() + test_rsp.status_code = 200 + test_rsp.headers = {'X-Auth-Token': 'abcdefghijklmn'} + with open("%s/with_error_rsp.json" % DATA_DIR,'r') as load_f: + file_data = json.load(load_f) + test_rsp._content = json.dumps(file_data) + data = self.rf_rest.handle_response(test_rsp, cmd='get_information') + assert data == file_data + + def test_request_login_connect_failed(self): + login_data = { "UserName": self.rf_rest.username, "Password": self.rf_rest.password } + self.rf_rest.session.request = mock.Mock(side_effect=SelfServerException('Login to BMC failed: Can\'t connect to')) + with pytest.raises(SelfServerException) as excinfo: + self.rf_rest.request('POST', self.session_url, headers=self.headers, payload=login_data, cmd='login') + assert excinfo.type == SelfServerException + assert 'Login to BMC failed: Can\'t connect to' in str(excinfo.value) + + def test_request_connect_failed(self): + self.rf_rest.session.request = mock.Mock(side_effect=SelfServerException('BMC did not respond. Validate BMC configuration and retry the command.')) + with pytest.raises(SelfServerException) as excinfo: + self.rf_rest.request('GET', self.manager_url, headers=self.headers) + assert excinfo.type == SelfServerException + assert 'BMC did not respond. Validate BMC configuration and retry the command.' in str(excinfo.value) + + def test_request_value_error(self): + self.rf_rest.session.request = mock.Mock(return_value='Mock return value for value error') + self.rf_rest.handle_response = mock.Mock(side_effect=ValueError()) + with pytest.raises(SelfServerException) as excinfo: + self.rf_rest.request('GET', self.manager_url, headers=self.headers) + assert excinfo.type == SelfServerException + assert 'Received wrong format response:' in str(excinfo.value) + + def test_request_login_success(self): + login_data = json.dumps({ "UserName": self.rf_rest.username, "Password": self.rf_rest.password }) + with open("%s/login_rsp.json" % DATA_DIR,'r') as load_f: + response = json.load(load_f) + self.rf_rest.session.request = mock.Mock(return_value=None) + self.rf_rest.handle_response = mock.Mock(return_value=response) + data = self.rf_rest.request('POST', self.session_url, headers=self.headers, payload=login_data, cmd='login') + assert self.rf_rest.session.request + assert data == response + + def test_login_success(self): + with open("%s/login_rsp.json" % DATA_DIR,'r') as load_f: + login_rsp = json.load(load_f) + self.rf_rest.request = mock.Mock(return_value=login_rsp) + assert self.rf_rest.login() == None + + def test_login_not_respond(self): + self.rf_rest.request = mock.Mock(side_effect=SelfServerException('BMC did not respond. Validate BMC configuration and retry the command.')) + with pytest.raises(SelfServerException) as excinfo: + self.rf_rest.login() + assert excinfo.type == SelfServerException + assert 'BMC did not respond. Validate BMC configuration and retry the command.' in str(excinfo.value) + + def test_login_value_error(self): + self.rf_rest.request = mock.Mock(side_effect=SelfServerException('Received wrong format response: xxxxxx')) + with pytest.raises(SelfServerException) as excinfo: + self.rf_rest.login() + assert excinfo.type == SelfServerException + assert 'Received wrong format response:' in str(excinfo.value) + + def test__get_members(self): + resp_data = {"Members": [ {"@odata.id": self.manager_url + "/BMC"} ] } + self.rf_rest.request = mock.Mock(return_value=resp_data) + members = self.rf_rest._get_members(self.manager_url) + assert members == [ {"@odata.id": self.manager_url + "/BMC"} ] + + def test__get_members_keyerror(self): + self.rf_rest.request = mock.Mock(return_value={"key": "value"}) + with pytest.raises(SelfServerException) as excinfo: + members = self.rf_rest._get_members(self.manager_url) + assert excinfo.type == SelfServerException + assert 'Get KeyError' in str(excinfo.value) + + def test_get_bmc_state(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.manager_url + "/BMC"} ]) + with open("%s/manager_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + self.rf_rest.request = mock.Mock(return_value=rsp) + assert self.rf_rest.get_bmc_state() == "On" + + def test_get_bmc_state_keyerror(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.manager_url + "/BMC"} ]) + self.rf_rest.request = mock.Mock(return_value={"powerState": "Off"}) + with pytest.raises(SelfServerException) as excinfo: + resp_data = self.rf_rest.get_bmc_state() + assert excinfo.type == SelfServerException + assert 'Get KeyError' in str(excinfo.value) + + def test_get_chassis_power_state(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.chassis_url + '/MotherBoard'} ]) + with open("%s/chassis_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + self.rf_rest.request = mock.Mock(return_value=rsp) + assert self.rf_rest.get_chassis_power_state() == 'On' + + def test_get_chassis_power_state_keyerror(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.chassis_url + '/MotherBoard'} ]) + self.rf_rest.request = mock.Mock(return_value={"Powerstate": "On"}) + with pytest.raises(SelfServerException) as excinfo: + resp_data = self.rf_rest.get_chassis_power_state() + assert excinfo.type == SelfServerException + assert 'Get KeyError' in str(excinfo.value) + + def test_get_systems_power_state(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.systems_url + '/Computer'} ]) + with open("%s/systems_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + self.rf_rest.request = mock.Mock(return_value=rsp) + assert self.rf_rest.get_systems_power_state() == 'On' + + def test_get_systems_power_state_keyerror(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.systems_url + '/Computer'} ]) + self.rf_rest.request = mock.Mock(return_value={"powerstate": "On"}) + with pytest.raises(SelfServerException) as excinfo: + self.rf_rest.get_systems_power_state() + assert excinfo.type == SelfServerException + assert 'Get KeyError' in str(excinfo.value) + + def test__get_bmc_actions(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.manager_url + '/BMC'} ]) + with open("%s/manager_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + self.rf_rest.request = mock.Mock(return_value=rsp) + reset_string = '#Manager.Reset' + assert self.rf_rest._get_bmc_actions() == (rsp['Actions'][reset_string]['target'], rsp['Actions'][reset_string]['ResetType@Redfish.AllowableValues']) + + def test__get_bmc_actions_keyerror(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.manager_url + '/BMC'} ]) + with open("%s/manager_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + del rsp['Actions']['#Manager.Reset']['ResetType@Redfish.AllowableValues'] + self.rf_rest.request = mock.Mock(return_value=rsp) + with pytest.raises(SelfServerException) as excinfo: + self.rf_rest._get_bmc_actions() + assert excinfo.type == SelfServerException + assert 'Get KeyError' in str(excinfo.value) + + def test_reboot_bmc(self): + with open("%s/manager_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + self.rf_rest._get_bmc_actions = mock.Mock(return_value=(rsp['Actions']['#Manager.Reset']['target'], ['ForceRestart'])) + self.rf_rest.request = mock.Mock(return_value=None) + assert self.rf_rest.reboot_bmc() == None + assert self.rf_rest.request + + def test_reboot_bmc_unsupported(self): + self.rf_rest._get_bmc_actions = mock.Mock(return_value=(self.manager_url + '/BMC/Reset', ['forcerestart'])) + with pytest.raises(SelfClientException) as excinfo: + self.rf_rest.reboot_bmc() + assert excinfo.type == SelfClientException + assert 'Unsupported option:' in str(excinfo.value) + + def test__get_power_actions(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.systems_url + '/Computer'} ]) + with open("%s/systems_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + self.rf_rest.request = mock.Mock(return_value=rsp) + reset_string = '#ComputerSystem.Reset' + assert self.rf_rest._get_power_actions() == (rsp['Actions'][reset_string]['target'], rsp['Actions'][reset_string]['ResetType@Redfish.AllowableValues']) + + def test__get_power_actions_keyerror(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.systems_url + '/Computer'} ]) + with open("%s/systems_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + del rsp['Actions']['#ComputerSystem.Reset']['target'] + self.rf_rest.request = mock.Mock(return_value=rsp) + with pytest.raises(SelfServerException) as excinfo: + self.rf_rest._get_power_actions() + assert excinfo.type == SelfServerException + assert 'Get KeyError' in str(excinfo.value) + + def test_set_power_state(self): + with open("%s/systems_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + reset_string = '#ComputerSystem.Reset' + self.rf_rest._get_power_actions = mock.Mock(return_value=(rsp['Actions'][reset_string]['target'], rsp['Actions'][reset_string]['ResetType@Redfish.AllowableValues'])) + self.rf_rest.request = mock.Mock(return_value=None) + assert self.rf_rest.set_power_state('on') == None + assert self.rf_rest.request + + def test_set_power_state_unsupported(self): + self.rf_rest._get_power_actions = mock.Mock(return_value=(self.systems_url + '/Computer/Reset', ['ForceRestart', 'ForceOff'])) + with pytest.raises(SelfClientException) as excinfo: + self.rf_rest.set_power_state('on') + assert excinfo.type == SelfClientException + assert 'Unsupported option:' in str(excinfo.value) + + def test_get_boot_state(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.systems_url + '/Computer'} ]) + with open("%s/systems_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + self.rf_rest.request = mock.Mock(return_value=rsp) + assert self.rf_rest.get_boot_state() == "boot override inactive" + rsp['Boot']['BootSourceOverrideTarget'] = 'Pxe' + self.rf_rest.request = mock.Mock(return_value=rsp) + assert self.rf_rest.get_boot_state() == 'Network' + rsp['Boot']['BootSourceOverrideEnabled'] = 'Disabled' + self.rf_rest.request = mock.Mock(return_value=rsp) + assert self.rf_rest.get_boot_state() == "boot override inactive" + + def test_get_boot_state_keyerror(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.systems_url + '/Computer'} ]) + with open("%s/systems_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + del rsp['Boot']['BootSourceOverrideEnabled'] + self.rf_rest.request = mock.Mock(return_value=rsp) + with pytest.raises(SelfServerException) as excinfo: + self.rf_rest.get_boot_state() + assert excinfo.type == SelfServerException + assert 'Get KeyError' in str(excinfo.value) + + def test__get_boot_actions(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.systems_url + '/Computer'} ]) + with open("%s/systems_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + self.rf_rest.request = mock.Mock(return_value=rsp) + assert self.rf_rest._get_boot_actions() == (self.systems_url + '/Computer', rsp['Boot']['BootSourceOverrideTarget@Redfish.AllowableValues']) + + def test__get_boot_actions_keyerror(self): + self.rf_rest._get_members = mock.Mock(return_value=[ {"@odata.id": self.systems_url + '/Computer'} ]) + with open("%s/systems_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + del rsp['Boot']['BootSourceOverrideTarget@Redfish.AllowableValues'] + self.rf_rest.request = mock.Mock(return_value=rsp) + with pytest.raises(SelfServerException) as excinfo: + self.rf_rest._get_boot_actions() + assert excinfo.type == SelfServerException + assert 'Get KeyError' in str(excinfo.value) + + def test_set_boot_state(self): + with open("%s/systems_rsp.json" % DATA_DIR,'r') as load_f: + rsp = json.load(load_f) + self.rf_rest._get_boot_actions = mock.Mock(return_value=(self.systems_url + '/Computer', rsp['Boot']['BootSourceOverrideTarget@Redfish.AllowableValues'])) + self.rf_rest.request = mock.Mock(return_value=None) + assert self.rf_rest.set_boot_state(False, 'def') == None + assert self.rf_rest.request + assert self.rf_rest.set_boot_state(True, 'cd') == None + assert self.rf_rest.request + + def test_set_boot_state_unsupported(self): + allow_values = ['cd','def'] + self.rf_rest._get_boot_actions = mock.Mock(return_value=(self.systems_url + '/Computer', allow_values)) + with pytest.raises(SelfClientException) as excinfo: + self.rf_rest.set_boot_state(False, 'hd') + assert excinfo.type == SelfClientException + assert 'Unsupported option:' in str(excinfo.value) + +def test_init_no_bmcip(): + nodeinfo_dict = {'bmc': 'testbmc', 'username': 'username', 'password': 'password'} + rf_rest_new = rf.RedfishRest(name='testnode', nodeinfo=nodeinfo_dict, messager=Messager(), + debugmode=True, verbose=False) + + assert rf_rest_new.bmcip == 'testnode'