diff --git a/redfish_service_validator/tohtml.py b/redfish_service_validator/tohtml.py index ed43b1f..22eb4b7 100644 --- a/redfish_service_validator/tohtml.py +++ b/redfish_service_validator/tohtml.py @@ -13,6 +13,7 @@ from types import SimpleNamespace from collections import Counter import json +import re # hack in tagnames into module namespace tag = SimpleNamespace(**{tagName: lambda string, attr=None, tag=tagName: wrapTag(string, tag=tag, attr=attr)\ @@ -29,7 +30,7 @@ def count_errors(results): for countType in sorted(innerCounts.keys()): if innerCounts.get(countType) == 0: continue - if any(x in countType for x in ['problem', 'fail', 'bad', 'exception', 'err.']): + if re.search(r"^error|problem|fail|bad|exception|err[.]", countType): counters_all_pass = False error_lines.append('{} {} errors in {}'.format(innerCounts[countType], countType, results[item]['uri'])) innerCounts[countType] += 0 diff --git a/redfish_service_validator/validateRedfish.py b/redfish_service_validator/validateRedfish.py index 8bb90cf..aa7427c 100644 --- a/redfish_service_validator/validateRedfish.py +++ b/redfish_service_validator/validateRedfish.py @@ -42,12 +42,17 @@ def validateExcerpt(prop, val): return True -def validateAction(act_name, actionDecoded, all_actions): +def validateAction(act_fulltype, actionDecoded, all_actions): actionMessages, actionCounts = OrderedDict(), Counter() - act_name, act_type = getNamespace(act_name.strip('#')), getType(act_name) + act_namespace, act_type = getNamespace(act_fulltype.strip('#')), getType(act_fulltype) actPass = False if act_type not in all_actions: + my_logger.error('Action {} does not exist in Namespace {}'.format(act_type, act_namespace)) actionCounts['errorActionBadName'] += 1 + actionMessages[act_fulltype] = ( + 'Action', '-', + 'Yes' if actionDecoded != REDFISH_ABSENT else 'No', + 'FAIL') else: my_act = all_actions[act_type] actOptional = my_act.find('annotation', {'term': 'Redfish.Required'}) is not None @@ -55,21 +60,21 @@ def validateAction(act_name, actionDecoded, all_actions): if actOptional: actPass = True else: - my_logger.error('{}: Mandatory action missing'.format(act_name)) + my_logger.error('{}: Mandatory action missing'.format(act_namespace)) actionCounts['failMandatoryAction'] += 1 if actionDecoded != REDFISH_ABSENT: # validate target target = actionDecoded.get('target') if target is None: - my_logger.error('{}: target for action is missing'.format(act_name)) + my_logger.error('{}: target for action is missing'.format(act_namespace)) elif not isinstance(target, str): - my_logger.error('{}: target for action is malformed'.format(act_name)) + my_logger.error('{}: target for action is malformed'.format(act_namespace)) # check for unexpected properties for ap_name in actionDecoded: expected = ['target', 'title', '@Redfish.ActionInfo', '@Redfish.OperationApplyTimeSupport'] if ap_name not in expected and '@Redfish.AllowableValues' not in ap_name: my_logger.error('{}: Property "{}" is not allowed in actions property. \ - Allowed properties are "{}", "{}", "{}", "{}" and "{}"'.format(act_name, ap_name, *expected, '*@Redfish.AllowableValues')) + Allowed properties are "{}", "{}", "{}", "{}" and "{}"'.format(act_namespace, ap_name, *expected, '*@Redfish.AllowableValues')) actPass = True if actOptional and actPass: actionCounts['optionalAction'] += 1 @@ -78,9 +83,9 @@ def validateAction(act_name, actionDecoded, all_actions): else: actionCounts['failAction'] += 1 - actionMessages[act_name] = ( + actionMessages[act_fulltype] = ( 'Action', '-', - 'Yes' if actionDecoded != 'n/a' else 'No', + 'Yes' if actionDecoded != REDFISH_ABSENT else 'No', 'Optional' if actOptional else 'PASS' if actPass else 'FAIL') return actionMessages, actionCounts @@ -218,8 +223,8 @@ def validateComplex(service, sub_obj, prop_name, oem_check=True): subCounts.update(new_counts) subCounts['invalidNamedProperty.complex'] += 1 - successPayload, odataMessages = checkPayloadConformance(sub_obj.Value, '') + if not successPayload: odataMessages['failPayloadError.complex'] += 1 my_logger.error('{}: complex payload error, @odata property non-conformant'.format(str(sub_obj.Name))) @@ -227,6 +232,8 @@ def validateComplex(service, sub_obj, prop_name, oem_check=True): if prop_name == 'Actions': actionMessages, actionCounts = OrderedDict(), Counter() + # Get our actions from the object itself to test + # Action Namespace.Type, Action Object my_actions = [(x.strip('#'), y) for x, y in sub_obj.Value.items() if x != 'Oem'] if 'Oem' in sub_obj.Value.items(): if oem_check: