Ejemplo n.º 1
0
    def run(self):
        if self.metadata_container is None:
            return

        test_name = "Storage Services CRUD test"
        print "MESSAGE::%s starting" % test_name

        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        self.discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI,
                                                                 MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        requirements = [
            Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1),
            Requirement(MetadataConstants.STORAGE_SERVICE, min=1),
            Requirement(MetadataConstants.LOGICAL_DRIVE_COLLECTION, min=1),
            Requirement(MetadataConstants.REMOTE_TARGET_COLLECTION, min=1),
            Requirement(MetadataConstants.LOGICAL_DRIVE, min=2)
        ]
        preconditions = Preconditions(self.metadata_container, requirements)
        status = preconditions.validate(self.discovery_container)

        if  status == ValidationStatus.FAILED:
            self.set_status_blocked()
            return

        self.api_caller = ApiCaller(self.configuration)

        status = ValidationStatus.join_statuses(status, self.crud_logical_drive())
        status = ValidationStatus.join_statuses(status, self.crud_remote_target())

        print "MESSAGE::%s overall status: %s" % (test_name, ColorPrinter.format_status(status))
Ejemplo n.º 2
0
    def run(self):
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        status = ValidationStatus.PASSED

        catalog = expanduser(
            "~"
        ) + "/.cts/tests/Rack_Scale_2_5_Storage_Services/required/tests_archeo_ss/"
        for test in listdir(catalog):
            with open(catalog + test) as f:
                data = json.load(f)
                test_name = data["name"]
                print "TEST_CASE::Validating section " + ColorPrinter.format_text(test_name,
                                                                                  color=ColorPrinter.YELLOW_FORE) + \
                      " of architecture specification"
                status_of_test = ArchSpecTests().parse_json(
                    discovery_container, data)
                if _skip_pnc_tests_if_resource_is_not_available(test) and \
                        (status_of_test == ValidationStatus.FAILED):
                    status = ValidationStatus.join_statuses(
                        status, ValidationStatus.PASSED_WITH_WARNINGS)
                    print "MESSAGE:: CTS can not detect a PNC. Skipping this tests"
                else:
                    status = ValidationStatus.join_statuses(
                        status, status_of_test)
                print "STATUS::{status}".format(status=status_of_test)
        print "MESSAGE::All tests finished"
        print "STATUS::{status}".format(status=status)
Ejemplo n.º 3
0
    def run(self):
        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)

        discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        print "TEST_CASE::Checking for mandatory entities"
        requirements = [
            Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1)
        ]
        preconditions = Preconditions(self.metadata_container, requirements)
        self.set_validation_status(preconditions.validate(discovery_container))

        validation_functions = [
            self.at_least_one_compute_module_in_pod,
            self.at_least_one_ethernet_switch_in_the_pod,
            self.ethernet_based_fabric_for_network_connectivity,
            self.secure_communication_channel, self.node_reset_support,
            self.manual_tests, self.validate_all_or_none_chassis_have_location,
            self.validate_path_using_contains_property,
            self.power_monitoring_support
        ]

        for validation_function in validation_functions:
            try:
                validation_function(discovery_container)
            except Exception as err:
                print "ERROR::Exception %s" % err
                self.set_validation_status(ValidationStatus.FAILED)

        print "SCREEN::Overall status: %s" % self.validation_status
Ejemplo n.º 4
0
    def run(self):
        if self.metadata_container is None:
            return

        self.chosen_endpoint, self.chosen_zone, self.chosen_volume, self.chosen_volume_collection = (None,)*4
        self.initiator_endpoint, self.target_endpoint, self.zone_endpoint, self.created_volume = (None,)*4

        test_name = "Storage Services CRUD test"
        print "MESSAGE::%s starting" % test_name

        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        self.discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI,
                                                                 MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        requirements = [
            Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1),
            Requirement(MetadataConstants.STORAGE_SERVICE, min=1),
            Requirement(MetadataConstants.VOLUME, min=1),
            Requirement(MetadataConstants.VOLUME_COLLECTION, min=1)
        ]
        preconditions = Preconditions(self.metadata_container, requirements)
        status = preconditions.validate(self.discovery_container)

        if status == ValidationStatus.FAILED:
            self.set_status_failed()
            return

        self.api_caller = ApiCaller(self.configuration)

        status = ValidationStatus.join_statuses(status, self.crud_fabrics_target())

        print "MESSAGE::%s overall status: %s" % (test_name, ColorPrinter.format_status(status))
Ejemplo n.º 5
0
    def run(self):
        try:
            json_loader = JsonLoader()
        except OSError:
            print('ERROR:: No proper action found. Please reinstall a CTS')
            return

        if self.metadata_container is None:
            return

        if not self.configuration.UseCase:
            json_loader.print_available_actions()
            return

        try:
            actions_to_take = json_loader.get_use_case(
                self.configuration.UseCase)
            specific_action = json_loader.get_use_case_action(
                actions_to_take['filepath'])
        except (IndexError, TypeError):
            json_loader.print_available_actions()
            print('ERROR:: The selected action was not found. Exiting..')
            return

        print('TEST_CASE::API crawling')
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        self.discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        configuration = self.configuration
        self.api_caller = ApiCaller(configuration)

        print('TEST_CASE::Action Runner')
        status = self.action_runner(specific_action)
        print('STATUS::{status}'.format(status=status))
Ejemplo n.º 6
0
    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))
Ejemplo n.º 7
0
    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))
Ejemplo n.º 8
0
    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))))
Ejemplo n.º 9
0
    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))))
Ejemplo n.º 10
0
    def run(self):
        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        detected_profile = ValidateProfiles(discovery_container)
        detected_profile.validate()
Ejemplo n.º 11
0
    def run(self):
        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        MetadataGetValidator(
            self.metadata_container,
            RequiredTypes_PSME_2_1).validate(discovery_container)
    def run(self):
        metadata_manager = MetadataManager(self.configuration)
        metadata_manager.load_files()
        metadata_container = metadata_manager.load_metadata_properties()

        api_explorer = ApiExplorer("/redfish/v1/", "ServiceRoot.ServiceRoot", metadata_container, self.configuration)
        discovery_container = api_explorer.process_with_resource(DiscoveryContainer())
        discovery_container.keys()
        status = MetadataPatchValidator(metadata_container, self.configuration).validate(discovery_container)
        self.set_status(status)
Ejemplo n.º 13
0
    def run(self):
        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI,
                                                            MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        requirements = [
            Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1)
        ]
        MetadataGetValidator(self.metadata_container, requirements).validate(discovery_container)
Ejemplo n.º 14
0
    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))))
Ejemplo n.º 15
0
    def run(self):
        if self.metadata_container is None:
            return

        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI,
                                                            MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        MetadataGetValidator(self.metadata_container, RequiredTypes_Storage_2_4).validate(discovery_container)
        performance_status = self._measuring_request_responses(api_explorer)
        print("STATUS::{status}".format(status=performance_status))
Ejemplo n.º 16
0
    def run(self):
        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)

        discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        validator = MetadataPatchValidator(self.metadata_container,
                                           self.configuration,
                                           PatchingStrategy2_1(),
                                           RequiredTypes_Storage_2_1)
        validator.validate(discovery_container)
Ejemplo n.º 17
0
    def run(self):
        if self.metadata_container is None:
            return

        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI,
                                                            MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        MetadataGetValidator(self.metadata_container, RequiredTypes_Storage_2_4).validate(discovery_container)
        performance_status = self._measuring_request_responses(api_explorer)
        print("STATUS::{status}".format(status=performance_status))
Ejemplo n.º 18
0
    def run(self):
        print self.configuration.__dict__
        metadata_manager = MetadataManager(self.configuration)
        metadata_manager.load_files()
        metadata_container = metadata_manager.load_metadata_properties()

        api_explorer = ApiExplorer("/redfish/v1/", "ServiceRoot.ServiceRoot", metadata_container, self.configuration)
        discovery_container = api_explorer.process_with_resource(DiscoveryContainer())
        discovery_container.keys()
        status = MetadataPatchValidator(metadata_container, self.configuration).validate(discovery_container)
        if status:
            self.set_status_passed()
        else:
            self.set_status_failed()
Ejemplo n.º 19
0
    def run(self):
        if self.metadata_container is None:
            return

        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        MetadataGetValidator(
            self.metadata_container,
            RequiredTypes_PSME_2_3,
            skip_check_predicate=SkipCheckPredicate_PSME_2_3).validate(
                discovery_container)
Ejemplo n.º 20
0
    def run(self):
        if self.metadata_container is None:
            return

        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)

        discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI,
                                                            MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        validator = MetadataPatchValidator(self.metadata_container, self.configuration,
                                           PatchingStrategy2_4(), RequiredTypes_PODM_2_4,
                                           skip_list=self.configuration.IgnoredElements)
        validator.validate(discovery_container)
        performance_status = self._measuring_request_responses(api_explorer)
        print("STATUS::{status}".format(status=performance_status))
Ejemplo n.º 21
0
    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))
Ejemplo n.º 22
0
    def run(self):
        metadata_manager = MetadataManager(self.configuration)
        metadata_manager.load_files()
        metadata_container = metadata_manager.load_metadata_properties()

        api_explorer = ApiExplorer("/redfish/v1/", "ServiceRoot.ServiceRoot",
                                   metadata_container, self.configuration)

        discovery_container = api_explorer.process_with_resource(
            DiscoveryContainer())

        status = MetadataGetValidator(metadata_container).validate(
            discovery_container)

        if status:
            self.set_status_passed()
        else:
            self.set_status_failed()
Ejemplo n.º 23
0
    def run(self):
        if self.metadata_container is None:
            return

        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)

        discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        requirements = [
            Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1)
        ]
        validator = MetadataPatchValidator(self.metadata_container,
                                           self.configuration,
                                           PatchingStrategy2_1(), requirements)
        validator.validate(discovery_container)
Ejemplo n.º 24
0
    def post_resource(self, url, discovery_container, payload=None, acceptable_return_codes=None,
                      wait_if_async=True, expect_location=None, api_endpoint_override=None):
        """
        Sends http POST request to remote endpoint.
        Throws AsyncOperation if service created task in response to this request.

        :type url: str
        :type discovery_container: DiscoveryContainer
        :type payload: dict
        :type acceptable_return_codes: list(int)
        :type wait_if_async: bool
        """
        from cts_core.discovery.api_explorer import ApiExplorer

        if expect_location is None:
            expect_location = True

        _, status, status_code, response_body, headers = \
            self._perform_call(url,
                               http_method=HttpMethods.POST,
                               payload=payload,
                               acceptable_return_codes=acceptable_return_codes,
                               api_endpoint_override=api_endpoint_override)
        # determine if the operation was completed synchronously or asynchronously
        if status_code == ReturnCodes.ACCEPTED:
            if not wait_if_async:
                raise AsyncOperation()
            status, status_code, response_body, headers = self._wait_for_task(headers,
                                                                              discovery_container,
                                                                              acceptable_ret_codes=acceptable_return_codes)

        if expect_location and status and not self._skip_refresh_after_request(url):
            try:
                # add the created element and discover all its children
                new_url = self.links_factory.get_resource_link(headers["Location"],
                                                               api_endpoint_override=api_endpoint_override).link
                print "MESSAGE::Refreshing {} info".format(new_url)
                # refresh the collection info
                _, get_status, get_status_code, _, _ = self.get_resource(url, discovery_container,
                                                                         api_endpoint_override=api_endpoint_override,
                                                                         check_resource_against_metadata=True)
                _, rediscovery_status = ApiExplorer(discovery_container.metadata_container,
                                                    self._config_property_reader).discover(new_url,
                                                                                           discovery_container.get_expected_odata_type_for_url(new_url),
                                                                                           discovery_container)
                if get_status and rediscovery_status:
                    print "MESSAGE::Refreshed %s and its children info" % new_url
                else:
                    cts_warning("Refreshing {odata_id:id} after POST generated errors. Get status code: {code}",
                                odata_id=new_url, code=get_status_code)

            except (KeyError, TypeError) as err:
                cts_warning(
                    "POST {odata_id:id} Response has no 'Location' header; Error: {err:exception}",
                    odata_id=url, err=err)

        return status, status_code, response_body, headers
Ejemplo n.º 25
0
    def run(self):
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI,
                                                            MetadataConstants.SERVICE_ROOT)
        status = ValidationStatus.PASSED

        catalog = expanduser("~") + "/.cts/tests/Rack_Scale_2_5_PSME/required/tests_archeo_psme/"
        for test in listdir(catalog):
            with open(catalog + test) as f:
                data = json.load(f)
                test_name = data["name"]
                print "TEST_CASE::Validating section " + ColorPrinter.format_text(test_name,
                                                                                  color=ColorPrinter.YELLOW_FORE) + \
                      " of architecture specification"
                status_of_test = ArchSpecTests().parse_json(discovery_container, data)
                print "STATUS::{status}".format(status=status_of_test)
                status = ValidationStatus.join_statuses(status, status_of_test)
        print "MESSAGE::All tests finished"
        print "STATUS::{status}".format(status=status)
Ejemplo n.º 26
0
    def run(self):
        if self.metadata_container is None:
            return

        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)

        self.discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        requirements = [
            Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1),
        ]
        preconditions = Preconditions(self.metadata_container, requirements)
        status = preconditions.validate(self.discovery_container)

        self.api_caller = ApiCaller(self.configuration)
        self.crud_vlan()
Ejemplo n.º 27
0
    def run(self):
        if self.metadata_container is None:
            return

        self.chosen_endpoint, self.chosen_zone, self.chosen_volume, self.chosen_volume_collection = (
            None, ) * 4
        self.initiator_endpoint, self.target_endpoint, self.zone_endpoint, self.created_volume = (
            None, ) * 4

        self.initiator_unique_name = self.generate_unique_names() if self.configuration.UniqueInitiatorName \
            != "generate" else self.configuration.UniqueInitiatorName
        self.target_unique_name = self.generate_unique_names() if self.configuration.UniqueTargetName \
            != "generate" else self.configuration.UniqueTargetName

        test_name = "Storage Services CRUD test with NVM Express (NVMe) Support"
        print "MESSAGE::%s starting" % test_name

        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        self.discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        requirements = [
            Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1),
            Requirement(MetadataConstants.STORAGE_SERVICE, min=1),
            Requirement(MetadataConstants.VOLUME, min=1),
            Requirement(MetadataConstants.VOLUME_COLLECTION, min=1)
        ]
        preconditions = Preconditions(self.metadata_container, requirements)
        status = preconditions.validate(self.discovery_container)

        if status == ValidationStatus.FAILED:
            self.set_status_failed()
            return

        self.api_caller = ApiCaller(self.configuration)

        status = ValidationStatus.join_statuses(status, self.crud_nvme())

        print "MESSAGE::%s overall status: %s" % (
            test_name, ColorPrinter.format_status(status))
Ejemplo n.º 28
0
    def run(self):
        if self.metadata_container is None:
            return

        print "TEST_CASE::API crawling"

        api_explorer = ApiExplorer(self.metadata_container, self.configuration)

        self.discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI,
                                                                 MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        requirements = [
            Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1),
        ]
        preconditions = Preconditions(self.metadata_container, requirements)
        status = preconditions.validate(self.discovery_container)

        self.api_caller = ApiCaller(self.configuration)
        self.crud_vlan()
Ejemplo n.º 29
0
    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))
Ejemplo n.º 30
0
    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))
Ejemplo n.º 31
0
    def run(self):
        json_loader = JsonLoader()
        if self.metadata_container is None:
            return

        if not self.configuration.UseCase:
            json_loader.print_available_actions()
            return

        actions_to_take = json_loader.get_use_case(self.configuration.UseCase)
        specific_action = json_loader.get_use_case_action(actions_to_take['filepath'])

        print('TEST_CASE::API crawling')
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        self.discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI,
                                                                 MetadataConstants.SERVICE_ROOT)
        configuration = self.configuration
        self.api_caller = ApiCaller(configuration)

        print('TEST_CASE::Action Runner')
        status = self.action_runner(specific_action)
        print('STATUS::{status}'.format(status=status))
Ejemplo n.º 32
0
    def run(self):
        json_loader = JsonLoader()
        if self.metadata_container is None:
            return

        if not self.configuration.UseCase:
            json_loader.print_available_actions()
            return

        actions_to_take = json_loader.get_use_case(self.configuration.UseCase)
        specific_action = json_loader.get_use_case_action(
            actions_to_take['filepath'])

        print('TEST_CASE::API crawling')
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)
        self.discovery_container, status = api_explorer.discover(
            MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT)
        configuration = self.configuration
        self.api_caller = ApiCaller(configuration)

        print('TEST_CASE::Action Runner')
        status = self.action_runner(specific_action)
        print('STATUS::{status}'.format(status=status))
Ejemplo n.º 33
0
    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))
Ejemplo n.º 34
0
    def run(self):
        if self.metadata_container is None:
            return

        print "TEST_CASE::API crawling"
        api_explorer = ApiExplorer(self.metadata_container, self.configuration)

        discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI,
                                                            MetadataConstants.SERVICE_ROOT)
        print "STATUS::{status}".format(status=status)

        print "TEST_CASE::Checking for mandatory entities"
        requirements = [
            Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1)
        ]
        preconditions = Preconditions(self.metadata_container, requirements)
        self.set_validation_status(preconditions.validate(discovery_container))

        validation_functions = [self.at_least_one_compute_module_in_pod,
                                self.at_least_one_ethernet_switch_in_the_pod,
                                self.ethernet_based_fabric_for_network_connectivity,
                                self.secure_communication_channel,
                                self.node_reset_support,
                                self.manual_tests,
                                self.validate_all_or_none_chassis_have_location,
                                self.validate_path_using_contains_property,
                                self.power_monitoring_support]

        for validation_function in validation_functions:
            try:
                validation_function(discovery_container)
            except Exception as err:
                cts_error("Exception {err:exception}", err=err)
                self.set_validation_status(ValidationStatus.FAILED)

        print "SCREEN::Overall status: %s" % self.validation_status
Ejemplo n.º 35
0
class ApiExplorerUnitTest(unittest.TestCase):
    def setUp(self):
        config_property_parser = Mock()
        config_property_parser.ApiEndpoint = ""
        config_property_parser.UseSSL = "Yes"
        self.api_explorer = ApiExplorer(None, config_property_parser)

    def test_visited_endpoint(self):
        discovery_container = DiscoveryContainer()
        discovery_container.add_resource(ApiResource("http://*****:*****@odata.type': 'type.of.b',
                'inner': [
                    {'@odata.type': 'type.of.first.inner'},
                    {'@odata.type': 'type.of.second.inner'}
                ]
            }, None))
        link, status, body, _ = self.api_explorer._get_resource("/a/b#inner/0")
        self.assertEqual(RequestStatus.SUCCESS, status)
        self.assertEqual({'@odata.type': 'type.of.first.inner'}, body)

    def test_discovery_from_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"/>
                </EntityType>

                <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",
                "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_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_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_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_handle_entities_with_dynamic_property_patterns(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"/>
                            <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="N.Referenced"/>
                                    </Record>
                                </Collection>
                            </Annotation>
                        </EntityType>

                        <ComplexType Name="Referenced" Abstract="false">
                            <Property Name="name" Type="Edm.String"/>
                        </ComplexType>
                    </Schema>
                    """

        resource = \
            {
                "@odata.id": "resource.id",
                "@odata.type": "N.Outer",
                "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#CoMpLeXInVaLiD: @odata.type not found in '
                'complex additional property;',
                output.raw)

    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 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))))
Ejemplo n.º 36
0
 def setUp(self):
     config_property_parser = Mock()
     config_property_parser.ApiEndpoint = ""
     config_property_parser.UseSSL = "Yes"
     self.api_explorer = ApiExplorer(None, config_property_parser)
Ejemplo n.º 37
0
    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))))
Ejemplo n.º 38
0
    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))
Ejemplo n.º 39
0
    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))
Ejemplo n.º 40
0
 def setUp(self):
     config_property_parser = Mock()
     config_property_parser.ApiEndpoint = ""
     config_property_parser.UseSSL = "Yes"
     self.api_explorer = ApiExplorer(None, config_property_parser)
Ejemplo n.º 41
0
class ApiExplorerUnitTest(unittest.TestCase):
    def setUp(self):
        config_property_parser = Mock()
        config_property_parser.ApiEndpoint = ""
        config_property_parser.UseSSL = "Yes"
        self.api_explorer = ApiExplorer(None, config_property_parser)

    def test_visited_endpoint(self):
        discovery_container = DiscoveryContainer()
        discovery_container.add_resource(ApiResource("http://*****:*****@odata.type': 'type.of.b',
                'inner': [
                    {'@odata.type': 'type.of.first.inner'},
                    {'@odata.type': 'type.of.second.inner'}
                ]
            }, None))
        link, status, body, _ = self.api_explorer._get_resource("/a/b#inner/0")
        self.assertEqual(RequestStatus.SUCCESS, status)
        self.assertEqual({'@odata.type': 'type.of.first.inner'}, body)

    def test_get_resource_with_odata(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))
        link, status, body, _ = self.api_explorer._get_resource("/redfish/a/b#inner/3")
        self.assertEqual(RequestStatus.SUCCESS, status)
        self.assertEqual({'@odata.id': '/redfish/a/b#inner/3'}, body)

    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)

    def test_discovery_from_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"/>
                </EntityType>

                <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",
                "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_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_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))

    @unittest.skip("Temporary change related to bug in Discovery mechanism")
    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_handle_entities_with_dynamic_property_patterns(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"/>
                            <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="N.Referenced"/>
                                    </Record>
                                </Collection>
                            </Annotation>
                        </EntityType>

                        <ComplexType Name="Referenced" Abstract="false">
                            <Property Name="name" Type="Edm.String"/>
                        </ComplexType>
                    </Schema>
                    """

        resource = \
            {
                "@odata.id": "resource.id",
                "@odata.type": "N.Outer",
                "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#CoMpLeXInVaLiD: @odata.type not found in '
                'complex additional property;',
                output.raw)

    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 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))))