def setUp(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/v1/Fabrics/1/Endpoints/8", 'netloc', RESOURCE, "#Endpoint.v1_0_0.Endpoint"))
def test_property_invalid_collection(self): METADATA = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="MyNamespace.v1_0_0"> <EntityType Name="MyEntity"> <Property name="property_name" type="Collection(MyComplexType)"> </Property> </EntityType> <ComplexType Name="MyComplexType"> <Property Name="Name" Nullable="false" Type="Edm.String"/> </ComplexType> </Schema> """ discovery_container = DiscoveryContainer() metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", METADATA) EntityJson = { "@odata.type": "MyNamespace.v1_0_0.MyEntity", "property_name" : {'a' : {'x' : 1}, 'b' : {'y' : 2}} } entity_type = EntityJson["@odata.type"] with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, metadata_container.entities[entity_type].validate(EntityJson, '')) self.assertIn('ERROR::Property ->property_name is expected to be collection, but it is not' '', output.raw)
def test_iter_all(self): metadata_manager = MetadataManager(["qualifier"]) discovery_container = DiscoveryContainer( metadata_container=metadata_manager.read_metadata_from_strings("Unknown", self.TEST_METADATA)) chassis1_2 = { "@odata.context": "/redfish/v1/$metadata#Chassis/Members/$entity", "@odata.id": "/redfish/v1/Chassis/Rack1", "@odata.type": "#Chassis.v1_2_0.Chassis", "ChassisType": "Rack", } discovery_container.add_resource(ApiResource("/redfish/v1/Chassis/Rack1", 'netloc',chassis1_2, "Chassis.v1_2_0.Chassis")) self.assertEqual(1, len(list(discovery_container.iter_all("Chassis.v1_2_0.Chassis")))) self.assertEqual(1, len(list(discovery_container.iter_all("Chassis.v1_0_0.Chassis")))) self.assertEqual(1, len(list(discovery_container.iter_all("Chassis.Chassis")))) self.assertEqual(1, len(list(discovery_container.iter_all("Resource.v1_0_0.Resource")))) self.assertEqual(1, len(list(discovery_container.iter_all("Resource.Resource")))) chassis1_0 = { "@odata.context": "/redfish/v1/$metadata#Chassis/Members/$entity", "@odata.id": "/redfish/v1/Chassis/Module1", "@odata.type": "#Chassis.v1_0_0.Chassis", "ChassisType": "Module", } discovery_container.add_resource(ApiResource("/redfish/v1/Chassis/Module1", 'netloc', chassis1_0, "Chassis.v1_0_0.Chassis")) self.assertEqual(1, len(list(discovery_container.iter_all("Chassis.v1_2_0.Chassis")))) self.assertEqual(2, len(list(discovery_container.iter_all("Chassis.v1_0_0.Chassis")))) self.assertEqual(2, len(list(discovery_container.iter_all("Chassis.Chassis")))) self.assertEqual(2, len(list(discovery_container.iter_all("Resource.v1_0_0.Resource")))) self.assertEqual(2, len(list(discovery_container.iter_all("Resource.Resource"))))
def setUp(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/v1/Managers/RMC", 'netloc', RESOURCE, "#Manager.1.0.0.Manager"))
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_validate_elements_of_collection_with_elements_referenced_by_out_of_range_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": [ { "@odata.id": "/outer#MyCollection/0" }, { "@odata.id": "/outer#MyCollection/2" # pointer out of range } ] } 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.commons.api_caller.ApiCaller.get_resource') as get_resource: get_resource.side_effect = [(Link('url1', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url1', 'netloc')), (Link('url2', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url2', 'netloc')), (Link('url3', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url3', 'netloc'))] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(3, get_resource.call_count) self.assertIn( 'ERROR::JSON pointer exception while dereferencing /MyCollection/2', ';'.join(output)) requirements = [ ] validator = MetadataGetValidator(metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.PASSED, validator.validate(discovery_container)) self.assertEqual(0, len(re.findall('ERROR::', ';'.join(output))))
def setUp(self): self.discovery_container = DiscoveryContainer() metadata_manager = MetadataManager(["qualifier"]) self.metadata_container = metadata_manager.read_metadata_from_strings(METADATA) HardwareCheckList.MetadataConstants = MetadataConstants2_2 self.checklist = HardwareCheckList(dict()) #monkey patch self.checklist._load_metadata = lambda : self.metadata_container
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("Unknown", 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_should_pass_if_property_of_incorrect_type_declared_on_ignore_list(self): metadata_manager = MetadataManager(["qualifier"], ignore_types=["N.ObjectWithNumericProperty"]) 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_WITH_INVALID_PROPERTY_VALUE, "#N.R")) requirements = [ ] validator = MetadataGetValidator(self.metadata_container, requirements) self.assertEqual(ValidationStatus.PASSED, validator.validate(self.discovery_container))
def test_should_pass_if_entity_type_declared_on_ignore_list_with_asterix(self): metadata_manager = MetadataManager(['qualifier'], ignore_types=["N.*"]) 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_WITH_INVALID_PROPERTY_VALUE, '#N.R')) requirements = [] validator = MetadataGetValidator(self.metadata_container, requirements) self.assertEqual(ValidationStatus.PASSED, validator.validate(self.discovery_container))
def test_should_pass_when_unknown_complex_type_mapped_on_known_type(self): metadata_manager = MetadataManager(["qualifier"], map_types={"A" : "B", "unknown.complex.type" : "N.ObjectWithNumericProperty"}) 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_WITH_UNKNOWN_COMPLEX_TYPE, "#N.R")) requirements = [ ] validator = MetadataGetValidator(self.metadata_container, requirements) self.assertEqual(ValidationStatus.PASSED, validator.validate(self.discovery_container))
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_should_fail_bacause_of_unknown_complex_type(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_WITH_UNKNOWN_COMPLEX_TYPE, "#N.R")) requirements = [ ] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, validator.validate(self.discovery_container)) self.assertIn('Reference to unknown type unknown.complex.type', '\n'.join(output))
def test_should_fail_bacause_of_unknown_entity_type(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_WITH_UNKNOWN_ENTITY_TYPE, "#N.R")) requirements = [ ] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, validator.validate(self.discovery_container)) self.assertIn("ERROR::Unknown entity type 'unknown.entity.type'", output.raw)
def test_should_fail_if_property_of_incorrect_type(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_WITH_INVALID_PROPERTY_VALUE, "#N.R")) requirements = [ ] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, validator.validate(self.discovery_container)) self.assertIn('Property resource.id->ObjectWithNumber is expected to be json object', '\n'.join(output))
def test_should_validate_dynamic_properties_at_entity_level(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_WITH_INCOMPLETE_DYNAMIC_PROPERTY, "#N.R")) requirements = [ ] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, validator.validate(self.discovery_container)) self.assertIn('ERROR::Required property resource.id->aaaaaaaa->Obligatory not present in the resource', '\n'.join(output))
def test_should_fail_if_non_nullable_property_is_null(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_WITH_NULL_ON_NON_NULLABLE, "#N.R")) requirements = [ ] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, validator.validate(self.discovery_container)) self.assertIn('ERROR::Property resource.id->CapacityGiB cannot be null', '\n'.join(output)) self.assertIn('ERROR::Property resource.id->ObjectWithNumber->Number cannot be null', '\n'.join(output))
def test_should_pass_when_unknown_entity_type_mapped_to_known_one(self): metadata_manager = MetadataManager(["qualifier"], map_types={ "A": "B", "unknown.entity.type": "N.R" }) 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_WITH_UNKNOWN_ENTITY_TYPE, "#N.R")) requirements = [] validator = MetadataGetValidator(self.metadata_container, requirements) self.assertEqual(ValidationStatus.PASSED, validator.validate(self.discovery_container))
def test_should_fail_bacause_of_unknown_entity_type(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_WITH_UNKNOWN_ENTITY_TYPE, "#N.R")) requirements = [] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, validator.validate(self.discovery_container)) self.assertIn("ERROR::Unknown entity type 'unknown.entity.type'", output.raw)
def test_should_fail_bacause_of_unknown_complex_type(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_WITH_UNKNOWN_COMPLEX_TYPE, "#N.R")) requirements = [] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, validator.validate(self.discovery_container)) self.assertIn('Reference to unknown type unknown.complex.type', '\n'.join(output))
def test_property_invalid_collection(self): METADATA = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="MyNamespace.v1_0_0"> <EntityType Name="MyEntity"> <Property name="property_name" type="Collection(MyComplexType)"> </Property> </EntityType> <ComplexType Name="MyComplexType"> <Property Name="Name" Nullable="false" Type="Edm.String"/> </ComplexType> </Schema> """ discovery_container = DiscoveryContainer() metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings( "Unknown", METADATA) EntityJson = { "@odata.type": "MyNamespace.v1_0_0.MyEntity", "property_name": { 'a': { 'x': 1 }, 'b': { 'y': 2 } } } entity_type = EntityJson["@odata.type"] with StdoutCapture() as output: self.assertEqual( ValidationStatus.FAILED, metadata_container.entities[entity_type].validate( EntityJson, '')) self.assertIn( 'ERROR::Property ->property_name is expected to be collection, but it is not' '', output.raw)
def test_should_validate_dynamic_properties_at_entity_level(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_WITH_INCOMPLETE_DYNAMIC_PROPERTY, "#N.R")) requirements = [] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, validator.validate(self.discovery_container)) self.assertIn( 'ERROR::Required property resource.id->aaaaaaaa->Obligatory not present in the resource', '\n'.join(output))
def test_should_fail_if_property_of_incorrect_type(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_WITH_INVALID_PROPERTY_VALUE, "#N.R")) requirements = [] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, validator.validate(self.discovery_container)) self.assertIn( 'Property resource.id->ObjectWithNumber is expected to be json object', '\n'.join(output))
def test_should_suggest_other_names_for_additionals(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)) self.assertIn('Schema defines other, not used, but similar properties: [OptionalProperty1, OptionalProperty3]', '\n'.join(output)) self.assertIn( 'Schema defines other, not used, but similar properties: [OptionalPropertyInComplex1, OptionalPropertyInComplex3]', '\n'.join(output))
def test_discovery_can_handle_null_navigation_property(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </EntityType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "Link": { "@odata.id": None }, } 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) ] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output))
def test_should_pass_when_unknown_complex_type_mapped_on_known_type(self): metadata_manager = MetadataManager(["qualifier"], map_types={ "A": "B", "unknown.complex.type": "N.ObjectWithNumericProperty" }) self.metadata_container = metadata_manager.read_metadata_from_strings( METADATA) self.discovery_container = DiscoveryContainer() self.discovery_container.add_resource( ApiResource("/redfish/resource1", 'netloc', RESOURCE_WITH_UNKNOWN_COMPLEX_TYPE, "#N.R")) requirements = [] validator = MetadataGetValidator(self.metadata_container, requirements) self.assertEqual(ValidationStatus.PASSED, validator.validate(self.discovery_container))
def test_discovery_error_if_unexpected_additional_properties(self): """ Entity type used in this test does not accept additional properties. As a result, ApiExplorer is expected to raise an error about unexpected 'additional_property' property. ApiExplorer validate """ metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="@odata.id" Type="Edm.String"/> <Property Name="@odata.type" Type="Edm.String"/> <Property Name="expected" Type="Edm.Int64"/> <Annotation Term="OData.AdditionalProperties" Bool="false"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "id", "@odata.type": "N.Outer", "expected": 10, "additional_property": 1 } 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)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertIn("unexpected properties: [additional_property]", '\n'.join(output))
def test_discovery_error_if_unexpected_additional_properties(self): """ Entity type used in this test does not accept additional properties. As a result, ApiExplorer is expected to raise an error about unexpected 'additional_property' property. ApiExplorer validate """ metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="@odata.id" Type="Edm.String"/> <Property Name="@odata.type" Type="Edm.String"/> <Property Name="expected" Type="Edm.Int64"/> <Annotation Term="OData.AdditionalProperties" Bool="false"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "id", "@odata.type": "N.Outer", "expected": 10, "additional_property": 1 } 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)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertIn("unexpected properties: [additional_property]", '\n'.join(output))
def test_entity_sees_inherited_properties(self): metadata = """ <Schemas> <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="A"> <EntityType Name="Resource" Abstract="false"> <Property Name="GrandpaProperty" Type="Resource.Description"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </Property> </EntityType> </Schema> <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="B"> <EntityType Name="Resource" BaseType="A.Resource" Abstract="false"> <Property Name="DaddyProperty" Type="Resource.Id" Nullable="false"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </Property> </EntityType> </Schema> <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="C"> <EntityType Name="Resource" BaseType="B.Resource" Abstract="false"> <Property Name="KidProperty" Type="Resource.Id" Nullable="false"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </Property> </EntityType> </Schema> </Schemas> """ metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings( "Unknown", metadata) resource_definition = metadata_container.entities['C.Resource'] properties = resource_definition.properties self.assertIn('KidProperty', properties) self.assertIn('DaddyProperty', properties) self.assertIn('GrandpaProperty', properties)
def test_should_suggest_other_names_for_additionals(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)) self.assertIn( 'Schema defines other, not used, but similar properties: [OptionalProperty1, OptionalProperty3]', '\n'.join(output)) self.assertIn( 'Schema defines other, not used, but similar properties: [OptionalPropertyInComplex1, OptionalPropertyInComplex3]', '\n'.join(output))
def test_should_fail_if_non_nullable_property_is_null(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_WITH_NULL_ON_NON_NULLABLE, "#N.R")) requirements = [] validator = MetadataGetValidator(self.metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.FAILED, validator.validate(self.discovery_container)) self.assertIn( 'ERROR::Property resource.id->CapacityGiB cannot be null', '\n'.join(output)) self.assertIn( 'ERROR::Property resource.id->ObjectWithNumber->Number cannot be null', '\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_discovery_can_handle_null_navigation_property(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </EntityType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "Link": { "@odata.id": None }, } 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)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output))
def test_entity_sees_inherited_properties(self): metadata = """ <Schemas> <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="A"> <EntityType Name="Resource" Abstract="false"> <Property Name="GrandpaProperty" Type="Resource.Description"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </Property> </EntityType> </Schema> <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="B"> <EntityType Name="Resource" BaseType="A.Resource" Abstract="false"> <Property Name="DaddyProperty" Type="Resource.Id" Nullable="false"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </Property> </EntityType> </Schema> <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="C"> <EntityType Name="Resource" BaseType="B.Resource" Abstract="false"> <Property Name="KidProperty" Type="Resource.Id" Nullable="false"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </Property> </EntityType> </Schema> </Schemas> """ metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) resource_definition = metadata_container.entities['C.Resource'] properties = resource_definition.properties self.assertIn('KidProperty', properties) self.assertIn('DaddyProperty', properties) self.assertIn('GrandpaProperty', properties)
class MetadataManagerUnitTest(unittest.TestCase): def setUp(self): self.metadata_manager = MetadataManager(["qualifier"]) def test_entities_read(self): metadata_container = self.metadata_manager.read_metadata_from_strings( METADATA) self.assertIn(".".join([BASE_NAMESPACE_NAME, BASE_ENTITY_NAME]), metadata_container.entities) self.assertIn(".".join([DERIVED_NAMESPACE_NAME, DERIVED_ENTITY_NAME]), metadata_container.entities) def test_complex_type_read(self): metadata_container = self.metadata_manager.read_metadata_from_strings( METADATA) self.assertIn(".".join([BASE_NAMESPACE_NAME, BASE_COMPLEX_TYPE_NAME]), metadata_container.types) self.assertIn( ".".join([DERIVED_NAMESPACE_NAME, DERIVED_COMPLEX_TYPE_NAME]), metadata_container.types) self.assertIn( PROPERTY_NAME, metadata_container.entities[".".join( [DERIVED_NAMESPACE_NAME, DERIVED_ENTITY_NAME])].properties) self.assertIn( PROPERTY_NAME, metadata_container.entities[".".join( [BASE_NAMESPACE_NAME, BASE_ENTITY_NAME])].properties) self.assertEqual( ".".join([BASE_NAMESPACE_NAME, BASE_COMPLEX_TYPE_NAME]), metadata_container.types[".".join( [BASE_NAMESPACE_NAME, BASE_COMPLEX_TYPE_NAME])].properties[PROPERTY_NAME].type) self.assertEqual( ".".join([DERIVED_NAMESPACE_NAME, DERIVED_COMPLEX_TYPE_NAME]), metadata_container.types[".".join( [DERIVED_NAMESPACE_NAME, DERIVED_COMPLEX_TYPE_NAME])].properties[PROPERTY_NAME].type) def test_base_types(self): metadata_container = self.metadata_manager.read_metadata_from_strings( METADATA) self.assertEqual( metadata_container.entities[".".join([ BASE_NAMESPACE_NAME, BASE_ENTITY_NAME ])].validate( { "@odata.type": ".".join([DERIVED_NAMESPACE_NAME, DERIVED_ENTITY_NAME]), STRING_PROPERTY: "text", INT16_PROPERTY: 12, BOOLEAN_PROPERTY: True }, ""), ValidationStatus.PASSED) def test_follow_references_when_loading_local_matadata(self): MetadataManager.SERVICE_TO_DIR = {"SERVICE_A": "a"} os.path.isdir = MagicMock(return_value=True) manager = MetadataManager([]) with StdoutCapture() as output: with patch("__builtin__.open", mock_open(read_data=METADATA_ROOT)) as mock_file: with patch("cts_framework.commons.digest.DirDigest.__init__" ) as init: init.return_value = None with patch( "cts_framework.commons.digest.DirDigest.is_valid" ) as is_valid: is_valid.return_value = True manager.read_metadata_for_services("SERVICE_A") arguments = [arg[0][0] for arg in mock_file.call_args_list] self.assertGreater( len([a for a in arguments if "Org.OData.Core.V1.xml" in a]), 0) def test_follow_references_when_loading_remote_matadata(self): configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) manager = MetadataManager([]) with StdoutCapture() as output: with patch("cts_core.commons.api_caller.ApiCaller.get_xml" ) as get_xml: get_xml.side_effect = [ (None, RequestStatus.SUCCESS, 200, METADATA_ROOT, None), (None, RequestStatus.SUCCESS, 200, METADATA_ROOT, None) ] manager.download_metadata(configuration) arguments = [arg[0][0] for arg in get_xml.call_args_list] self.assertGreater( len([a for a in arguments if "Org.OData.Core.V1.xml" in a]), 0) self.assertEqual(-1, output.raw.find("ERROR::"))
class MetadataManagerUnitTest(unittest.TestCase): def setUp(self): self.metadata_manager = MetadataManager(["qualifier"]) def test_entities_read(self): metadata_container = self.metadata_manager.read_metadata_from_strings("Unknown", METADATA) self.assertIn(".".join([BASE_NAMESPACE_NAME, BASE_ENTITY_NAME]), metadata_container.entities) self.assertIn(".".join([DERIVED_NAMESPACE_NAME, DERIVED_ENTITY_NAME]), metadata_container.entities) def test_complex_type_read(self): metadata_container = self.metadata_manager.read_metadata_from_strings("Unknown", METADATA) self.assertIn(".".join([BASE_NAMESPACE_NAME, BASE_COMPLEX_TYPE_NAME]), metadata_container.types) self.assertIn(".".join([DERIVED_NAMESPACE_NAME, DERIVED_COMPLEX_TYPE_NAME]), metadata_container.types) self.assertIn(PROPERTY_NAME, metadata_container.entities[".".join([DERIVED_NAMESPACE_NAME, DERIVED_ENTITY_NAME])].properties) self.assertIn(PROPERTY_NAME, metadata_container.entities[".".join([BASE_NAMESPACE_NAME, BASE_ENTITY_NAME])].properties) self.assertEqual(".".join([BASE_NAMESPACE_NAME, BASE_COMPLEX_TYPE_NAME]), metadata_container.types[".".join([BASE_NAMESPACE_NAME, BASE_COMPLEX_TYPE_NAME])].properties[PROPERTY_NAME].type) self.assertEqual(".".join([DERIVED_NAMESPACE_NAME, DERIVED_COMPLEX_TYPE_NAME]), metadata_container.types[".".join([DERIVED_NAMESPACE_NAME, DERIVED_COMPLEX_TYPE_NAME])].properties[PROPERTY_NAME].type) def test_base_types(self): metadata_container = self.metadata_manager.read_metadata_from_strings("Unknown", METADATA) self.assertEqual(metadata_container.entities[".".join([BASE_NAMESPACE_NAME, BASE_ENTITY_NAME])].validate({ "@odata.type": ".".join([DERIVED_NAMESPACE_NAME, DERIVED_ENTITY_NAME]), STRING_PROPERTY: "text", INT16_PROPERTY: 12, BOOLEAN_PROPERTY: True }, ""), ValidationStatus.PASSED) def test_follow_references_when_loading_local_matadata(self): MetadataManager.SERVICE_TO_DIR = { "SERVICE_A": "a" } os.path.isdir = MagicMock(return_value=True) manager = MetadataManager([]) with StdoutCapture() as output: with patch("__builtin__.open", mock_open(read_data=METADATA_ROOT)) as mock_file: with patch("cts_framework.commons.digest.DirDigest.__init__") as init: init.return_value = None with patch("cts_framework.commons.digest.DirDigest.is_valid") as is_valid: is_valid.return_value = True manager.read_metadata_for_services("SERVICE_A") arguments = [arg[0][0] for arg in mock_file.call_args_list] self.assertGreater(len([a for a in arguments if "Org.OData.Core.V1.xml" in a]), 0) def test_follow_references_when_loading_remote_matadata(self): configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) manager = MetadataManager([]) with StdoutCapture() as output: with patch("cts_core.commons.api_caller.ApiCaller.get_xml") as get_xml: get_xml.side_effect = [(None, RequestStatus.SUCCESS, 200, METADATA_ROOT, None), (None, RequestStatus.SUCCESS, 200, METADATA_ROOT, None)] manager.download_metadata(configuration) arguments = [arg[0][0] for arg in get_xml.call_args_list] self.assertGreater(len([a for a in arguments if "Org.OData.Core.V1.xml" in a]), 0) self.assertEqual(-1, output.raw.find("ERROR::"))
def setUp(self): self.discovery_container = DiscoveryContainer() metadata_manager = MetadataManager(["qualifier"]) self.metadata_container = metadata_manager.read_metadata_from_strings("Unknown", AdditionalPropertiesPatchTest.METADATA) self.discovery_container = DiscoveryContainer()
def test_validate_elements_of_collection_with_elements_referenced_by_out_of_range_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": [ { "@odata.id": "/outer#MyCollection/0" }, { "@odata.id": "/outer#MyCollection/2" # pointer out of range } ] } 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.commons.api_caller.ApiCaller.get_resource' ) as get_resource: get_resource.side_effect = [ (Link('url1', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url1', 'netloc')), (Link('url2', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url2', 'netloc')), (Link('url3', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url3', 'netloc')) ] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(3, get_resource.call_count) self.assertIn( 'ERROR::JSON pointer exception while dereferencing /MyCollection/2', ';'.join(output)) requirements = [] validator = MetadataGetValidator(metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.PASSED, validator.validate(discovery_container)) self.assertEqual(0, len(re.findall('ERROR::', ';'.join(output))))
def setUp(self): metadata_manager = MetadataManager(["qualifier"]) self.metadata_container = metadata_manager.read_metadata_from_strings("Unknown", METADATA)
def test_handle_complex_types_with_dynamic_property_patterns(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="inner" Type="N.TypeWithDynamics"/> </EntityType> <ComplexType Name="TypeWithDynamics" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Annotation Term="Redfish.DynamicPropertyPatterns"> <Collection> <Record> <PropertyValue Property="Pattern" String="[a-z0-9]+"/> <PropertyValue Property="Type" String="N.Referenced"/> </Record> <Record> <PropertyValue Property="Pattern" String="[A-Z0-9]+"/> <PropertyValue Property="Type" String="Edm.String"/> </Record> </Collection> </Annotation> </ComplexType> <ComplexType Name="Referenced" Abstract="false"> <Property Name="name" Type="Edm.String"/> </ComplexType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "inner": { "additional1": { "name": "additional#1" }, "additional2": { "name": "additional#2" }, "ADDITIONAL3": "ADDITIONAL3", "ADDITIONAL4": "ADDITIONAL4", "SiMpLeTyPeIsOk": 22, "CoMpLeXInVaLiD": {"x": 1} } } 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('https://{API_ENDPOINT}/outer'.format( API_ENDPOINT=API_ENDPOINT), 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertEqual(1, len(re.findall('ERROR::', ';'.join(output)))) self.assertIn( 'ERROR::url=https://1.2.3.4:567/outer#inner.CoMpLeXInVaLiD: @odata.type not found in complex additional property;', ';'.join(output))
def setUp(self): metadata_manager = MetadataManager(["qualifier"]) self.metadata_container = metadata_manager.read_metadata_from_strings("Unknown", METADATA) self.discovery_container = DiscoveryContainer(metadata_container=self.metadata_container) self.validator = HierarchyValidator(self.discovery_container, self.metadata_container, MetadataConstants2_1) self.builder = ResourceBuilder(self.discovery_container)
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( 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), (Link('link', 'netloc'), RequestStatus.SUCCESS, referenced) ] 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_handle_complex_types_with_dynamic_property_patterns(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="inner" Type="N.TypeWithDynamics"/> </EntityType> <ComplexType Name="TypeWithDynamics" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Annotation Term="Redfish.DynamicPropertyPatterns"> <Collection> <Record> <PropertyValue Property="Pattern" String="[a-z0-9]+"/> <PropertyValue Property="Type" String="N.Referenced"/> </Record> <Record> <PropertyValue Property="Pattern" String="[A-Z0-9]+"/> <PropertyValue Property="Type" String="Edm.String"/> </Record> </Collection> </Annotation> </ComplexType> <ComplexType Name="Referenced" Abstract="false"> <Property Name="name" Type="Edm.String"/> </ComplexType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "inner": { "additional1": { "name": "additional#1" }, "additional2": { "name": "additional#2" }, "ADDITIONAL3": "ADDITIONAL3", "ADDITIONAL4": "ADDITIONAL4", "SiMpLeTyPeIsOk": 22, "CoMpLeXInVaLiD": {"x": 1} } } 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('https://{API_ENDPOINT}/outer'.format( API_ENDPOINT=API_ENDPOINT), 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertEqual(1, len(re.findall('ERROR::', ';'.join(output)))) self.assertIn( 'ERROR::url=https://1.2.3.4:567/outer#inner.CoMpLeXInVaLiD: @odata.type not found in complex additional property;', ';'.join(output))