Esempio n. 1
0
def test_publish_message_validator_factory_invalid_ack_fails_validation(
    faker: Faker, ):
    with_validation: Decorator = publish_message_validator_factory(
        message=Message(
            name=faker.word(),
            payload={
                "type": "object",
                "properties": {
                    "hello": {
                        "type": "string"
                    }
                },
            },
            x_ack=MessageAck(
                args={
                    "type": "object",
                    "properties": {
                        "acknowledged": {
                            "type": "string"
                        }
                    },
                    "required": ["acknowledged"],
                }),
        ))

    @with_validation
    def handler(message: Mapping) -> Mapping[str, str]:
        assert "hello" in message
        return {"not-acknowledged": faker.pystr()}

    with pytest.raises(MessageAckValidationException):
        handler({"hello": faker.pystr()})
Esempio n. 2
0
def test_validate_ack_args_with_tuple_schema_and_multiple_invalid_args(
    faker: Faker, ):
    with pytest.raises(MessageAckValidationException):
        validate_ack_args(
            ({
                "hello": faker.pystr()
            }, faker.pyint()),
            MessageAck(
                args={
                    "type":
                    "array",
                    "prefixItems": [
                        {
                            "type": "object",
                            "properties": {
                                "hello": {
                                    "type": "string"
                                }
                            },
                        },
                        {
                            "type": "string"
                        },
                    ],
                }),
        )
Esempio n. 3
0
def test_publish_message_validator_factory_validates_valid_args_and_acks_successfully(
    faker: Faker, ):
    with_validation: Decorator = publish_message_validator_factory(
        message=Message(
            name=faker.word(),
            payload={
                "type": "object",
                "properties": {
                    "hello": {
                        "type": "string"
                    }
                },
            },
            x_ack=MessageAck(
                args={
                    "type": "object",
                    "properties": {
                        "acknowledged": {
                            "type": "string"
                        }
                    },
                    "required": ["acknowledged"],
                }),
        ))

    @with_validation
    def handler(message: Mapping) -> Mapping[str, str]:
        assert "hello" in message
        return {"acknowledged": faker.pystr()}

    handler({"hello": faker.pystr()})
    assert True
Esempio n. 4
0
def test_make_subscription_task_with_no_message_payload_but_ack(
        server_info: Info, faker: Faker):
    namespace = f"/{faker.pystr()}"
    message = Message(
        name=faker.word(),
        x_ack=MessageAck(args={
            "type": "string",
            "enum": [faker.pystr(), faker.pystr()],
        }),
    )
    spec = AsyncApiSpec(
        asyncapi=faker.pystr(),
        info=server_info,
        channels={
            namespace:
            Channel(subscribe=Operation(message=OneOfMessages(
                one_of=[message]), ))
        },
    )
    server = new_mock_asynction_socket_io(spec)
    task = server.make_subscription_task(message=message, namespace=namespace)

    with patch.object(server, "emit") as emit_mock:
        task()
        emit_mock.assert_called_once_with(message.name,
                                          None,
                                          namespace=namespace,
                                          callback=_noop_handler)
Esempio n. 5
0
def test_validate_ack_args_with_tuple_schema_and_multiple_valid_args(
    faker: Faker, ):
    validate_ack_args(
        ({
            "hello": faker.pystr()
        }, faker.pyint()),
        MessageAck(
            args={
                "type":
                "array",
                "prefixItems": [
                    {
                        "type": "object",
                        "properties": {
                            "hello": {
                                "type": "string"
                            }
                        }
                    },
                    {
                        "type": "number"
                    },
                ],
            }),
    )
    assert True
Esempio n. 6
0
def test_publish_message_validator_factory_skips_ack_validation_if_handler_returns_none(
    faker: Faker, ):
    with_validation: Decorator = publish_message_validator_factory(
        message=Message(
            name=faker.word(),
            payload={
                "type": "object",
                "properties": {
                    "hello": {
                        "type": "string"
                    }
                },
            },
            x_ack=MessageAck(
                args={
                    "type": "object",
                    "properties": {
                        "acknowledged": {
                            "type": "string"
                        }
                    },
                    "required": ["acknowledged"],
                }),
        ))

    @with_validation
    def handler(message: Mapping) -> None:
        assert "hello" in message

    handler({"hello": faker.pystr()})
    assert True
Esempio n. 7
0
def test_validate_ack_args_with_array_schema_and_single_valid_arg(
    faker: Faker, ):
    validate_ack_args(
        (faker.pylist(value_types=[str]), ),
        MessageAck(args={
            "type": "array",
            "items": {
                "type": "string"
            },
        }),
    )
    assert True
Esempio n. 8
0
def test_validate_ack_args_with_array_schema_and_single_invalid_arg(
    faker: Faker, ):
    with pytest.raises(MessageAckValidationException):
        validate_ack_args(
            (faker.pylist(value_types=[int]), ),
            MessageAck(args={
                "type": "array",
                "items": {
                    "type": "string"
                },
            }),
        )
        assert True
Esempio n. 9
0
def test_validate_ack_args_with_single_object_schema_and_multiple_valid_args(
    faker: Faker, ):
    with pytest.raises(MessageAckValidationException):
        validate_ack_args(
            tuple([{
                "hello": faker.pystr()
            }] * faker.pyint(min_value=2, max_value=10)),
            MessageAck(args={
                "type": "object",
                "properties": {
                    "hello": {
                        "type": "string"
                    }
                },
            }),
        )
Esempio n. 10
0
def test_validate_ack_args_with_single_object_schema_and_single_invalid_arg(
    faker: Faker, ):
    with pytest.raises(MessageAckValidationException):
        validate_ack_args(
            ({
                "hello": faker.pyint()
            }, ),
            MessageAck(args={
                "type": "object",
                "properties": {
                    "hello": {
                        "type": "string"
                    }
                }
            }),
        )
Esempio n. 11
0
def test_validate_ack_args_with_single_object_schema_and_single_valid_arg(
    faker: Faker, ):
    validate_ack_args(
        ({
            "hello": faker.pystr()
        }, ),
        MessageAck(args={
            "type": "object",
            "properties": {
                "hello": {
                    "type": "string"
                }
            }
        }),
    )
    assert True
Esempio n. 12
0
def test_register_handlers_registers_valid_handler_for_message_with_ack(
        server_info: Info, faker: Faker):
    namespace = f"/{faker.pystr()}"
    event_name = faker.word()
    ack_schema = {
        "type": "object",
        "properties": {
            "foo": {
                "type": "string",
                "enum": [faker.pystr(), faker.pystr()],
            },
            "bar": {
                "type": "number",
                "minimum": 10,
                "maximum": 20,
            },
        },
        "required": ["foo", "bar"],
    }
    spec = AsyncApiSpec(
        asyncapi=faker.pystr(),
        info=server_info,
        channels={
            namespace:
            Channel(publish=Operation(message=OneOfMessages(one_of=[
                Message(
                    name=event_name,
                    payload={"type": "object"},
                    x_handler=faker.pystr(),
                    x_ack=MessageAck(args=ack_schema),
                )
            ]), ))
        },
    )
    server = new_mock_asynction_socket_io(spec)

    server._register_handlers()
    assert len(server.handlers) == 2  # connect handler included as well
    registered_event, registered_handler, registered_namespace = server.handlers[
        0]
    assert registered_event == event_name
    assert registered_namespace == namespace
    handler = deep_unwrap(registered_handler)

    ack = handler(faker.pydict())
    jsonschema.validate(ack, ack_schema)
    assert True
Esempio n. 13
0
def test_make_subscription_task_with_message_payload_and_ack(
        server_info: Info, faker: Faker):
    namespace = f"/{faker.pystr()}"
    message = Message(
        name=faker.word(),
        payload={
            "type": "object",
            "properties": {
                "foo": {
                    "type": "string",
                    "enum": [faker.pystr(), faker.pystr()],
                },
                "bar": {
                    "type": "number",
                    "minimum": 10,
                    "maximum": 20,
                },
            },
            "required": ["foo", "bar"],
        },
        x_ack=MessageAck(args={
            "type": "string",
            "enum": [faker.pystr(), faker.pystr()],
        }),
    )
    spec = AsyncApiSpec(
        asyncapi=faker.pystr(),
        info=server_info,
        channels={
            namespace:
            Channel(subscribe=Operation(message=OneOfMessages(
                one_of=[message]), ))
        },
    )
    server = new_mock_asynction_socket_io(spec)
    task = server.make_subscription_task(message=message, namespace=namespace)

    with patch.object(server, "emit") as emit_mock:
        task()
        emit_mock.assert_called_once_with(message.name,
                                          ANY,
                                          namespace=namespace,
                                          callback=_noop_handler)
        _, data = emit_mock.call_args[0]
        jsonschema.validate(data, message.payload)
        assert True
Esempio n. 14
0
def test_emit_event_wraps_callback_with_validator(super_method_mock: mock.Mock,
                                                  server_info: Info,
                                                  faker: Faker):
    namespace = f"/{faker.pystr()}"
    event_name = faker.pystr()
    spec = AsyncApiSpec(
        asyncapi=faker.pystr(),
        info=server_info,
        channels={
            namespace:
            Channel(subscribe=Operation(message=OneOfMessages(one_of=[
                Message(
                    name=event_name,
                    payload={"type": "number"},
                    x_ack=MessageAck(args={"type": "boolean"}),
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)

    def actual_callback(*args):
        # dummy callback

        pass

    server.emit(event_name,
                faker.pyint(),
                namespace=namespace,
                callback=actual_callback)
    super_method_mock.assert_called_once()
    *_, kwargs = super_method_mock.call_args
    callback_with_validation = kwargs["callback"]

    callback_args = [faker.pystr()
                     ]  # invalid callback args (should have been a boolean)

    # actual callback has no validation -- hence it does not fail
    actual_callback(*callback_args)

    with pytest.raises(MessageAckValidationException):
        callback_with_validation(*callback_args)
Esempio n. 15
0
def test_register_handlers_adds_ack_validator_if_validation_is_enabled(
        server_info: Info, faker: Faker):
    namespace = f"/{faker.pystr()}"
    event_name = faker.word()
    spec = AsyncApiSpec(
        asyncapi=faker.pystr(),
        info=server_info,
        channels={
            namespace:
            Channel(publish=Operation(message=OneOfMessages(one_of=[
                Message(
                    name=event_name,
                    payload={"type": "string"},
                    x_handler="tests.fixtures.handlers.ping_with_ack",
                    x_ack=MessageAck(
                        args={
                            "type": "object",
                            "properties": {
                                "ack": {
                                    "type": "number"
                                }
                            },
                            "required": ["ack"],
                        }),
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)

    server._register_handlers()
    _, registered_handler, _ = server.handlers[0]
    handler_with_validation = deep_unwrap(registered_handler, depth=1)
    actual_handler = deep_unwrap(handler_with_validation)
    args = (faker.pystr(), )  # valid handler args

    # actual handler does not raise validation errors, although it returns invalid data
    actual_handler(*args)

    with pytest.raises(MessageAckValidationException):
        handler_with_validation(*args)
Esempio n. 16
0
def test_callback_validator_factory_invalid_callback_args_fail_validation(
    faker: Faker, ):
    with_validation: Decorator = callback_validator_factory(message=Message(
        name=faker.word(),
        x_ack=MessageAck(
            args={
                "type": "object",
                "properties": {
                    "acknowledged": {
                        "type": "string"
                    }
                },
                "required": ["acknowledged"],
            }),
    ))

    @with_validation
    def callback(message: Mapping) -> None:
        assert "not-acknowledged" in message

    with pytest.raises(MessageAckValidationException):
        callback({"not-acknowledged": faker.pystr()})
Esempio n. 17
0
def test_callback_validator_factory_validates_valid_callback_args_successfully(
    faker: Faker, ):
    with_validation: Decorator = callback_validator_factory(message=Message(
        name=faker.word(),
        x_ack=MessageAck(
            args={
                "type": "object",
                "properties": {
                    "acknowledged": {
                        "type": "string"
                    }
                },
                "required": ["acknowledged"],
            }),
    ))

    @with_validation
    def callback(message: Mapping) -> None:
        assert "acknowledged" in message

    callback({"acknowledged": faker.pystr()})
    assert True