示例#1
0
    def add(self, defn):
        """Adds the given Command Definition to this Command Dictionary."""
        if defn.name not in self:
            self[defn.name] = defn
        else:
            msg = "Duplicate Command name '%s'" % defn.name
            log.error(msg)
            raise util.YAMLError(msg)

        if defn._opcode not in self.opcodes:
            self.opcodes[defn._opcode] = defn
        else:
            msg = "Duplicate Command opcode '%s'" % defn._opcode
            log.error(msg)
            raise util.YAMLError(msg)
示例#2
0
 def add(self, defn):
     """Adds the given Packet Definition to this Telemetry Dictionary."""
     if defn.name not in self:
         self[defn.name] = defn
     else:
         msg = f"Duplicate packet name {defn.name}"
         log.error(msg)
         raise util.YAMLError(msg)
示例#3
0
 def add(self, defn):
     if defn.name not in self and defn.code not in self.codes:
         self[defn.name] = defn
         self.codes[defn.code] = defn
     else:
         msg = "EVRDict: Duplicate EVR name/code {}".format(defn)
         log.error(msg)
         raise util.YAMLError(msg)
示例#4
0
    def schema_val(self, messages=None):
        "Perform validation with processed YAML and Schema"
        self._ymlproc = YAMLProcessor(self._ymlfile)
        self._schemaproc = SchemaProcessor(self._schemafile)
        valid = True

        log.debug(
            "BEGIN: Schema-based validation for YAML '%s' with schema '%s'",
            self._ymlfile,
            self._schemafile,
        )

        # Make sure the yml and schema have been loaded
        if self._ymlproc.loaded and self._schemaproc.loaded:
            # Load all of the yaml documents. Could be more than one in the same YAML file.
            for docnum, data in enumerate(
                    yaml.load_all(self._ymlproc.data, Loader=yaml.Loader)):

                # Since YAML allows integer keys but JSON does not, we need to first
                # dump the data as a JSON string to encode all of the potential integers
                # as strings, and then read it back out into the YAML format. Kind of
                # a clunky workaround but it works as expected.
                data = yaml.load(json.dumps(data), Loader=yaml.Loader)

                # Now we want to get a validator ready
                v = jsonschema.Draft4Validator(self._schemaproc.data)

                # Loop through the errors (if any) and set valid = False if any are found
                # Display the error message
                for error in v.iter_errors(data):
                    msg = ("Schema-based validation failed for YAML file '" +
                           self._ymlfile + "'")
                    self.ehandler.process(docnum, self._ymlproc.doclines,
                                          error, messages)
                    valid = False

                if not valid:
                    log.error(msg)

        elif not self._ymlproc.loaded:
            raise util.YAMLError("YAML must be loaded in order to validate.")
        elif not self._schemaproc.loaded:
            raise jsonschema.SchemaError(
                "Schema must be loaded in order to validate.")

        log.debug("END: Schema-based validation complete for '%s'",
                  self._ymlfile)
        return valid
示例#5
0
    def process(self, ymlfile):
        """Cleans out all document tags from the YAML file to make it
        JSON-friendly to work with the JSON Schema.
        """
        output = ""

        try:
            # Need a list of line numbers where the documents resides
            # Used for finding/displaying errors
            self.doclines = []
            linenum = None
            with open(ymlfile, "r") as txt:
                for linenum, line in enumerate(txt):
                    # Pattern to match document start lines
                    doc_pattern = re.compile(r"(---) (![a-z]+)(.*$)",
                                             flags=re.I)

                    # Pattern to match sequence start lines
                    seq_pattern = re.compile(r"(\s*)(-+) !([a-z]+)(.*$)",
                                             flags=re.I)

                    # If we find a document, remove the tag
                    if doc_pattern.match(line):
                        line = doc_pattern.sub(r"---", line).lower()
                        self.doclines.append(linenum)
                    elif seq_pattern.match(line):
                        # Replace the sequence start with key string
                        line = seq_pattern.sub(
                            r"\1\2 \3: line " + str(linenum), line).lower()

                    output = output + line

            if linenum is None:
                msg = "Empty YAML file: " + ymlfile
                raise util.YAMLError(msg)
            else:
                # Append one more document to docline for the end
                self.doclines.append(linenum + 1)

            return output

        except IOError as e:
            msg = "Could not process YAML file '" + ymlfile + "': '" + str(
                e) + "'"
            raise IOError(msg)
示例#6
0
    def load(self, ymlfile=None):
        """Load and process the YAML file"""
        if ymlfile is not None:
            self.ymlfile = ymlfile

        try:
            # If yaml should be 'cleaned' of document references
            if self._clean:
                self.data = self.process(self.ymlfile)
            else:
                with open(self.ymlfile, "rb") as stream:
                    for data in yaml.load_all(stream, Loader=yaml.Loader):
                        self.data.append(data)

            self.loaded = True
        except ScannerError as e:
            msg = "YAML formattting error - '" + self.ymlfile + ": '" + str(
                e) + "'"
            raise util.YAMLError(msg)
示例#7
0
def test_YAMLError_exception(log_mock):
    message = "foo"
    e = util.YAMLError(message)
    assert message == e.message
    log_mock.assert_called_with(message)
示例#8
0
    def content_val(self, ymldata=None, messages=None):
        """Validates the Command Dictionary to ensure the contents for each of the fields
        meets specific criteria regarding the expected types, byte ranges, etc."""

        self._ymlproc = YAMLProcessor(self._ymlfile, False)

        # Turn off the YAML Processor
        log.debug("BEGIN: Content-based validation of Command dictionary")
        if ymldata is not None:
            cmddict = ymldata
        elif ymldata is None and self._ymlproc.loaded:
            cmddict = self._ymlproc.data
        elif not self._ymlproc.loaded:
            raise util.YAMLError("YAML failed to load.")

        try:
            # instantiate the document number. this will increment in order to
            # track the line numbers and section where validation fails
            docnum = 0

            # boolean to hold argument validity
            argsvalid = True

            # list of rules to validate against
            rules = []

            ### set the command rules
            #
            # set uniqueness rule for command names
            rules.append(
                UniquenessRule('name', "Duplicate command name: %s", messages))

            # set uniqueness rule for opcodes
            rules.append(
                UniquenessRule('opcode', "Duplicate opcode: %s", messages))
            #
            ###
            for cmdcnt, cmddefn in enumerate(cmddict[0]):
                # check the command rules
                for rule in rules:
                    rule.check(cmddefn)

                # list of argument rules to validate against
                argrules = []

                ### set rules for command arguments
                #
                # set uniqueness rule for opcodes
                argrules.append(
                    UniquenessRule(
                        'name',
                        "Duplicate argument name: " + cmddefn.name + ".%s",
                        messages))

                # set type rule for arg.type
                argrules.append(
                    TypeRule(
                        'type', "Invalid argument type for argument: " +
                        cmddefn.name + ".%s", messages))

                # set argument size rule for arg.type.nbytes
                argrules.append(
                    TypeSizeRule(
                        'nbytes', "Invalid argument size for argument: " +
                        cmddefn.name + ".%s", messages))

                # set argument enumerations rule to check no enumerations contain un-quoted YAML special variables
                argrules.append(
                    EnumRule(
                        'enum', "Invalid enum value for argument: " +
                        cmddefn.name + ".%s", messages))

                # set byte order rule to ensure proper ordering of aruguments
                argrules.append(
                    ByteOrderRule(
                        'bytes', "Invalid byte order for argument: " +
                        cmddefn.name + ".%s", messages))
                #
                ###

                argdefns = cmddefn.argdefns
                for arg in argdefns:
                    # check argument rules
                    for rule in argrules:
                        rule.check(arg)

                # check if argument rule failed, if so set the validity to False
                if not all(r.valid is True for r in argrules):
                    argsvalid = False

            log.debug("END: Content-based validation complete for '%s'",
                      self._ymlfile)

            # check validity of all command rules and argument validity
            return all(rule.valid is True for rule in rules) and argsvalid

        except util.YAMLValidationError, e:
            # Display the error message
            if messages is not None:
                if len(e.message) < 128:
                    msg = "Validation Failed for YAML file '" + self._ymlfile + "': '" + str(
                        e.message) + "'"
                else:
                    msg = "Validation Failed for YAML file '" + self._ymlfile + "'"

                log.error(msg)
                self.ehandler.process(docnum, self.ehandler.doclines, e,
                                      messages)
                return False