Example #1
0
    def _validate_additional_property(self, property_name, property_value, resource_path, unused_properties):
        if self.allow_additional_properties:
            print "DEBUG::Additional property {resource_path}->{property_name}".format(
                resource_path=resource_path, property_name=property_name)
            try_suggest_other_property_names(name=property_name, candidates=unused_properties)

            odata_type = match_dynamic_property(property_name, self)
            if odata_type is None:
                try:
                    odata_type = get_odata_type(property_value)
                except KeyError:
                    if isinstance(property_value, dict):
                        cts_error("Property {path}->{property_name} is of complex type without @odata_type",
                                  path=resource_path, property_name=property_name)
                        return ValidationStatus.FAILED
                    else:
                        return ValidationStatus.PASSED

            mapped_odata_type = self.metadata_container.map_type(odata_type)

            # assuming all aditional properties are nullable
            if property_value is None:
                return ValidationStatus.PASSED

            if not self.metadata_container.to_be_ignored(odata_type, mapped_odata_type):
                return self.metadata_container.types[odata_type].validate(
                    property_value, resource_path + '->' + property_name)
            else:
                return ValidationStatus.PASSED
        else:
            cts_error("Property {resource_path}->{property_name} is present, but not defined in metadata. " \
                      "Type {type_name} does not allow additional properties",
                      resource_path=resource_path, property_name=property_name, type_name=self.name)
            try_suggest_other_property_names(name=property_name, candidates=unused_properties)
            return ValidationStatus.FAILED
Example #2
0
    def _validate_additional_property(self, property_name, property_value, resource_path, unused_properties):
        if self.allow_additional_properties:
            print "DEBUG::Additional property {odata_id}->{property_name}" \
                .format(odata_id=resource_path, property_name=property_name)
            try_suggest_other_property_names(name=property_name, candidates=unused_properties)

            odata_type = match_dynamic_property(property_name, self)
            if odata_type is None:
                try:
                    odata_type = get_odata_type(property_value)
                except KeyError:
                    if isinstance(property_value, dict):
                        cts_error("Property {odata_id:id}->{key} is of complex type without @odata_type",
                                  odata_id=resource_path, key=property_name)
                        return ValidationStatus.FAILED
                    else:
                        return ValidationStatus.PASSED
            mapped_odata_type = self.metadata_container.map_type(odata_type)
            if not self.metadata_container.to_be_ignored(odata_type, mapped_odata_type):
                return self.metadata_container.types[mapped_odata_type].validate(
                    property_value,
                    resource_path + '->' + property_name)
        else:
            cts_error("Property {odata_id:id}->{property_name} is present, but not defined in metadata. "
                      "Entity {entity_name} does not allow additional properties",
                      odata_id=resource_path, property_name=property_name, entity_name=self.name)
            try_suggest_other_property_names(name=property_name, candidates=unused_properties)

            status = ValidationStatus.FAILED
Example #3
0
    def validate(self, resource, resource_path, annotations=None):
        """
        :type annotations: dict
        :type resource: dict
        :type resource_path: str
        :rtype: str
        """
        try:
            odata_type = self.metadata_container.map_type(get_odata_type(resource))
            mapped_odata_type = self.metadata_container.map_type(odata_type)
            if self.metadata_container.to_be_ignored(odata_type, mapped_odata_type):
                return ValidationStatus.PASSED
        except KeyError:
            pass #this is legal that complex type does not have odata.type specified

        types_consistency_validation_status, complex_type_name = self.validate_types_consistency(resource, resource_path)
        if self.metadata_container.to_be_ignored(complex_type_name):
            return ValidationStatus.PASSED

        if complex_type_name == self.name:
            resource_validation_status = self.validate_properties(resource, resource_path)
        else:
            try:
                resource_validation_status = self.metadata_container.types[complex_type_name].validate(resource, resource_path)
            except KeyError:
                resource_validation_status = ValidationStatus.FAILED
            except Exception as err:
                import traceback
                cts_error("{path} - exception {err:exceptions}: {stack:stacktrace}",
                          path=resource_path, err=err, stack=traceback.format_exc())
                resource_validation_status = ValidationStatus.FAILED

        return ValidationStatus.join_statuses(types_consistency_validation_status, resource_validation_status)
Example #4
0
    def _validate_types_consistency(self,
                                    resource,
                                    resource_path,
                                    odata_type=None):
        """
        :type resource: dict
        :type resource_path: str
        :type odata_type: str
        :return: validation_status, type that will be validated
        :rtype: str, str
        """
        if not odata_type:
            try:
                odata_type = get_odata_type(resource)
            except KeyError:
                odata_type = None

        if not odata_type:
            cts_warning("Missing odata.type property in {odata_id:id}",
                        odata_id=resource_path)
            return ValidationStatus.PASSED_WITH_WARNINGS, self.name
        else:
            reported_odata_type = self.metadata_container.map_type(odata_type)
            if self.metadata_container.to_be_ignored(odata_type,
                                                     reported_odata_type):
                return ValidationStatus.PASSED, reported_odata_type

        try:
            if self.is_compatible(reported_odata_type):
                msg = (
                    "DEBUG::Resource {odata_id} reported entity type {reported_odata_type}, "
                    +
                    "expected type {expected_entity_type}, types are consistent"
                ).format(odata_id=resource_path,
                         reported_odata_type=reported_odata_type,
                         expected_entity_type=self.name)
                print msg

                return ValidationStatus.PASSED, reported_odata_type
            else:
                cts_error(
                    "Resource {odata_id:id} reported entity type {reported_odata_type}, "
                    +
                    "expected type {expected_entity_type}, types are not consistent",
                    odata_id=resource_path,
                    reported_odata_type=reported_odata_type,
                    expected_entity_type=self.name)

                return ValidationStatus.FAILED, reported_odata_type
        except KeyError:
            cts_error(
                "Resource {odata_id:id} reported unknown entity type {reported_odata_type},"
                +
                "will process validation with expected entity type {expected_entity_type}",
                odata_id=resource_path,
                reported_odata_type=reported_odata_type,
                expected_entity_type=self.name)

            return ValidationStatus.FAILED, reported_odata_type
Example #5
0
    def _process_complex_type(self, property_description, body, url, path):
        try:
            # use override @odata.type if present.
            # At this stage do not verify if override type is consistent with type from property_description;
            # This will be validated in validate_get_responses test
            odata_type = get_odata_type(body)
        except KeyError:
            odata_type = property_description.type

        type_definition = self._metadata_container.types[odata_type]
        self._process_properties(body, type_definition, url, path)
    def _validate_property_list(self, context, variable_path, property_list):
        """
        :type context: Context
        :type variable_path: list [str or int]
        :type property_list: list[cts_core.metadata.model.property.Property]
        :rtype: str
        """
        api_resource = context.api_resource

        status = ValidationStatus.PASSED
        # use local copy - api resource will be modified while test is executed
        local_property_list = list(property_list)
        for property_description in local_property_list:
            status = ValidationStatus.join_statuses(
                self._validate_property(context, variable_path,
                                        property_description), status)

        # validate additional properties
        try:
            body = api_resource.get_value_from_path(variable_path)
        except KeyError as key:
            cts_warning("Unable to access {odataid:id}->{path}. Key={key}",
                        odataid=api_resource.odata_id,
                        path="->".join(variable_path),
                        key=key)
            body = None

        if body is not None:
            all_properties = set(body.keys())
            known_properties = set(
                [property.name for property in local_property_list])
            additional_properties = all_properties - known_properties
            for additional_property_name in additional_properties:
                property_value = body[additional_property_name]
                if isinstance(property_value,
                              dict) and "@odata.type" in property_value:
                    raw_soup = """
                    <Property Name="{name}" Type="{type}">
                        <Annotation Term="OData.Permissions"
                                    EnumMember="OData.Permission/ReadWrite"/>
                    </Property>
                    """
                    soup = BeautifulSoup(
                        raw_soup.format(name=additional_property_name,
                                        type=get_odata_type(property_value)),
                        "lxml").find_all("property")[0]

                    adhoc_description = Property(self._metadata_container,
                                                 None, soup)
                    status = ValidationStatus.join_statuses(
                        self._validate_property(context, variable_path,
                                                adhoc_description), status)

        return status
Example #7
0
    def validate(self,
                 resource,
                 resource_path,
                 annotations=None,
                 odata_type=None):
        """
        :type annotations: dict
        :type resource: dict
        :type resource_path: str
        :type odata_type: str
        :rtype: str
        """
        if not odata_type:
            try:
                odata_type = get_odata_type(resource)
            except KeyError:
                odata_type = None

        if not odata_type:
            cts_warning(
                "Resource {odata_id} did not report odata.type property",
                odata_id=resource_path)
            return ValidationStatus.PASSED_WITH_WARNINGS
        else:
            mapped_odata_type = self.metadata_container.map_type(odata_type)
            if self.metadata_container.to_be_ignored(odata_type,
                                                     mapped_odata_type):
                return ValidationStatus.PASSED

        types_consistency_validation_status, entity_type = self._validate_types_consistency(
            resource, resource_path, odata_type)

        if entity_type == self.name:
            resource_validation_status = self._validate_container(
                resource, resource_path)
        else:
            try:
                resource_validation_status = self.metadata_container.entities[
                    entity_type]._validate_container(resource, resource_path)
            except KeyError:
                resource_validation_status = ValidationStatus.FAILED
            except Exception as error:
                cts_error("{id:id} Unexpected error: {error:exception}",
                          id == resource_path,
                          error=error)
                resource_validation_status = ValidationStatus.FAILED

        return ValidationStatus.join_statuses(
            types_consistency_validation_status, resource_validation_status)
Example #8
0
    def validate_types_consistency(self, container, path):
        """
        :type container: dict
        :type path: str
        :return: validation_status, type that will be validated
        :rtype: str, str
        """
        try:
            odata_type = get_odata_type(container)
        except KeyError:
            odata_type = self.name
        reported_odata_type = self.metadata_container.map_type(odata_type)
        if self.metadata_container.to_be_ignored(odata_type, reported_odata_type):
            return ValidationStatus.PASSED, reported_odata_type

        if reported_odata_type == self.name:
            return ValidationStatus.PASSED, self.name

        try:
            if self.is_compatible(reported_odata_type):
                msg = ("DEBUG::Resource {resource_path} reported type {reported_odata_type}, " +
                       "expected type {expected_type}, types are consistent").format(
                    resource_path=path, reported_odata_type=reported_odata_type, expected_type=self.name)
                print msg

                return ValidationStatus.PASSED, reported_odata_type
            else:
                cts_error("Resource {resource_path} reported type {reported_odata_type}, " +
                          "expected type {expected_type}, types are not consistent",
                          resource_path=path, reported_odata_type=reported_odata_type, expected_type=self.name)

                print "MESSAGE::Setting results to ERROR, but will process validation with reported complex type " + \
                      "{reported_odata_type}".format(reported_odata_type=reported_odata_type)

                return ValidationStatus.FAILED, reported_odata_type
        except KeyError:
            cts_error("Resource {resource_path} reported unknown type {reported_odata_type}," +
                      "will process validation with expected entity type {expected_type}",
                      resource_path=path, reported_odata_type=reported_odata_type, expected_type=self.name)

            return ValidationStatus.FAILED, self.name
        except AttributeError:
            cts_error("Resource {resource_path} reported itself as not complex type {reported_type}",
                      resource_path=path, reported_type=reported_odata_type)

            return ValidationStatus.FAILED, self.name
Example #9
0
    def _validate_types_consistency(self, resource, resource_path, odata_type=None):
        """
        :type resource: dict
        :type resource_path: str
        :type odata_type: str
        :return: validation_status, type that will be validated
        :rtype: str, str
        """
        if not odata_type:
            try:
                odata_type = get_odata_type(resource)
            except KeyError:
                odata_type = None

        if not odata_type:
            cts_warning("Missing odata.type property in {odata_id:id}", odata_id=resource_path)
            return ValidationStatus.PASSED_WITH_WARNINGS, self.name
        else:
            reported_odata_type = self.metadata_container.map_type(odata_type)
            if self.metadata_container.to_be_ignored(odata_type, reported_odata_type):
                return ValidationStatus.PASSED, reported_odata_type

        try:
            if self.is_compatible(reported_odata_type):
                msg = ("DEBUG::Resource {odata_id} reported entity type {reported_odata_type}, " +
                       "expected type {expected_entity_type}, types are consistent").format(
                    odata_id=resource_path, reported_odata_type=reported_odata_type, expected_entity_type=self.name)
                print msg

                return ValidationStatus.PASSED, reported_odata_type
            else:
                cts_error("Resource {odata_id:id} reported entity type {reported_odata_type}, " +
                          "expected type {expected_entity_type}, types are not consistent",
                          odata_id=resource_path,
                          reported_odata_type=reported_odata_type,
                          expected_entity_type=self.name)

                return ValidationStatus.FAILED, reported_odata_type
        except KeyError:
            cts_error("Resource {odata_id:id} reported unknown entity type {reported_odata_type}," +
                      "will process validation with expected entity type {expected_entity_type}",
                      odata_id=resource_path,
                      reported_odata_type=reported_odata_type,
                      expected_entity_type=self.name)

            return ValidationStatus.FAILED, reported_odata_type
Example #10
0
    def _append_additional_properties(self, property_list, body,
                                      type_definition, url, path):
        additionals = set(body.keys()) - set(
            [property.name for property in property_list])
        # filter out special properties (properties that contain @ and #)
        additionals = filter(
            lambda property: not is_special_property(property), additionals)

        if len(additionals) > 0:
            if type_definition.allow_additional_properties:
                for property_name in additionals:
                    # process only objects
                    try:
                        property_value = body[property_name]
                        if isinstance(property_value, dict):
                            odata_type = match_dynamic_property(
                                property_name, type_definition)
                            if odata_type is None:
                                try:
                                    odata_type = get_odata_type(property_value)
                                except KeyError as key:
                                    cts_error(
                                        "{url:id}#{path}: @odata.type not found in complex "
                                        "additional property",
                                        url=url,
                                        path=path.append(property_name))
                                    continue

                            adhoc_description = self.ad_hoc_type_definition(
                                property_name, odata_type)
                            property_list.append(adhoc_description)
                    except KeyError:
                        pass
            else:
                cts_error(
                    "{url:id}#{path}: Object of type {type}; unexpected properties: [{"
                    "properties}]",
                    type=type_definition.name,
                    properties=", ".join(additionals),
                    url=url,
                    path=path)
                self._status = ValidationStatus.FAILED
Example #11
0
    def validate(self, resource, resource_path, annotations=None, odata_type=None):
        """
        :type annotations: dict
        :type resource: dict
        :type resource_path: str
        :type odata_type: str
        :rtype: str
        """
        if not odata_type:
            try:
                odata_type = get_odata_type(resource)
            except KeyError:
                odata_type = None

        if not odata_type:
            cts_warning("Resource {odata_id} did not report odata.type property", odata_id=resource_path)
            return ValidationStatus.PASSED_WITH_WARNINGS
        else:
            mapped_odata_type = self.metadata_container.map_type(odata_type)
            if self.metadata_container.to_be_ignored(odata_type, mapped_odata_type):
                return ValidationStatus.PASSED

        types_consistency_validation_status, entity_type = self._validate_types_consistency(resource,
                                                                                            resource_path,
                                                                                            odata_type)

        if entity_type == self.name:
            resource_validation_status = self._validate_container(resource, resource_path)
        else:
            try:
                resource_validation_status = self.metadata_container.entities[entity_type]._validate_container(resource,
                                                                                                               resource_path)
            except KeyError:
                resource_validation_status = ValidationStatus.FAILED
            except Exception as error:
                cts_error("{id:id} Unexpected error: {error:exception}", id==resource_path, error=error)
                resource_validation_status = ValidationStatus.FAILED

        return ValidationStatus.join_statuses(types_consistency_validation_status, resource_validation_status)