示例#1
0
def test_emit_validiation_is_ignored_if_validation_flag_is_false(
        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"},
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, False, True, [], None, None)

    event_args = [faker.pystr()]  # invalid args
    server.emit(event_name, *event_args, namespace=namespace)

    # super method called because validation was skipped
    super_method_mock.assert_called_once_with(event_name,
                                              *event_args,
                                              namespace=namespace)
示例#2
0
def test_emit_event_with_tuple_payload_fails_array_schema_validation(
        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": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)

    payload = ("foo", "bar")  # valid element types, but invalid container type
    with pytest.raises(PayloadValidationException):
        server.emit(event_name, payload, namespace=namespace)
示例#3
0
def test_register_handlers_skips_payload_validator_if_validation_is_disabled(
    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",
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, False, 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)

    assert handler_with_validation == actual_handler
    args = (faker.pyint(), )
    handler_with_validation(*args)  # handler does not raise validation errors
    assert True
示例#4
0
def test_emit_valid_event_invokes_super_method(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": "string"},
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)

    event_args = [faker.pystr()]
    server.emit(event_name, *event_args, namespace=namespace)
    super_method_mock.assert_called_once_with(event_name,
                                              *event_args,
                                              namespace=namespace)
示例#5
0
def test_emit_event_with_array_payload_is_treated_as_single_arg(
        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": "array",
                        "items": {
                            "type": "number"
                        }
                    },
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)
    payload = faker.pylist(value_types=[int])
    server.emit(event_name, payload, namespace=namespace)
    super_method_mock.assert_called_once_with(event_name,
                                              payload,
                                              namespace=namespace)
示例#6
0
def test_register_handlers_registers_channel_handlers(
    server_info: Info,
    faker: Faker,
):
    namespace = f"/{faker.pystr()}"
    spec = AsyncApiSpec(
        asyncapi=faker.pystr(),
        info=server_info,
        channels={
            namespace:
            Channel(x_handlers=ChannelHandlers(
                connect="tests.fixtures.handlers.connect",
                disconnect="tests.fixtures.handlers.disconnect",
                error="tests.fixtures.handlers.some_error",
            ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)

    server._register_handlers()

    assert server.exception_handlers[namespace] == some_error
    for event_name, handler, handler_namespace in server.handlers:
        assert handler_namespace == namespace
        unwrapped = deep_unwrap(handler)
        if event_name == "connect":
            assert unwrapped == connect
        else:
            assert unwrapped == disconnect
示例#7
0
def test_register_handlers_registers_callables_with_correct_event_name_and_namespace(
    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": "object"},
                    x_handler="tests.fixtures.handlers.ping",
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)

    server._register_handlers()
    assert len(server.handlers) == 2  # connection handler is also registered
    ping_handler_entry, connect_handler_entry = server.handlers

    registered_event, registered_handler, registered_namespace = ping_handler_entry
    assert registered_event == event_name
    assert deep_unwrap(registered_handler) == ping
    assert registered_namespace == namespace

    connection_event, connection_handler, registered_namespace = connect_handler_entry
    assert connection_event == "connect"
    assert deep_unwrap(connection_handler) == _noop_handler
    assert registered_namespace == namespace
示例#8
0
def test_emit_event_not_defined_under_given_valid_namespace_raises_validation_exc(
    server_info: Info,
    faker: Faker,
):
    namespace = f"/{faker.pystr()}"
    spec = AsyncApiSpec(
        asyncapi=faker.pystr(),
        info=server_info,
        channels={
            namespace:
            Channel(subscribe=Operation(message=OneOfMessages(one_of=[
                Message(
                    name=faker.pystr(),
                    payload={"type": "object"},
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)

    with pytest.raises(ValidationException):
        # Correct namespace but undefined event:
        server.emit(faker.pystr(),
                    faker.pydict(value_types=[str, int]),
                    namespace=namespace)
示例#9
0
def test_emit_event_with_tuple_payload_is_treated_as_multiple_args(
        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": "array",
                        "prefixItems": [
                            {
                                "type": "number"
                            },
                            {
                                "type": "string"
                            },
                        ],
                    },
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)
    payload = (faker.pyint(), faker.pystr())
    server.emit(event_name, payload, namespace=namespace)
    super_method_mock.assert_called_once_with(event_name,
                                              payload,
                                              namespace=namespace)
示例#10
0
def test_init_app_does_not_register_blueprint_if_docs_are_disabled(
        server_info: Info, faker: Faker):
    spec = AsyncApiSpec(
        asyncapi=faker.pystr(),
        info=server_info,
        channels={},
    )
    server = AsynctionSocketIO(spec, True, False, [], None, None)
    app = Flask(__name__)
    server.init_app(app)
    assert "asynction_docs" not in app.blueprints
示例#11
0
def test_register_handlers_registers_default_error_handler(
        optional_error_handler: Optional[ErrorHandler], server_info: Info,
        faker: Faker):
    server = AsynctionSocketIO(
        AsyncApiSpec(asyncapi=faker.pystr(), info=server_info, channels={}),
        True,
        True,
        [],
        optional_error_handler,
        None,
    )

    server._register_handlers()
    assert server.default_exception_handler == optional_error_handler
示例#12
0
def test_asynction_socketio_from_spec_path_kwarg_takes_precedence_over_server_name(
    fixture_paths: FixturePaths, ):
    p = "/async/socket.io"
    asio = AsynctionSocketIO.from_spec(
        spec_path=fixture_paths.simple_with_servers,
        path=p,
        server_name="production")
    assert asio.server_options["path"] == p
示例#13
0
def test_register_namespace_handlers_includes_server_security_validation():
    channel_handlers = ChannelHandlers(
        connect="tests.fixtures.handlers.connect")
    spec = AsyncApiSpec(
        asyncapi="2.3.0",
        info=Info("test", "1.0.0"),
        servers={
            "test":
            Server("https://localhost/", ServerProtocol.WSS, [{
                "basic": []
            }])
        },
        channels={GLOBAL_NAMESPACE: Channel(x_handlers=channel_handlers)},
        components=Components(
            security_schemes={
                "basic":
                SecurityScheme(
                    type=SecuritySchemesType.HTTP,
                    scheme=HTTPAuthenticationScheme.BASIC,
                    x_basic_info_func="tests.fixtures.handlers.basic_info",
                )
            }),
    )

    server = AsynctionSocketIO(spec, False, True,
                               spec.servers.get("test").security, None, None)
    server._register_namespace_handlers(
        GLOBAL_NAMESPACE,
        channel_handlers,
        None,
        None,  # No channel security requirements
    )
    event_name, registered_handler, _ = server.handlers[0]
    assert event_name == "connect"
    handler_with_security = deep_unwrap(registered_handler, depth=1)
    actual_handler = deep_unwrap(handler_with_security)

    with Flask(__name__).test_client() as c:
        c.post()  # Inject invalid POST request
        actual_handler()
        with pytest.raises(SecurityException):
            handler_with_security()  # handler raises security exception
            assert True
示例#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)
示例#15
0
def test_register_namespace_handlers_omits_bindings_validator_if_validation_disabled(
):
    channel_handlers = ChannelHandlers(
        connect="tests.fixtures.handlers.connect")
    channel_bindings = ChannelBindings(
        ws=WebSocketsChannelBindings(method="GET", ))
    server = AsynctionSocketIO(mock.Mock(), False, True, [], None, None)

    server._register_namespace_handlers(GLOBAL_NAMESPACE, channel_handlers,
                                        channel_bindings, [])
    event_name, registered_handler, _ = server.handlers[0]
    assert event_name == "connect"
    handler_with_validation = deep_unwrap(registered_handler, depth=1)
    actual_handler = deep_unwrap(handler_with_validation)

    with Flask(__name__).test_client() as c:
        c.post()  # Inject invalid POST request
        assert handler_with_validation == actual_handler
        handler_with_validation()  # handler does not raise validation errors
        assert True
示例#16
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)
示例#17
0
def test_init_app_does_not_register_handlers_if_app_is_none(
        server_info: Info, faker: Faker):
    namespace = f"/{faker.pystr()}"
    event_name = faker.pystr()
    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="tests.fixtures.handlers.ping",
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, False, False, [], None, None)
    server.init_app(app=None)
    assert not server.handlers
示例#18
0
def test_emit_event_with_invalid_args_fails_validation(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"},
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)

    with pytest.raises(PayloadValidationException):
        # Event args do not adhere to the schema
        server.emit(event_name, faker.pystr(), namespace=namespace)
示例#19
0
def test_asynction_socketio_from_spec_registers_default_error_handler(
    fixture_paths: FixturePaths, ):
    def my_default_error_handler(_):
        # dummy handler
        pass

    asio = AsynctionSocketIO.from_spec(
        spec_path=fixture_paths.simple,
        default_error_handler=my_default_error_handler,
        app=mock.MagicMock(
        ),  # app needs to be defined in order to register handlers
    )

    assert asio.default_exception_handler == my_default_error_handler
示例#20
0
def test_emit_event_that_has_no_subscribe_operation_raises_validation_exc(
        server_info: Info, faker: Faker):
    namespace = f"/{faker.pystr()}"
    event_name = faker.pystr()
    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="tests.fixtures.handlers.ping",
                )
            ]), ))
        },
    )
    server = AsynctionSocketIO(spec, True, True, [], None, None)

    with pytest.raises(ValidationException):
        server.emit(event_name,
                    faker.pydict(value_types=[str, int]),
                    namespace=namespace)
示例#21
0
def test_asynction_socketio_from_spec_raises_value_error_for_non_existent_server_name(
    fixture_paths: FixturePaths, ):
    with pytest.raises(ValueError):
        AsynctionSocketIO.from_spec(
            spec_path=fixture_paths.simple_with_servers,
            server_name="not-production")
示例#22
0
def test_asynction_socketio_from_spec(fixture_paths: FixturePaths):
    asio = AsynctionSocketIO.from_spec(spec_path=fixture_paths.simple)
    assert isinstance(asio, AsynctionSocketIO)
示例#23
0
def test_asynction_socketio_from_spec_empty_server_path_is_ignored(
    fixture_paths: FixturePaths, ):
    asio = AsynctionSocketIO.from_spec(
        spec_path=fixture_paths.simple_with_servers, server_name="development")
    assert "path" not in asio.server_options
示例#24
0
def test_asynction_socketio_from_spec_object(fixture_paths: FixturePaths):
    with open(fixture_paths.simple, "r") as simple:
        spec = yaml.safe_load(simple)
    asio = AsynctionSocketIO.from_spec(spec_path=spec)
    assert isinstance(asio, AsynctionSocketIO)
示例#25
0
def test_asynction_socketio_from_spec_uses_spec_server_path_as_socketio_path(
    fixture_paths: FixturePaths, ):
    asio = AsynctionSocketIO.from_spec(
        spec_path=fixture_paths.simple_with_servers, server_name="production")
    assert asio.server_options["path"] == "/api/socket.io"