Example #1
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))
Example #2
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))))
Example #3
0
    def test_empty_body(self):
        self.api_explorer._get_resource = MagicMock(
            return_value=(Link('link', 'netloc'), RequestStatus.SUCCESS, {}))

        with StdoutCapture() as output:
            self.api_explorer.discover("odata_id", None)

        self.assertIn('Empty response body', '\n'.join(output))
Example #4
0
    def test_correct_body_processing(self):
        discovery_container = DiscoveryContainer()
        self.api_explorer._metadata_container = MagicMock()
        self.api_explorer._get_resource = MagicMock(return_value=(Link('link', 'netloc'),
                                                                  RequestStatus.SUCCESS,
                                                                  dict(a=1),
                                                                  None))
        self.api_explorer._process_resource = MagicMock(return_value=discovery_container)

        self.api_explorer.discover("url", None)
        self.api_explorer._process_resource.assert_called_once_with(ANY)
Example #5
0
 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)
Example #6
0
 def test_get_resource(self):
     self.api_explorer._api_caller.get_resource = MagicMock(
         return_value=(
             Link('link', 'netloc'),
             RequestStatus.SUCCESS, None, {
             '@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)
Example #7
0
 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)
Example #8
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))
Example #9
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))
Example #10
0
 def test_ssl_default(self):
     configuration = Configuration(**dict(ApiEndpoint=API_ENDPOINT))
     url, kwargs = ApiCaller(configuration)._build_request(RESOURCE)
     self.assertEqual(url, Link("http://%s%s" % (API_ENDPOINT, RESOURCE), API_ENDPOINT))
Example #11
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))))
Example #12
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))
    def test_patch_nontrivial_boot_property(self):
        metadata_manager = MetadataManager(["qualifier"])
        this_dir = os.path.dirname(os.path.realpath(__file__))
        metadata_dir = os.path.join(this_dir, 'metadata')
        self.assertTrue(metadata_manager.read_metadata_from_dir(metadata_dir))
        metadata_container = metadata_manager.metadata_container

        entity_json = {
            "@odata.context":
            "/redfish/v1/$metadata#ComputerSystem.ComputerSystem",
            "@odata.id": "/redfish/v1/Systems/34",
            "@odata.type": "#ComputerSystem.v1_3_0.ComputerSystem",
            "Id": "34",
            "Name": "Computer System",
            "Description": "Computer System description",
            "SystemType": "Physical",
            "AssetTag": "AZaz09[]!@#$%^&*()_+",
            "Manufacturer": None,
            "Model": None,
            "SKU": None,
            "SerialNumber": None,
            "PartNumber": None,
            "UUID": "1d7a1040-05e4-11e6-a108-54ab3a8ec80f",
            "HostName": None,
            "Status": {
                "State": "Enabled",
                "Health": "OK",
                "HealthRollup": "OK"
            },
            "IndicatorLED": None,
            "PowerState": "Off",
            "BiosVersion": "F20A3A03",
            "Boot": {
                "@odata.type":
                "#ComputerSystem.v1_1_0.Boot",
                "BootSourceOverrideEnabled":
                "Disabled",
                "BootSourceOverrideTarget":
                "None",
                "*****@*****.**":
                ["Hdd", "Pxe", "None", "RemoteDrive"],
                "BootSourceOverrideMode":
                "Legacy",
                "*****@*****.**":
                ["Legacy", "UEFI"]
            },
            "ProcessorSummary": {
                "Count": 2,
                "Model": "Intel(R) Xeon(R)",
                "Status": {
                    "State": "Enabled",
                    "Health": "OK",
                    "HealthRollup": "OK"
                }
            },
            "MemorySummary": {
                "TotalSystemMemoryGiB": 30.52,
                "Status": {
                    "State": "Enabled",
                    "Health": "OK",
                    "HealthRollup": "OK"
                }
            },
            "Processors": {
                "@odata.id": "/redfish/v1/Systems/34/Processors"
            },
            "EthernetInterfaces": {
                "@odata.id": "/redfish/v1/Systems/34/EthernetInterfaces"
            },
            "NetworkInterfaces": {
                "@odata.id": "/redfish/v1/Systems/34/NetworkInterfaces"
            },
            "Storage": {
                "@odata.id": "/redfish/v1/Systems/34/Storage"
            },
            "Memory": {
                "@odata.id": "/redfish/v1/Systems/34/Memory"
            },
            "PCIeDevices": [],
            "PCIeFunctions": [],
            "TrustedModules": [],
            "Links": {
                "@odata.type": "#ComputerSystem.v1_2_0.Links",
                "Chassis": [{
                    "@odata.id": "/redfish/v1/Chassis/38"
                }],
                "Endpoints": [],
                "ManagedBy": [{
                    "@odata.id": "/redfish/v1/Managers/38"
                }],
                "Oem": {}
            },
            "Actions": {
                "#ComputerSystem.Reset": {
                    "target":
                    "/redfish/v1/Systems/34/Actions/ComputerSystem.Reset",
                    "*****@*****.**": [
                        "On", "ForceOff", "GracefulShutdown",
                        "GracefulRestart", "ForceRestart"
                    ]
                },
                "Oem": {
                    "#Intel.Oem.ChangeTPMState": {
                        "target":
                        "/redfish/v1/Systems/34/Actions/Oem/Intel.Oem.ChangeTPMState",
                        "*****@*****.**": []
                    }
                }
            },
            "Oem": {
                "Intel_RackScale": {
                    "@odata.type": "#Intel.Oem.ComputerSystem",
                    "PciDevices": [],
                    "PCIeConnectionId": [],
                    "ProcessorSockets": 2,
                    "MemorySockets": 16,
                    "DiscoveryState": "Basic",
                    "UserModeEnabled": None,
                    "TrustedExecutionTechnologyEnabled": None,
                    "Metrics": {
                        "@odata.id": "/redfish/v1/Systems/34/Metrics"
                    }
                }
            }
        }

        self.discovery_container.add_resource(
            ApiResource("/redfish/v1/Systems/34", "https://localhost:8443",
                        entity_json, "#ComputerSystem.v1_3_0.ComputerSystem"))

        with mock.patch('cts_core.commons.api_caller.ApiCaller.__init__'
                        ) as api_caller_init_mock:
            api_caller_init_mock.return_value = None
            validator = MetadataPatchValidator(metadata_container, None,
                                               PatchingStrategy2_2())

            # this ValidationStatus.BLOCKED should be not affect final ValidationStatus
            validator._verify_property = MagicMock(
                return_value=(ValidationStatus.PASSED, None))
            validator._restore_property = MagicMock(
                return_value=ValidationStatus.PASSED)
            validator._patch_property = MagicMock(
                return_value=(True, True, ValidationStatus.PASSED))

            with mock.patch(
                    'cts_core.commons.api_caller.ApiCaller.patch_resource'
            ) as api_caller_patch_resource:
                api_caller_patch_resource.return_value = (
                    RequestStatus.SUCCESS, 200, None, None)
                with mock.patch(
                        'cts_core.commons.api_caller.ApiCaller.get_resource'
                ) as api_caller_get_resource:
                    api_caller_get_resource.return_value = (Link(
                        "/redfish/v1/Systems/34",
                        "https://localhost:8443"), RequestStatus.SUCCESS, 200,
                                                            entity_json, None)

                    with StdoutCapture() as out:
                        self.assertEqual(
                            ValidationStatus.PASSED,
                            validator.validate(self.discovery_container))

                    self.assertNotIn('WARNING::Skipping non-trivial property',
                                     out.raw)