Esempio n. 1
0
def test_creating_exception_from_call_error():
    call_error = CallError(unique_id="1337",
                           error_code="ProtocolError",
                           error_description="Something went wrong",
                           error_details="Some details about the error")

    assert call_error.to_exception() == ProtocolError(
        description="Something went wrong",
        details="Some details about the error")
Esempio n. 2
0
def unpack(msg):
    """
    Unpacks a message into either a Call, CallError or CallResult.
    """
    try:
        msg = json.loads(msg)
    except json.JSONDecodeError as e:
        raise FormatViolationError(f'Message is not valid JSON: {e}')

    if not isinstance(msg, list):
        raise ProtocolError("OCPP message hasn't the correct format. It "
                            f"should be a list, but got {type(msg)} instead")

    for cls in [Call, CallResult, CallError]:
        try:
            if msg[0] == cls.message_type_id:
                return cls(*msg[1:])
        except IndexError:
            raise ProtocolError("Message doesn\'t contain MessageTypeID")

    raise PropertyConstraintViolationError(f"MessageTypeId '{msg[0]}' isn't "
                                           "valid")
Esempio n. 3
0
def test_exception_with_error_details():
    exception = ProtocolError("Some error", {'key': 'value'})

    assert exception.description == "Some error"
    assert exception.details == {'key': 'value'}
Esempio n. 4
0
def test_exception_without_error_details():
    exception = ProtocolError()

    assert exception.description == "Payload for Action is incomplete"
    assert exception.details == {}
Esempio n. 5
0
def validate_payload(message, ocpp_version):
    """ Validate the payload of the message using JSON schemas. """
    if type(message) not in [Call, CallResult]:
        raise ValidationError("Payload can't be validated because message "
                              f"type. It's '{type(message)}', but it should "
                              "be either 'Call'  or 'CallResult'.")

    try:
        # 3 OCPP 1.6 schedules have fields of type floats. The JSON schema
        # defines a certain precision for these fields of 1 decimal. A value of
        # 21.4 is valid, whereas a value if 4.11 is not.
        #
        # The problem is that Python's internal representation of 21.4 might
        # have more than 1 decimal. It might be 21.399999999999995. This would
        # make the validation fail, although the payload is correct. This is a
        # known issue with jsonschemas, see:
        # https://github.com/Julian/jsonschema/issues/247
        #
        # This issue can be fixed by using a different parser for floats than
        # the default one that is used.
        #
        # Both the schema and the payload must be parsed using the different
        # parser for floats.
        if ocpp_version == '1.6' and (
            (type(message) == Call and
                message.action in ['SetChargingProfile', 'RemoteStartTransaction'])  # noqa
            or
            (type(message) == CallResult and
                message.action == 'GetCompositeSchedule')
        ):
            validator = get_validator(
                message.message_type_id, message.action,
                ocpp_version, parse_float=decimal.Decimal
            )

            message.payload = json.loads(
                json.dumps(message.payload), parse_float=decimal.Decimal
            )
        else:
            validator = get_validator(
                message.message_type_id, message.action, ocpp_version
            )
    except (OSError, json.JSONDecodeError) as e:
        raise ValidationError("Failed to load validation schema for action "
                              f"'{message.action}': {e}")

    try:
        validator.validate(message.payload)
    except SchemaValidationError as e:
        if (e.validator == SchemaValidators.type.__name__):
            raise TypeConstraintViolationError(details={"cause": e.message})
        elif (e.validator == SchemaValidators.additionalProperties.__name__):
            raise FormatViolationError(details={"cause": e.message})
        elif (e.validator == SchemaValidators.required.__name__):
            raise ProtocolError(details={"cause": e.message})
        elif e.validator == "maxLength":
            raise TypeConstraintViolationError(
                details={"cause": e.message}) from e
        else:
            raise ValidationError(f"Payload '{message.payload} for action "
                                  f"'{message.action}' is not valid: {e}")