Esempio n. 1
0
def test_mock_result_event_names_fired(mock_result: testing.MockResult,
                                       property_name):
    mock_result.event.events = [
        (EventMessage(api_name="api", event_name="event"), {}),
        (EventMessage(api_name="api2", event_name="event2"), {}),
    ]
    assert getattr(mock_result, property_name) == ["api.event", "api2.event2"]
Esempio n. 2
0
def test_mock_result_assert_events_fired_times(mock_result: testing.MockResult,
                                               method_name):
    assert_events_fired = getattr(mock_result, method_name)
    mock_result.event.events = [
        (EventMessage(api_name="api", event_name="event"), {}),
        (EventMessage(api_name="api", event_name="event"), {}),
    ]

    # No error
    try:
        assert_events_fired("api.event")
    except AssertionError as e:
        assert False, f"{method_name} incorrectly raised an assertion error: {e}"

    # No error
    try:
        assert_events_fired("api.event", times=2)
    except AssertionError as e:
        assert False, f"{method_name} incorrectly raised an assertion error: {e}"

    # Error
    with pytest.raises(AssertionError):
        assert_events_fired("api.event", times=0)

    # Error
    with pytest.raises(AssertionError):
        assert_events_fired("api.event", times=1)

    # Error
    with pytest.raises(AssertionError):
        assert_events_fired("api.event", times=3)
Esempio n. 3
0
def test_mock_result_get_event_messages_filtered(
        mock_result: testing.MockResult, method_name):
    get_event_messages = getattr(mock_result, method_name)

    event1 = EventMessage(api_name="api", event_name="event1")
    event2 = EventMessage(api_name="api", event_name="event2")

    mock_result.event.events = [(event1, {}), (event2, {})]

    assert get_event_messages("api.event2") == [event2]
Esempio n. 4
0
async def test_transaction_rollback_continue(dbapi_database: DbApiConnection,
                                             get_processed_events):
    # Check we can still use the connection following a rollback
    await dbapi_database.migrate()

    await dbapi_database.start_transaction()
    await dbapi_database.store_processed_event(
        EventMessage(api_name="api", event_name="event", id="123"))
    await dbapi_database.rollback_transaction()  # Rollback
    await dbapi_database.store_processed_event(
        EventMessage(api_name="api", event_name="event", id="123"))

    assert len(await get_processed_events()) == 1
Esempio n. 5
0
def test_mock_result_event_names_fired(mock_result: testing.MockResult, property_name):
    event1 = EventMessage(api_name="api1", event_name="event1")
    event2 = EventMessage(api_name="api2", event_name="event2")
    # fmt: off
    mock_result.mocker_context.event.to_transport.put_items = [
        (
            SendEventCommand(message=event1, options={}),
            None,
        ), (
            SendEventCommand(message=event2, options={}),
            None,
        ),
    ]
    # fmt: on
    assert getattr(mock_result, property_name) == ["api1.event1", "api2.event2"]
Esempio n. 6
0
def test_event_validate(create_bus_client_with_unhappy_schema):
    client: BusClient = create_bus_client_with_unhappy_schema()

    message = EventMessage(api_name="api", event_name="proc", kwargs={"p": 1})
    with pytest.raises(ValidationError):
        validate_outgoing(config=client.config, schema=client.schema, message=message)
    jsonschema.validate.assert_called_with({"p": 1}, {"p": {}})
Esempio n. 7
0
async def test_fetch_ok(transaction_transport_with_consumer, aiopg_cursor,
                        loop):
    message1 = EventMessage(api_name="api", event_name="event", id="1")
    message2 = EventMessage(api_name="api", event_name="event", id="2")
    message3 = EventMessage(api_name="api", event_name="event", id="3")

    transport = await transaction_transport_with_consumer(
        event_messages=[message1, message2, message3])
    consumer = transport.consume(listen_for="api.event")
    produced_events = await consumer_to_messages(consumer)
    assert produced_events == [message1, message2, message3]

    await aiopg_cursor.execute("SELECT COUNT(*) FROM lightbus_processed_events"
                               )
    total_processed_events = (await aiopg_cursor.fetchone())[0]
    assert total_processed_events == 3
Esempio n. 8
0
async def test_transaction_commit(dbapi_database: DbApiConnection,
                                  get_processed_events):
    await dbapi_database.migrate()
    await dbapi_database.store_processed_event(
        EventMessage(api_name="api", event_name="event", id="123"))
    await dbapi_database.commit_transaction()
    assert len(await get_processed_events()) == 1
def test_event_validate(create_bus_client_with_unhappy_schema):
    client: BusClient = create_bus_client_with_unhappy_schema()

    message = EventMessage(api_name="api", event_name="proc", kwargs={"p": 1})
    with pytest.raises(ValidationError):
        client._validate(message, direction="outgoing", api_name="api", procedure_name="proc")
    jsonschema.validate.assert_called_with({"p": 1}, {"p": {}})
Esempio n. 10
0
async def test_fetch_duplicate(transaction_transport_with_consumer,
                               aiopg_cursor, loop):
    # Same IDs = duplicate messages
    message1 = EventMessage(api_name="api", event_name="event", id="1")
    message2 = EventMessage(api_name="api", event_name="event", id="1")

    transport = await transaction_transport_with_consumer(
        event_messages=[message1, message2])
    consumer = transport.consume(listen_for="api.event")
    produced_events = await consumer_to_messages(consumer)
    assert produced_events == [message1
                               ]  # The second message should be ignored

    await aiopg_cursor.execute("SELECT COUNT(*) FROM lightbus_processed_events"
                               )
    total_processed_events = (await aiopg_cursor.fetchone())[0]
    assert total_processed_events == 1
Esempio n. 11
0
def test_mock_result_get_event_messages_filtered(mock_result: testing.MockResult, method_name):
    get_event_messages = getattr(mock_result, method_name)

    event1 = EventMessage(api_name="api", event_name="event1")
    event2 = EventMessage(api_name="api", event_name="event2")
    # fmt: off
    mock_result.mocker_context.event.to_transport.put_items = [
        (
            SendEventCommand(message=event1, options={}),
            None,
        ), (
            SendEventCommand(message=event2, options={}),
            None,
        ),
    ]
    # fmt: on

    assert get_event_messages("api.event2") == [event2]
Esempio n. 12
0
async def test_send_event_bad_option_value(dbapi_database: DbApiConnection):
    await dbapi_database.migrate()
    message = EventMessage(api_name="api",
                           event_name="event",
                           kwargs={"field": "abc"},
                           id="123")
    options = {"key": range(1, 100)}  # not json-serializable
    with pytest.raises(UnsupportedOptionValue):
        await dbapi_database.send_event(message, options)
Esempio n. 13
0
async def test_transaction_rollback(dbapi_database: DbApiConnection,
                                    get_processed_events):
    await dbapi_database.migrate()
    # We're about to rollback, so make sure we commit our migration first
    await dbapi_database.start_transaction()

    await dbapi_database.store_processed_event(
        EventMessage(api_name="api", event_name="event", id="123"))
    await dbapi_database.rollback_transaction()
    assert len(await get_processed_events()) == 0
Esempio n. 14
0
 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)
Esempio n. 15
0
def test_mock_result_assert_events_fired_times(mock_result: testing.MockResult,
                                               method_name):
    assert_events_fired = getattr(mock_result, method_name)
    mock_result.mocker_context.event.to_transport.put_items = [
        (
            SendEventCommand(message=EventMessage(api_name="api",
                                                  event_name="event"),
                             options={}),
            None,
        ),
        (
            SendEventCommand(message=EventMessage(api_name="api",
                                                  event_name="event"),
                             options={}),
            None,
        ),
    ]

    # No error
    try:
        assert_events_fired("api.event")
    except AssertionError as e:
        assert False, f"{method_name} incorrectly raised an assertion error: {e}"

    # No error
    try:
        assert_events_fired("api.event", times=2)
    except AssertionError as e:
        assert False, f"{method_name} incorrectly raised an assertion error: {e}"

    # Error
    with pytest.raises(AssertionError):
        assert_events_fired("api.event", times=0)

    # Error
    with pytest.raises(AssertionError):
        assert_events_fired("api.event", times=1)

    # Error
    with pytest.raises(AssertionError):
        assert_events_fired("api.event", times=3)
Esempio n. 16
0
async def test_remove_pending_event(dbapi_database: DbApiConnection,
                                    get_outbox):
    await dbapi_database.migrate()
    message = EventMessage(api_name="api",
                           event_name="event",
                           kwargs={"field": "abc"},
                           id="123")
    await dbapi_database.send_event(message, options={})

    assert len(await get_outbox()) == 1
    await dbapi_database.remove_pending_event(message_id="123")
    assert len(await get_outbox()) == 0
Esempio n. 17
0
async def test_send_event(mocker, transaction_transport):
    f = asyncio.Future()
    f.set_result(None)
    m = mocker.patch.object(transaction_transport.database,
                            "send_event",
                            return_value=f)
    message = EventMessage(api_name="api", event_name="event", id="123")

    await transaction_transport.send_event(event_message=message,
                                           options={"a": 1})
    assert m.called
    args, kwargs = m.call_args
    assert args == (message, {"a": 1})
Esempio n. 18
0
def test_mock_result_assert_event_not_fired(mock_result: testing.MockResult,
                                            method_name):
    assert_event_not_fired = getattr(mock_result, method_name)
    mock_result.event.events = [(EventMessage(api_name="api",
                                              event_name="event"), {})]

    # No exception
    try:
        assert_event_not_fired("api.bad_event")
    except AssertionError as e:
        assert False, f"{method_name} incorrectly raised an assertion error: {e}"

    with pytest.raises(AssertionError):
        assert_event_not_fired("api.event")
Esempio n. 19
0
async def test_publish_pending(transaction_transport, mocker):
    f = asyncio.Future()
    f.set_result(None)
    m = mocker.patch.object(transaction_transport.child_transport,
                            "send_event",
                            return_value=f)

    message1 = EventMessage(api_name="api", event_name="event", id="1")
    message2 = EventMessage(api_name="api", event_name="event", id="2")
    message3 = EventMessage(api_name="api", event_name="event", id="3")

    await transaction_transport.database.send_event(message1,
                                                    options={"a": "1"})
    await transaction_transport.database.send_event(message2,
                                                    options={"a": "2"})
    await transaction_transport.database.send_event(message3,
                                                    options={"a": "3"})

    await transaction_transport.publish_pending()

    assert m.call_count == 3
    messages = [c[0][0] for c in m.call_args_list]
    message_ids = [message.id for message in messages]
    assert message_ids == ["1", "2", "3"]
Esempio n. 20
0
async def test_checking_to_closed_transport(mocker, redis_pool: TransportPool):
    transport = await redis_pool.checkout()
    mocker.spy(transport, "close")

    # Close the pool
    await redis_pool.close()

    # Should work even though pool is closed
    await transport.send_event(EventMessage(api_name="api",
                                            event_name="event"),
                               options={})

    # Check the transport into the closed pool
    await redis_pool.checkin(transport)

    # The transport has been closed by the pool
    assert transport.close.called
Esempio n. 21
0
async def test_exception_in_listener_shutdown(
        new_bus, worker: Worker, queue_mocker: Type[BusQueueMockerContext],
        caplog):
    caplog.set_level(logging.ERROR)

    class TestException(Exception):
        pass

    def listener(*args, **kwargs):
        raise TestException()

    bus = new_bus()
    bus.client.proxied_client.stop_loop = MagicMock()

    # Start the listener
    bus.client.listen_for_events(
        events=[("my_api", "my_event")],
        listener=listener,
        listener_name="test",
        on_error=OnError.SHUTDOWN,
    )
    with queue_mocker(bus.client) as q:
        async with worker(bus):
            consume_command = q.event.to_transport.commands.get(
                ConsumeEventsCommand)
            consume_command.destination_queue.put_nowait(
                EventMessage(api_name="my_api", event_name="my_event"))
            await asyncio.sleep(0.1)

            assert len(q.errors.put_items
                       ) == 1, f"Expected one error, got: {q.errors.put_items}"
            error: Error = q.errors.put_items[0]
            assert isinstance(error.value, TestException)
            assert bus.client.stop_loop.called

            # Note that this hasn't actually shut the bus down, we'll test that in test_server_shutdown

            assert len(caplog.records) == 2

            exception_record: logging.LogRecord = caplog.records[0]
            assert "TestException" in exception_record.msg

            help_record: logging.LogRecord = caplog.records[1]
            assert "Lightbus will now shutdown" in help_record.message
Esempio n. 22
0
async def test_exception_in_listener_log(
        new_bus, worker: Worker, queue_mocker: Type[BusQueueMockerContext],
        caplog):
    """When on_error=OnError.ACKNOWLEDGE_AND_LOG, we should see an exception logged and
    the messaged acked"""
    caplog.set_level(logging.ERROR)

    class TestException(Exception):
        pass

    def listener(*args, **kwargs):
        raise TestException()

    bus: BusPath = new_bus()
    bus.client.proxied_client.stop_loop = MagicMock()

    # Start the listener
    bus.client.listen_for_events(
        events=[("my_api", "my_event")],
        listener=listener,
        listener_name="test",
        on_error=OnError.ACKNOWLEDGE_AND_LOG,
    )
    with queue_mocker(bus.client) as q:
        # Don't send event acks, we just want to ensure an attempt was made to ack
        q.event.to_transport.blackhole(AcknowledgeEventCommand)

        async with worker(bus):
            consume_command = q.event.to_transport.commands.get(
                ConsumeEventsCommand)
            consume_command.destination_queue.put_nowait(
                EventMessage(api_name="my_api", event_name="my_event"))
            await asyncio.sleep(0.1)

            # Ack happened
            assert not q.errors.put_items
            assert not bus.client.stop_loop.called
            assert q.event.to_transport.commands.get(AcknowledgeEventCommand)

            # Logging happened
            assert len(caplog.records) == 1
            log_record: logging.LogRecord = caplog.records[0]
            assert log_record.levelname == "ERROR"
            assert type(log_record.msg) == TestException
Esempio n. 23
0
async def test_send_event_ok(dbapi_database: DbApiConnection, get_outbox):
    await dbapi_database.migrate()

    message = EventMessage(api_name="api",
                           event_name="event",
                           kwargs={"field": "abc"},
                           id="123")
    options = {"key": "value"}
    await dbapi_database.send_event(message, options)

    assert len(await get_outbox()) == 1
    retrieved_message, options = await dbapi_database.consume_pending_events(
        message_id="123").__anext__()
    assert retrieved_message.id == "123"
    assert retrieved_message.get_kwargs() == {"field": "abc"}
    assert retrieved_message.get_metadata() == {
        "api_name": "api",
        "event_name": "event",
        "id": "123",
        "version": 1,
    }
    assert options == {"key": "value"}
Esempio n. 24
0
async def test_is_event_duplicate_false(dbapi_database: DbApiConnection):
    await dbapi_database.migrate()
    message = EventMessage(api_name="api", event_name="event", id="123")
    assert await dbapi_database.is_event_duplicate(message) == False
Esempio n. 25
0
async def test_is_event_duplicate_true(dbapi_database: DbApiConnection):
    await dbapi_database.migrate()
    message = EventMessage(api_name="api", event_name="event", id="123")
    await dbapi_database.store_processed_event(message)
    assert await dbapi_database.is_event_duplicate(message) == True