Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added tests to verify functionality with settings resources #56

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions redfish_protocol_validator/console_scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from urllib3.exceptions import InsecureRequestWarning
from http.client import HTTPConnection

from redfish_protocol_validator import data_model
from redfish_protocol_validator import protocol_details
from redfish_protocol_validator import report
from redfish_protocol_validator import resources
Expand All @@ -33,6 +34,7 @@ def perform_tests(sut: SystemUnderTest):
protocol_details.test_protocol_details(sut)
service_requests.test_service_requests(sut)
service_responses.test_service_responses(sut)
data_model.test_data_model(sut)
service_details.test_service_details(sut)
security_details.test_security_details(sut)

Expand Down
11 changes: 11 additions & 0 deletions redfish_protocol_validator/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Result(NoValue):
class ResourceType(NoValue):
MANAGER_ACCOUNT = auto()
ROLE = auto()
BIOS = auto()


class RequestType(NoValue):
Expand Down Expand Up @@ -385,6 +386,16 @@ class Assertion(NoValue):
'that contains an entry for the Service Root and each resource that '
'is a direct child of the Service Root.'
)
# Data model assertions (prefix of "DATA_")
DATA_SETTINGS_RES_SETTINGS_ANNOTATION = (
'For resources that support a future intended state, the response '
'shall contain a property with the @Redfish.Settings payload '
'annotation.'
)
DATA_SETTINGS_RES_DATA_TYPE = (
'The settings resource shall be of the same schema definition as the '
'active resource.'
)
# Service details assertions (prefix of "SERV_")
SERV_EVENT_POST_RESP = (
'If the [Event Service] subscription request succeeds, the service '
Expand Down
111 changes: 111 additions & 0 deletions redfish_protocol_validator/data_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Copyright Notice:
# Copyright 2020-2023 DMTF. All rights reserved.
# License: BSD 3-Clause License. For full text see link:
# https://github.com/DMTF/Redfish-Protocol-Validator/blob/master/LICENSE.md

import requests

from redfish_protocol_validator import utils
from redfish_protocol_validator.constants import Assertion, RequestType, ResourceType, Result
from redfish_protocol_validator.system_under_test import SystemUnderTest

def test_settings_resources(sut):
"""Perform tests from the 'Settings resource' sub-section of the spec."""

# Find resources that have a high likelihood of containing a settings resource
responses = sut.get_responses_by_method('GET', resource_type=ResourceType.BIOS)
if len(responses) == 0:
# No resources found
msg = 'No Bios resource found to test assertion'
sut.log(Result.NOT_TESTED, '', '', '',
Assertion.DATA_SETTINGS_RES_SETTINGS_ANNOTATION, msg)
sut.log(Result.NOT_TESTED, '', '', '',
Assertion.DATA_SETTINGS_RES_DATA_TYPE, msg)
return

# Check each resource for a settings resource
for uri, response in responses.items():
if response.ok:
response_data = response.json()
check_settings_type = False

# Try to get the settings resource URI
settings_uri = response_data.get('@Redfish.Settings', {}).get('SettingsObject', {}).get('@odata.id')

if settings_uri is not None:
# Settings annotation found; pass
sut.log(Result.PASS, 'GET', response.status_code, uri,
Assertion.DATA_SETTINGS_RES_SETTINGS_ANNOTATION,
'Test passed')
check_settings_type = True
settings_response = sut.session.get(sut.rhost + settings_uri)
else:
# Not found; probe for potential settings resource
for segment in ['/SD', '/Settings']:
settings_uri = uri + segment
settings_response = sut.session.get(sut.rhost + settings_uri)
if settings_response.ok:
check_settings_type = True
msg = ('%s does not contain a settings annotation, but '
'the settings resource %s is accessible' %
(uri, settings_uri))
sut.log(Result.FAIL, response.request.method,
response.status_code, uri,
Assertion.DATA_SETTINGS_RES_SETTINGS_ANNOTATION, msg)
break
if not settings_response.ok:
# No responses
msg = ('%s does not contain a settings resource' % uri)
sut.log(Result.NOT_TESTED, response.request.method,
response.status_code, uri,
Assertion.DATA_SETTINGS_RES_SETTINGS_ANNOTATION, msg)

# If there's a settings resource, compare the resource types
if check_settings_type:
settings_response_data = settings_response.json()
if settings_response.ok:
# Successful settings resource response; compare @odata.type
if settings_response_data.get('@odata.type') != response_data.get('@odata.type'):
msg = ('The settings resource contains @odata.type %s, '
'but the active resource contains @odata.type '
'%s' % (settings_response_data.get('@odata.type'),
response_data.get('@odata.type')))
sut.log(Result.FAIL, response.request.method,
response.status_code, uri,
Assertion.DATA_SETTINGS_RES_SETTINGS_ANNOTATION,
msg)
else:
sut.log(Result.PASS, 'GET', response.status_code, uri,
Assertion.DATA_SETTINGS_RES_DATA_TYPE,
'Test passed')
else:
# Could not get the settings resource
msg = ('%s request to %s failed with status %s;'
'extended error %s' %
(settings_response.request.method, settings_uri,
settings_response.status_code,
utils.get_extended_error(settings_response)))
sut.log(Result.WARN, response.request.method,
response.status_code, uri,
Assertion.DATA_SETTINGS_RES_DATA_TYPE, msg)
else:
msg = ('%s does not contain a settings resource' % uri)
sut.log(Result.NOT_TESTED, response.request.method,
response.status_code, uri,
Assertion.DATA_SETTINGS_RES_DATA_TYPE, msg)
else:
msg = ('%s request to %s failed with status %s;'
'extended error %s' %
(response.request.method, uri, response.status_code,
utils.get_extended_error(response)))
sut.log(Result.WARN, response.request.method,
response.status_code, uri,
Assertion.DATA_SETTINGS_RES_SETTINGS_ANNOTATION, msg)
sut.log(Result.WARN, response.request.method,
response.status_code, uri,
Assertion.DATA_SETTINGS_RES_DATA_TYPE, msg)


def test_data_model(sut: SystemUnderTest):
"""Perform tests from the 'Data model' section of the spec."""
test_settings_resources(sut)
1 change: 1 addition & 0 deletions redfish_protocol_validator/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
('PROTO_', 'Protocol Details'),
('REQ_', 'Service Requests'),
('RESP_', 'Service Responses'),
('DATA_', 'Data Model'),
('SERV_', 'Service Details'),
('SEC_', 'Security Details'),
]
Expand Down
41 changes: 29 additions & 12 deletions redfish_protocol_validator/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,35 @@ def get_default_resources(sut: SystemUnderTest, uri='/redfish/v1/',
sut.set_service_uuid(root.get('UUID'))
sut.set_supported_query_params(root.get('ProtocolFeaturesSupported', {}))

for prop in ['Systems', 'Chassis']:
if prop in root:
uri = root[prop]['@odata.id']
sut.set_nav_prop_uri(prop, uri)
r = sut.session.get(sut.rhost + uri)
yield {'uri': uri, 'response': r}
if r.ok:
data = r.json()
if 'Members' in data and len(data['Members']):
uri = data['Members'][0]['@odata.id']
r = sut.session.get(sut.rhost + uri)
yield {'uri': uri, 'response': r}
if 'Chassis' in root:
uri = root['Chassis']['@odata.id']
sut.set_nav_prop_uri('Chassis', uri)
r = sut.session.get(sut.rhost + uri)
yield {'uri': uri, 'response': r}
if r.ok:
data = r.json()
if 'Members' in data and len(data['Members']):
uri = data['Members'][0]['@odata.id']
r = sut.session.get(sut.rhost + uri)
yield {'uri': uri, 'response': r}

if 'Systems' in root:
uri = root['Systems']['@odata.id']
sut.set_nav_prop_uri('Systems', uri)
r = sut.session.get(sut.rhost + uri)
yield {'uri': uri, 'response': r}
if r.ok:
data = r.json()
if 'Members' in data and len(data['Members']):
uri = data['Members'][0]['@odata.id']
r = sut.session.get(sut.rhost + uri)
yield {'uri': uri, 'response': r}
if r.ok:
d = r.json()
if 'Bios' in d:
uri = d['Bios']['@odata.id']
r = sut.session.get(sut.rhost + uri)
yield {'uri': uri, 'response': r, 'resource_type': ResourceType.BIOS}

if 'Managers' in root:
uri = root['Managers']['@odata.id']
Expand Down