def test_with_regular_formatting_fields(self): with StdoutCapture() as output: cts_error('kot{kogo}wazy{ile}', kogo='prezesa', ile='sporo') self.assertIsNotNone(re.search("kotprezesawazysporo.*\[#Id=[0-9a-f]{32}\]", output.raw)) with StdoutCapture() as output: cts_error('kot{kogo}wazy{ile}kg', kogo='prezesa', ile=20) self.assertIsNotNone(re.search("kotprezesawazy20kg.*\[#Id=[0-9a-f]{32}\]", output.raw))
def test_identical_error_id_for_different_stacktraces(self): with StdoutCapture() as output: cts_error('{stacktrace:stacktrace}', stacktrace='one') match = re.search("\[#Id=(?P<id>[0-9a-f]{32})\]", output.raw) self.assertIsNotNone(match) id_1 = match.group('id') with StdoutCapture() as output: cts_error('{stacktrace:stacktrace}', stacktrace='two') match = re.search("\[#Id=(?P<id>[0-9a-f]{32})\]", output.raw) self.assertIsNotNone(match) id_2 = match.group('id') self.assertEqual(id_1, id_2)
def test_should_validate_complex_type_additional_typed_property_and_fail(self): """ when additional property of type 'ComplexType' does have odata.type specified we can validate it against metadata. In this case Inner complex type property is not conformant with metadata. """ EntityJson = { "@odata.type": "MyNamespace.v1_0_0.MyEntity", "Outer": { "@odata.type": "MyNamespace.v1_0_0.OuterComplexType", "Name": "OuterName", "InnerValidate": { "@odata.type": "MyNamespace.v1_0_0.InnerComplexType", "foo": "bar" } } } entity_type = EntityJson["@odata.type"] with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, self.metadata_container.entities[entity_type].validate(EntityJson, '')) self.assertIn('ERROR::Property ->Outer->InnerValidate->foo is present, but not defined in metadata. ' + \ 'Type MyNamespace.v1_0_0.InnerComplexType does not allow additional properties', output.raw)
def test_failed_when_id_not_unique_within_scope(self): parent = self.builder.build("/redfish/v1/Chassis/Rack", "#Chassis.v1_2_0.Chassis", "/redfish/v1/$metadata#Chassis/Members/$entity", ChassisType='Rack' ).with_location(id='Rack', parent_id=None) \ .contains("/redfish/v1/Chassis/Drawer1", "/redfish/v1/Chassis/Drawer2") \ .commit() child1 = self.builder.build("/redfish/v1/Chassis/Drawer1", "#Chassis.v1_2_0.Chassis", "/redfish/v1/$metadata#Chassis/Members/$entity", ChassisType='Rack' )\ .with_location(id='LocationA', parent_id='Rack') \ .contained_by("/redfish/v1/Chassis/Rack") \ .commit() child2 = self.builder.build("/redfish/v1/Chassis/Drawer2", "#Chassis.v1_2_0.Chassis", "/redfish/v1/$metadata#Chassis/Members/$entity", ChassisType='Rack' )\ .with_location(id='LocationA', parent_id='Rack') \ .contained_by("/redfish/v1/Chassis/Rack") \ .commit() with StdoutCapture() as output: self.assertEqual( ValidationStatus.FAILED, self.validator.validate_path_using_contains_property()) self.assertIn( 'has location id LocationA that conflicts with resources', '\n'.join(output))
def test_should_fail_when_processors_invalid_on_computer_system(self): system = { "@odata.context": "/redfish/v1/$metadata#Systems/Members/$entity", "@odata.id": "/redfish/v1/Systems/s1-2", "@odata.type": "#ComputerSystem.v1_0_0.ComputerSystem", "ProcessorSummary": { "Count": 0 }, "MemorySummary": { "TotalSystemMemoryGiB": 8 } } self.discovery_container.add_resource( ApiResource("/redfish/v1/ComputerSystem/1", 'netloc', system, "ComputerSystem.v1_1_0.ComputerSystem")) with StdoutCapture() as output: self.checklist.at_least_one_compute_module_in_pod( self.discovery_container) self.assertIn( 'ERROR::Computer System with memory and processors not found', output.raw) self.assertIn('STATUS::Failed', output)
def test_failed_when_circular_dependency(self): parent = self.builder.build("/redfish/v1/Chassis/Rack", "#Chassis.v1_2_0.Chassis", "/redfish/v1/$metadata#Chassis/Members/$entity", ChassisType='Rack' ).with_location(id='Rack', parent_id=None) \ .contains("/redfish/v1/Chassis/Drawer") \ .contained_by("/redfish/v1/Chassis/Drawer") \ .commit() child = self.builder.build("/redfish/v1/Chassis/Drawer", "#Chassis.v1_2_0.Chassis", "/redfish/v1/$metadata#Chassis/Members/$entity", ChassisType='Rack' ).with_location(id='Chassis', parent_id='Rack') \ .contained_by("/redfish/v1/Chassis/Rack") \ .contains("/redfish/v1/Chassis/Rack") \ .commit() with StdoutCapture() as output: self.assertEqual( ValidationStatus.FAILED, self.validator.validate_path_using_contains_property()) self.assertIn( 'but child resource has invalid Location->ParentId. Is: None. Expected: Chassis', '\n'.join(output))
def test_should_raise_error_on_complex_additional_property_without_odata_type(self): """ when additional property inside Entity does not have odata.type specified and it is not DynamicProperty, CTS should raise an error """ EntityJson = { "@odata.type": "MyNamespace.v1_0_0.MyEntity", "EntityLevelAdditional": { # odatatype intentionally skipped "foo": "bar" }, "Outer": { "@odata.type": "MyNamespace.v1_0_0.OuterComplexType", "Name": "OuterName", } } entity_type = EntityJson["@odata.type"] with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, self.metadata_container.entities[entity_type].validate(EntityJson, '')) self.assertIn('ERROR::Property url=->EntityLevelAdditional is of complex type without ' '@odata_type', output.raw)
def test_failed_when_some_resources_have_location_some_not(self): parent = self.builder.build("/redfish/v1/Chassis/Rack", "#Chassis.v1_2_0.Chassis", "/redfish/v1/$metadata#Chassis/Members/$entity", ChassisType='Rack' ) \ .contains("/redfish/v1/Chassis/Drawer1", "/redfish/v1/Chassis/Drawer2") \ .commit() child1 = self.builder.build("/redfish/v1/Chassis/Drawer1", "#Chassis.v1_2_0.Chassis", "/redfish/v1/$metadata#Chassis/Members/$entity", ChassisType='Rack' )\ .with_location(id='LocationA', parent_id='Rack') \ .contained_by("/redfish/v1/Chassis/Rack") \ .commit() with StdoutCapture() as output: self.assertEqual( ValidationStatus.FAILED, self.validator.validate_all_or_none_chassis_have_location()) self.assertIn( 'Some chassis have Oem/Intel_RackScale/Location some does not', '\n'.join(output))
def test_should_raise_an_error_when_complex_type_additional_property_without_odatatype( self): """ when additional property of type 'ComplexType' does not have odata.type specified we cannot validate it against metadata """ EntityJson = { "@odata.type": "MyNamespace.v1_0_0.MyEntity", "Outer": { "@odata.type": "MyNamespace.v1_0_0.OuterComplexType", "Name": "OuterName", "InnerToNotValidate": { #odatatype intentionally skipped "foo": "bar" } } } entity_type = EntityJson["@odata.type"] with StdoutCapture() as output: self.assertEqual( ValidationStatus.FAILED, self.metadata_container.entities[entity_type].validate( EntityJson, '')) self.assertIn( 'ERROR::Property ->Outer->InnerToNotValidate is of complex type without @odata_type', output.raw)
def test_discovery_from_nested_additional_properties(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Property Name="Oem" Type="N.Oem"> </Property> </EntityType> <ComplexType Name="Oem" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> </ComplexType> <ComplexType Name="Inner" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </ComplexType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "Oem": { "additional_property": { "@odata.type": "#N.Inner", "Link": { "@odata.id": "/this/is/the/link/to/be/discovered" }, } } } referenced = \ { "@odata.id": "referenced.id", "@odata.type": "#N.Referenced", } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, referenced, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(2, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output))
def test_empty_body(self): self.api_explorer._get_resource = MagicMock( return_value=(Link('link', 'netloc'), RequestStatus.SUCCESS, {})) with StdoutCapture() as output: self.api_explorer.discover("odata_id", None) self.assertIn('Empty response body', '\n'.join(output))
def test_with_incorrect_replay_id(self): replay_action = ReplayActionUnderTest() configuration = Mock(replay_id=['incorrect']) with StdoutCapture() as output: replay_action.process_action(configuration) self.assertIn('Replay id has invalid format', output.raw)
def test_url_required_exception(self): with mock.patch('requests.get') as requests_get_mock: requests_get_mock.side_effect = requests.URLRequired() with StdoutCapture() as output: self.api_caller.get_resource("/resource", DiscoveryContainer()) self.assertIn("ERROR::Get url=http://1.2.3.4:567/resource Error <class " "'requests.exceptions.URLRequired'>:", output.raw)
def test_to_many_redirects_exception(self): with mock.patch('requests.get') as requests_get_mock: requests_get_mock.side_effect = requests.TooManyRedirects() with StdoutCapture() as output: self.api_caller.get_resource("/resource", DiscoveryContainer()) self.assertIn( "ERROR::Get url=http://1.2.3.4:567/resource Error <class 'requests.exceptions.TooManyRedirects'>:;", output.raw)
def test_handle_collection_with_typeless_elements_referenced_by_json_pointer( self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="MyCollection" Type="Collection(ReferencedEntity)" ContainsTarget="true"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </NavigationProperty> </EntityType> <EntityType Name="ReferencedEntity" Abstract="false"> <Property Name="name" Type="Edm.String"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "MyCollection": [ { # implicit odata.type = ReferencedEntity "@odata.id": "/outer#MyCollection/0", "name": "MyName 0" }, { # implicit odata_type = ReferencedEntity "@odata.id": "/outer#MyCollection/1", "name": "MyName 1" } ] } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings( metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch('cts_core.commons.api_caller.ApiCaller.get_resource' ) as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(3, get_resource.call_count) self.assertEqual(0, len(re.findall('ERROR::', ';'.join(output))))
def test_empty_service_root(self): with mock.patch('requests.get') as requests_get_mock: requests_get_mock.side_effect = requests.ConnectionError() with StdoutCapture() as output: self.api_caller.get_resource("/redfish/v1", DiscoveryContainer()) self.assertIn( "ERROR::Get url=http://1.2.3.4:567/redfish/v1 Error <class 'requests.exceptions.ConnectionError'>:;", output.raw)
def test_incorrect_status_code(self): with mock.patch('requests.get') as requests_get_mock: response = Mock() response.status_code = 500 response.headers = {} response.text = "{}" requests_get_mock.return_value = response with StdoutCapture() as output: self.api_caller.get_resource("/resource", DiscoveryContainer()) self.assertIn("ERROR::url=/resource Get failed. Status code: 500;", output.raw)
def test_parse_big_ordered_tree_response(self): from collections import OrderedDict response_payload = OrderedDict( [(u'@odata.context', u'/redfish/v1/$metadata#ServiceRoot.ServiceRoot'), (u'@odata.etag', u'W/"1557488360"'), (u'@odata.id', \ u'/redfish/v1/'), (u'@odata.type', u'#ServiceRoot.v1_3_1.ServiceRoot'), (u'AccountService', OrderedDict([(u'@odata.id', u'/redfish/v1/AccountService')])), (u'Chassis', OrderedDict([(u'@odata.id', u'/redfish/v1/Chassis')])), (u'Description', u'The service root \ for all Redfish requests on this host \ ' ), (u'EventService', OrderedDict([(u' @ odata.id', u' / redfish / v1 / EventService')])), (u'Id', u'RootService'), ( u'Links', OrderedDict( [(u'Oem', OrderedDict([(u'Ami', OrderedDict([(u'@odata.id', u'/redfish/v1/configurations')]))])), (u'Sessions', OrderedDict([(u'@odata.id', u'/redfish/v1/SessionService/Sessions')]))])), ( u'Managers', OrderedDict([(u'@odata.id', u'/redfish/v1/Managers')])), (u'Name', u'PSME Service Root'), ( u'Oem', OrderedDict([(u'Ami', OrderedDict([(u'Chassislocation', OrderedDict( [(u'@odata.id', u'/redfish/v1/Chassislocation')])), (u'Configurations', OrderedDict([(u'@odata.id', u'/redfish/v1/configurations')])), (u'PsmeVersion', u'2.4.181218.tb1')])), (u'Intel_RackScale', OrderedDict([(u'@odata.type', u'#Intel.Oem.ServiceRoot'), (u'ApiVersion', u'2.4.0'), ( u'TelemetryService', OrderedDict([(u'@odata.id', u'/redfish/v1/TelemetryService')]))]))])), (u'Product', u'AMI Redfish Server'), (u'ProtocolFeaturesSupported', OrderedDict([(u'ExpandQuery', OrderedDict( [(u'ExpandAll', True), (u'Levels', True), (u'Links', True), (u'MaxLevels', 5), (u'NoLinks', True)])), (u'FilterQuery', True), (u'SelectQuery', True)])), ( u'RedfishVersion', u'1.5.0'), (u'Registries', OrderedDict([(u'@odata.id', u'/redfish/v1/Registries')])), ( u'SessionService', OrderedDict([(u'@odata.id', u'/redfish/v1/SessionService')])), (u'Systems', OrderedDict([( u'@odata.id', u'/redfish/v1/Systems')])), (u'Tasks', OrderedDict([(u'@odata.id', u'/redfish/v1/TaskService')])), (u'UUID', u'ffffffff-ffff-ffff-ffff-ffffffffffff'), (u'UpdateService', OrderedDict([(u'@odata.id', u'/redfish/v1/UpdateService')]))]) with mock.patch('requests.get') as requests_get_mock: response = Mock() response.status_code = 200 response.headers = {} response.text = response_payload requests_get_mock.return_value = response with StdoutCapture() as output: self.api_caller.get_resource("/resource", DiscoveryContainer()) self.assertIsNot("ERROR", output.raw)
def test_incorrect_body(self): with mock.patch('requests.get') as requests_get_mock: response = Mock() response.status_code = 200 response.headers = {} response.text = "not a json" requests_get_mock.return_value = response with StdoutCapture() as output: self.api_caller.get_resource("/resource", DiscoveryContainer()) self.assertIn("ERROR", output.raw)
def test_patch(self): with mock.patch('cts_core.commons.api_caller.ApiCaller.__init__') as api_caller_init_mock: api_caller_init_mock.return_value = None with mock.patch('cts_core.validation.patch.metadata_patch_validator.MetadataPatchValidator._validate_patchable_property') as validate_property: validate_property.return_value = ValidationStatus.PASSED validator = MetadataPatchValidator(self.metadata_container, None, PatchingStrategy2_1()) with StdoutCapture() as output: self.assertEqual(ValidationStatus.PASSED, validator.validate(self.discovery_container))
def test_invalid_hierarchy_without_root_resource(self): self.builder.build("/redfish/v1/Chassis/Rack", "#Chassis.v1_2_0.Chassis", "/redfish/v1/$metadata#Chassis/Members/$entity", ChassisType='Rack').with_location( id='Rack', parent_id='SomeNode').commit() with StdoutCapture() as output: self.assertEqual( ValidationStatus.FAILED, self.validator.validate_path_using_contains_property()) self.assertIn('but none has NULL ParentId', '\n'.join(output))
def test_with_nonexistent_replay_id(self): with mock.patch( 'cts_framework.db.dao.script_dao.ScriptDAO.get_script_execution_details' ) as get_script_execution_details: get_script_execution_details.return_value = None replay_action = ReplayActionUnderTest() configuration = Mock(replay_id=['62']) with StdoutCapture() as output: replay_action.process_action(configuration) self.assertIn('Recording for script execution id=62 not found', output.raw)
def test_should_pass_for_chassis_with_power(self): self.discovery_container.add_resource(ApiResource("/redfish/v1/Chassis/rack-with-power", 'netloc', RACK_WITH_POWER, "Chassis.v1_1_0.Chassis")) self.discovery_container.add_resource(ApiResource( "/redfish/v1/Chassis/rack-with-power/PowerZones", 'netloc', POWER_ZONES_EMPTY, "PowerZoneCollection.PowerZoneCollection")) self.discovery_container.add_resource(ApiResource( "/redfish/v1/Chassis/rack-with-power/Power", 'netloc', POWER_WITH_POWER_CONTROL, "Power.v1_1_0.Power")) self.discovery_container.add_resource(ApiResource( "/redfish/v1/Chassis/rack-with-power/Power/PowerControl/1", 'netloc', POWER_CONTROL_1, "Power.v1_1_0.PowerControl")) with StdoutCapture() as output: self.checklist.power_monitoring_support(self.discovery_container) self.assertEqual(ValidationStatus.PASSED, self.checklist.validation_status)
def test_failed_when_contained_does_not_exist(self): self.builder.build("/redfish/v1/Chassis/Rack", "#Chassis.v1_2_0.Chassis", "/redfish/v1/$metadata#Chassis/Members/$entity", ChassisType='Rack' ).with_location(id='Rack', parent_id=None) \ .contains("/redfish/v1/Chassis/Drawer").commit() with StdoutCapture() as output: self.assertEqual( ValidationStatus.FAILED, self.validator.validate_path_using_contains_property()) self.assertIn( 'contains reference to nonexistent resource url=/redfish/v1/Chassis/Drawer', '\n'.join(output))
def test_should_pass_with_correct_resource(self): metadata_manager = MetadataManager(["qualifier"]) self.metadata_container = metadata_manager.read_metadata_from_strings( "Unknown", METADATA) self.discovery_container = DiscoveryContainer() self.discovery_container.add_resource( ApiResource("/redfish/resource1", 'netloc', RESOURCE_CORRECT, "#N.R")) requirements = [] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.PASSED, validator.validate(self.discovery_container))
def test_parent_odata_id(self): child_parent_pairs = [ ("", None), (None, None), ("/", ""), ("/anything", "/"), ("/some/resource/path", "/some/resource"), ("/some/resource/path/", "/some/resource"), ("/redfish/v1/EthernetSwitches/1/Ports/1/VLANs/1", "/redfish/v1/EthernetSwitches/1/Ports/1/VLANs"), ("/redfish/v1/EthernetSwitches/1/Ports/1/VLANs/", "/redfish/v1/EthernetSwitches/1/Ports/1"), ("/redfish/v1/Chassis/cr1-1/Thermal#/Temperatures/1", "/redfish/v1/Chassis/cr1-1/Thermal#/Temperatures") ] with StdoutCapture() as output: # some warnings for Nones and empty strings expected for pair in child_parent_pairs: resource = ApiResource(pair[0], 'netloc', { '@odata.id' : pair[0] }, None) self.assertEqual(resource._get_parent_url(), pair[1])
def test_failed_when_more_than_one_root(self): chassis_1 = self.builder.build( "/redfish/v1/Chassis/Rack", "#Chassis.v1_2_0.Chassis", "/redfish/v1/$metadata#Chassis/Members/$entity", ChassisType='Rack').with_location(id='Rack', parent_id=None).commit() self.builder.clone("/redfish/v1/Chassis/Rack2").commit() with StdoutCapture() as output: self.assertEqual( ValidationStatus.FAILED, self.validator.validate_path_using_contains_property()) self.assertIn( 'More than one root resource (with NULL ParentId). Expected only one', '\n'.join(output))
def test_should_not_patch_if_property_annotation_is_non_trivial_and_alternative_implementation_not_known( self): """ when additional property of type 'ComplexType' does have annotation Term Nontriavial should not be patched """ metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings( AdditionalPropertiesPatchTest.METADATA) entity_json = { "@odata.type": "MyNamespace.v1_0_0.MyEntity", "Outer": { "@odata.type": "MyNamespace.v1_0_0.OuterComplexType", "Name": "OuterName", "InnerToValidate": { "@odata.type": "MyNamespace.v1_0_0.InnerComplexType", "Name": "This name property is required" } } } self.discovery_container.add_resource( ApiResource("/redfish/v1/Managers/RMC", "netloc", entity_json, "#MyNamespace.v1_0_0.MyEntity")) with mock.patch('cts_core.commons.api_caller.ApiCaller.__init__' ) as api_caller_init_mock: api_caller_init_mock.return_value = None validator = MetadataPatchValidator(metadata_container, None, PatchingStrategy2_2()) # this ValidationStatus.BLOCKED should be not affect final ValidationStatus validator._verify_property = MagicMock( return_value=(ValidationStatus.BLOCKED, None)) validator._restore_property = MagicMock( return_value=ValidationStatus.BLOCKED) validator._patch_property = MagicMock( return_value=(True, True, ValidationStatus.BLOCKED)) with StdoutCapture() as out: self.assertEqual(ValidationStatus.PASSED_WITH_WARNINGS, validator.validate(self.discovery_container)) self.assertIn('WARNING::Skipping non-trivial property Name;', out.raw)
def test_with_invalid_script_path(self): with mock.patch( 'cts_framework.db.dao.script_dao.ScriptDAO.get_script_execution_details' ) as get_script_execution_details: script_execution = Mock(configuration="", script_path="nonexistent") get_script_execution_details.return_value = script_execution replay_action = ReplayActionUnderTest() configuration = Mock(replay_id=['62']) with StdoutCapture() as output: with self.assertRaises(SystemExit) as cm: replay_action.process_action(configuration) self.assertIn('Script to execute not found in any package', output.raw)
def test_get_resource_with_odata_failed(self): self.api_explorer._api_caller.get_resource = MagicMock( return_value=( Link('link', 'netloc'), RequestStatus.SUCCESS, None, { '@odata.type': 'type.of.b', 'inner': [ {'@odata.id': '/redfish/a/b#inner/3'}, {'@odata.id': '/redfish/a/b#inner/4'} ] }, None)) with StdoutCapture() as output: link, status, body, _ = self.api_explorer._get_resource("/redfish/a/b#inner/543534634") self.assertIsNot(RequestStatus.SUCCESS, status) self.assertIn( "ERROR::Could not find /inner/543534634 from url=/redfish/a/b#inner/543534634 with search by @odata.id;", output.raw)