Beispiel #1
0
    def create_bus_client_with_unhappy_schema(validate=True, strict_validation=True):
        # Use the base transport as a dummy, it only needs to have a
        # close() method on it in order to keep the client.close() method happy
        schema = Schema(
            schema_transport=TransportPool(
                transport_class=lightbus.Transport,
                config=None,
                transport_config=NamedTuple("DummyTransportConfig")(),
            )
        )
        # Fake loading of remote schemas from schema transport
        schema._remote_schemas = {}
        config = Config.load_dict(
            {"apis": {"default": {"validate": validate, "strict_validation": strict_validation}}}
        )
        fake_schema = {"parameters": {"p": {}}, "response": {}}
        mocker.patch.object(schema, "get_rpc_schema", autospec=True, return_value=fake_schema),
        mocker.patch.object(schema, "get_event_schema", autospec=True, return_value=fake_schema),
        # Make sure the test api named "api" has a schema, otherwise strict_validation
        # will fail it
        schema.local_schemas["api"] = fake_schema
        mocker.patch(
            "jsonschema.validate", autospec=True, side_effect=ValidationError("test error")
        ),
        dummy_bus.client.schema = schema
        dummy_bus.client.config = config

        return dummy_bus.client
Beispiel #2
0
 def _instantiate_transport_pool(self, transport_class: Type["Transport"],
                                 transport_config: NamedTuple,
                                 config: "Config"):
     transport_pool = TransportPool(transport_class=transport_class,
                                    transport_config=transport_config,
                                    config=config)
     return transport_pool
Beispiel #3
0
 async def _result_listener(
     self,
     result_transport: TransportPool,
     timeout: float,
     rpc_message: RpcMessage,
     return_path: str,
     options: dict,
     result_queue: InternalQueue,
 ):
     try:
         logger.debug("Result listener is waiting")
         result = await asyncio.wait_for(
             result_transport.receive_result(
                 rpc_message=rpc_message, return_path=return_path, options=options
             ),
             timeout=timeout,
         )
     except asyncio.TimeoutError as e:
         logger.debug("Result listener timed out")
         await result_queue.put(e)
     else:
         logger.debug("Result listener received result, putting onto result queue")
         await result_queue.put(result)
     finally:
         self.listener_tasks.discard(asyncio.current_task())
Beispiel #4
0
def test_equal(dummy_pool):
    """Test the __eq__ method"""
    assert dummy_pool == TransportPool(
        transport_class=DebugEventTransport,
        transport_config=DebugEventTransport.Config(),
        config=Config.default(),
    )
Beispiel #5
0
async def redis_pool(redis_server_url):
    pool = TransportPool(
        transport_class=RedisEventTransport,
        transport_config=RedisEventTransport.Config(url=redis_server_url),
        config=Config.default(),
    )
    yield pool
    await pool.close()
Beispiel #6
0
async def test_checkout_checkin_asyncio(mocker, redis_pool: TransportPool,
                                        get_total_redis_connections):
    """Check in/out many connections concurrently (using asyncio tasks)

    Unlike using threads, this should grow the pool
    """
    # mocker.spy in pytest-mock runs afoul of this change in 3.8.1
    #    https://bugs.python.org/issue38857
    # We therefore use mocker.spy for python 3.7, or the new AsyncMock in 3.8
    # See: https://github.com/pytest-dev/pytest-mock/issues/178
    if sys.version_info >= (3, 8):
        from unittest.mock import AsyncMock

        redis_pool.grow = AsyncMock(wraps=redis_pool.grow)
        redis_pool._create_transport = AsyncMock(
            wraps=redis_pool._create_transport)
        redis_pool._close_transport = AsyncMock(
            wraps=redis_pool._close_transport)
    else:
        mocker.spy(redis_pool, "grow")
        mocker.spy(redis_pool, "_create_transport")
        mocker.spy(redis_pool, "_close_transport")

    async def _check_in_out():
        transport = await redis_pool.checkout()
        # Ensure we do something here in order to slow down the execution
        # time, thereby ensuring our pool starts to fill up. We also need to
        # use the connection to ensure the connection is lazy loaded
        await transport.send_event(EventMessage(api_name="api",
                                                event_name="event"),
                                   options={})
        await asyncio.sleep(0.02)
        await redis_pool.checkin(transport)

    async def _check_in_out_loop():
        for _ in range(0, 500 // 20):
            await _check_in_out()

    tasks = [asyncio.create_task(_check_in_out_loop()) for _ in range(0, 20)]
    await asyncio.wait(tasks)
    await redis_pool.close()

    assert redis_pool.grow.call_count == 20
    assert redis_pool._create_transport.call_count == 20
    assert redis_pool._close_transport.call_count == 20
    assert await get_total_redis_connections() == 1
Beispiel #7
0
async def dummy_pool():
    pool = TransportPool(
        transport_class=DebugEventTransport,
        transport_config=DebugEventTransport.Config(),
        config=Config.default(),
    )
    yield pool
    await pool.close()
Beispiel #8
0
def test_hash_equal(dummy_pool):
    """Test the __hash__ method"""
    assert hash(dummy_pool) == hash(
        TransportPool(
            transport_class=DebugEventTransport,
            transport_config=DebugEventTransport.Config(),
            config=Config.default(),
        ))
Beispiel #9
0
def test_not_equal(redis_pool, redis_server_url):
    """Test the __eq__ method"""
    assert redis_pool != TransportPool(
        transport_class=RedisEventTransport,
        transport_config=RedisEventTransport.Config(url=redis_server_url,
                                                    service_name="123"),
        config=Config.default(),
    )
Beispiel #10
0
async def test_checkout_checkin_threaded(mocker, redis_pool: TransportPool,
                                         run_in_many_threads,
                                         get_total_redis_connections):
    """Check in/out many connections concurrently (using threads)

    Note that this will not grow the pool. See the doc string for TransportPool
    """

    # mocker.spy in pytest-mock runs afoul of this change in 3.8.1
    #    https://bugs.python.org/issue38857
    # We therefore use mocker.spy for python 3.7, or the new AsyncMock in 3.8.
    # See: https://github.com/pytest-dev/pytest-mock/issues/178
    if sys.version_info >= (3, 8):
        from unittest.mock import AsyncMock

        redis_pool.grow = AsyncMock(wraps=redis_pool.grow)
        redis_pool._create_transport = AsyncMock(
            wraps=redis_pool._create_transport)
        redis_pool._close_transport = AsyncMock(
            wraps=redis_pool._close_transport)
    else:
        mocker.spy(redis_pool, "grow")
        mocker.spy(redis_pool, "_create_transport")
        mocker.spy(redis_pool, "_close_transport")

    async def _check_in_out():
        transport = await redis_pool.checkout()
        # Ensure we do something here in order to slow down the execution
        # time, thereby ensuring our pool starts to fill up. We also need to
        # use the connection to ensure the connection is lazy loaded
        await transport.send_event(EventMessage(api_name="api",
                                                event_name="event"),
                                   options={})
        await asyncio.sleep(0.02)
        await redis_pool.checkin(transport)

    run_in_many_threads(_check_in_out, executions=500, max_workers=20)

    # We're running in a thread, so we never grow the pool. Instead
    # we just return one-off connections which will be closed
    # when they get checked back in
    assert not redis_pool.grow.called
    assert redis_pool._create_transport.call_count == 500
    assert redis_pool._close_transport.call_count == 500
    assert await get_total_redis_connections() == 1
Beispiel #11
0
async def attr_test_pool(redis_server_url):
    """Used for testing attribute access only"""
    class AttrTestEventTransport(EventTransport):
        class_prop = True

        async def async_method(self):
            return True

        def sync_method(self):
            return True

        async def _async_private_method(self):
            return True

    pool = TransportPool(
        transport_class=AttrTestEventTransport,
        transport_config=AttrTestEventTransport.Config(),
        config=Config.default(),
    )
    yield pool
    await pool.close()