예제 #1
0
def test_should_consumer_react_to_chaos_with_failure_simulation_and_check_logger_with_subscribers():
    spy = SpyEvents()
    spy_dead_letter = SpyEvents()

    logger = FakeLogger()

    def assert_consumer(event: Event) -> Result[bool, Error]:
        spy.append(event)
        return isSuccess

    def assert_dead_letter_consumer(event: Event) -> Result[bool, Error]:
        spy_dead_letter.append(event)
        return isSuccess

    event = EventUserCreatedMother.random()
    subscribers = [
        EventSubscriber(
            event_name=event.event_name,
            event_version=event.event_version,
            handlers=[assert_consumer],
        )
    ]

    configurer = RabbitMqEventConfigurerMother.with_main_and_retry_ttl_100ms()
    configurer.configure_subscribers(subscribers)

    bus = RabbitMqEventBusMother.default()
    bus.publish(event)

    max_retries_allowed = 5
    chaos = RabbitMqEventChaos(
        percentage_simulate_failures=1.0,
        protected_routing_keys=[
            "dead_letter.alice.petisco.1.event.user_created.assert_consumer"
        ],
    )
    consumer = RabbitMqEventConsumerMother.with_chaos(
        chaos, max_retries_allowed, logger
    )
    consumer.add_subscribers(subscribers)
    consumer.add_handler_on_queue(
        "dead_letter.alice.petisco.1.event.user_created.assert_consumer",
        assert_dead_letter_consumer,
    )

    consumer.start()

    sleep(1.5)

    consumer.stop()
    configurer.clear()

    spy.assert_count_by_event_id(event.event_id, 0)
    spy_dead_letter.assert_count_by_event_id(event.event_id, 1)

    assert_logger_represents_simulated_failure_scenario(logger, max_retries_allowed)
예제 #2
0
def test_should_store_consumer_react_to_chaos_with_nck_simulation_and_send_several_event_to_dead_letter():
    spy = SpyEvents()
    spy_dead_letter_store = SpyEvents()
    logger = FakeLogger()

    def assert_consumer(event: Event) -> Result[bool, Error]:
        spy.append(event)
        return isSuccess

    def assert_dead_letter_store_consumer(event: Event) -> Result[bool, Error]:
        spy_dead_letter_store.append(event)
        return isSuccess

    configurer = RabbitMqEventConfigurerMother.with_main_and_retry_ttl_10ms()
    configurer.configure()

    bus = RabbitMqEventBusMother.default()

    event_ids = []
    for _ in range(5):
        event = EventUserCreatedMother.random()
        event_ids.append(event.event_id)
        bus.publish(event)

    max_retries_allowed = 5
    chaos = RabbitMqEventChaos(percentage_simulate_nack=1.0)
    consumer_with_chaos = RabbitMqEventConsumerMother.with_chaos(
        chaos, max_retries_allowed, logger
    )
    consumer_with_chaos.add_handler_on_store(assert_consumer)
    consumer_with_chaos.start()
    sleep(1.0)
    consumer_with_chaos.stop()

    consumer_without_chaos = RabbitMqEventConsumerMother.default()
    consumer_without_chaos.add_handler_on_queue(
        "dead_letter.store", assert_dead_letter_store_consumer
    )

    consumer_without_chaos.start()
    sleep(1.0)
    consumer_without_chaos.stop()

    configurer.clear()

    for event_id in event_ids:
        spy.assert_count_by_event_id(event_id, 0)  # Rejected before by Event Chaos
        spy_dead_letter_store.assert_count_by_event_id(event_id, 1)
예제 #3
0
def test_should_consumer_react_to_chaos_with_nck_simulation_and_check_logger():
    spy = SpyEvents()
    logger = FakeLogger()

    def assert_consumer(event: Event) -> Result[bool, Error]:
        spy.append(event)
        return isSuccess

    event = EventUserCreatedMother.random()
    subscribers = [
        EventSubscriber(
            event_name=event.event_name,
            event_version=event.event_version,
            handlers=[assert_consumer],
        )
    ]

    configurer = RabbitMqEventConfigurerMother.with_retry_ttl_10ms()
    configurer.configure_subscribers(subscribers)

    bus = RabbitMqEventBusMother.default()
    bus.publish(event)

    max_retries_allowed = 5
    chaos = RabbitMqEventChaos(percentage_simulate_nack=1.0)
    consumer = RabbitMqEventConsumerMother.with_chaos(
        chaos, max_retries_allowed, logger
    )
    consumer.add_subscribers(subscribers)
    consumer.start()

    sleep(1.0)

    consumer.stop()
    configurer.clear()

    assert len(logger.get_logging_messages()) >= 200
    first_logging_message = logger.get_logging_messages()[0]

    assert first_logging_message[0] == DEBUG
    assert first_logging_message[1]["meta"] == {
        "layer": "rabbitmq_event_consumer",
        "operation": "assert_consumer",
    }
    assert (
        first_logging_message[1]["data"]["message"]["chaos_action"] == "nack simulated"
    )
예제 #4
0
def test_should_consumer_react_to_chaos_with_zero_probability():
    spy = SpyEvents()
    logger = FakeLogger()

    def assert_consumer(event: Event) -> Result[bool, Error]:
        spy.append(event)
        return isSuccess

    event = EventUserCreatedMother.random()
    subscribers = [
        EventSubscriber(
            event_name=event.event_name,
            event_version=event.event_version,
            handlers=[assert_consumer],
        )
    ]

    configurer = RabbitMqEventConfigurerMother.with_retry_ttl_10ms()
    configurer.configure_subscribers(subscribers)

    bus = RabbitMqEventBusMother.default()
    bus.publish(event)

    max_retries_allowed = 5
    chaos = RabbitMqEventChaos(
        percentage_simulate_nack=0.0, percentage_simulate_failures=0.0
    )
    consumer = RabbitMqEventConsumerMother.with_chaos(
        chaos, max_retries_allowed, logger
    )
    consumer.add_subscribers(subscribers)
    consumer.start()

    sleep(1.0)

    consumer.stop()
    configurer.clear()

    spy.assert_number_unique_events(1)
    spy.assert_first_event(event)
    spy.assert_count_by_event_id(event.event_id, 1)

    assert len(logger.get_logging_messages()) == 2
    logging_message = logger.get_logging_messages()[1]
    assert logging_message[0] == DEBUG
    assert logging_message[1]["data"]["message"]["derived_action"] == {}
예제 #5
0
def test_should_consumer_react_to_chaos_with_failure_simulation_and_check_logger_without_subscribers():
    spy = SpyEvents()
    spy_dead_letter = SpyEvents()

    logger = FakeLogger()

    def assert_store_consumer(event: Event) -> Result[bool, Error]:
        spy.append(event)
        return isSuccess

    def assert_dead_letter_store_consumer(event: Event) -> Result[bool, Error]:
        spy_dead_letter.append(event)
        return isSuccess

    event = EventUserCreatedMother.random()

    configurer = RabbitMqEventConfigurerMother.with_main_and_retry_ttl_100ms()
    configurer.configure()

    bus = RabbitMqEventBusMother.default()
    bus.publish(event)

    max_retries_allowed = 5
    chaos = RabbitMqEventChaos(
        percentage_simulate_failures=1.0, protected_routing_keys=["dead_letter.store"]
    )
    consumer = RabbitMqEventConsumerMother.with_chaos(
        chaos, max_retries_allowed, logger
    )
    consumer.add_handler_on_store(assert_store_consumer)
    consumer.add_handler_on_queue(
        "dead_letter.store", assert_dead_letter_store_consumer
    )
    consumer.start()

    sleep(1.5)

    consumer.stop()
    configurer.clear()

    spy.assert_count_by_event_id(event.event_id, 0)
    spy_dead_letter.assert_count_by_event_id(event.event_id, 1)
예제 #6
0
    spy.assert_number_unique_events(1)
    spy.assert_first_event(event)
    spy.assert_count_by_event_id(event.event_id, 1)

    assert len(logger.get_logging_messages()) == 2
    logging_message = logger.get_logging_messages()[1]
    assert logging_message[0] == DEBUG
    assert logging_message[1]["data"]["message"]["derived_action"] == {}


@pytest.mark.integration
@testing_with_rabbitmq
@pytest.mark.parametrize(
    "max_retries_allowed,expected_number_event_consumed,chaos",
    [
        (5, 0, RabbitMqEventChaos(percentage_simulate_nack=1.0)),
        (1, 0, RabbitMqEventChaos(percentage_simulate_failures=1.0)),
        (1, 1, RabbitMqEventChaos(delay_before_event_handler_second=2.0)),
    ],
)
def test_should_consumer_react_to_chaos_inputs(
    max_retries_allowed, expected_number_event_consumed, chaos
):
    spy = SpyEvents()

    def assert_consumer(event: Event) -> Result[bool, Error]:
        spy.append(event)
        return isSuccess

    event = EventUserCreatedMother.random()
    subscribers = [
예제 #7
0
    def from_dict(kdict):
        event_subscribers = None
        queues_subscribers = None
        store_queue_subscriber = None

        events = kdict.get("events")
        queues = kdict.get("queues")

        retry_ttl = DEFAULT_QUEUE_RETRY_TTL
        main_ttl = DEFAULT_QUEUE_RETRY_TTL
        queue_config = QueueConfig.default(retry_ttl, main_ttl)

        if events:
            retry_ttl = events.get("retry_ttl", DEFAULT_QUEUE_RETRY_TTL)
            main_ttl = events.get("retry_ttl", DEFAULT_QUEUE_RETRY_TTL)
            queue_config = QueueConfig.default(retry_ttl, main_ttl)

            dict_events_subscribers = events.get("subscribers")
            if dict_events_subscribers:
                event_subscribers = []
                for src_event_name, event_info in dict_events_subscribers.items(
                ):
                    handlers_names = check_list_or_str_item(
                        event_info, "handlers", typename="EventHandler")

                    event_name = get_event_name(src_event_name)
                    event_version = event_info.get("version", 1)
                    handlers = get_handlers(handlers_names, kdict)

                    event_subscribers.append(
                        EventSubscriber(
                            event_name=event_name,
                            event_version=event_version,
                            handlers=handlers,
                        ))

        if queues:
            str_store_queue_subscriber = queues.get("store")
            if str_store_queue_subscriber:
                store_queue_subscriber = get_handlers(
                    [str_store_queue_subscriber], kdict)[0]

            dict_queues_subscribers = queues.get("subscribers")
            if dict_queues_subscribers:
                queues_subscribers = {}
                for queue_name in dict_queues_subscribers.keys():
                    handlers_names = check_list_or_str_item(
                        dict_queues_subscribers,
                        queue_name,
                        typename="QueueHandler")
                    handlers = get_handlers(handlers_names, kdict)
                    queues_subscribers[queue_name] = handlers

            specific_queues_config = queues.get("specific_config")
            if specific_queues_config:
                queue_config = QueueConfig.from_dict(specific_queues_config,
                                                     retry_ttl, main_ttl)

        return ConfigEvents(
            organization=events.get("organization"),
            service=events.get("service"),
            publish_deploy_event=events.get("publish_deploy_event"),
            consumer_verbose=events.get("consumer_verbose", False),
            use_store_queues=events.get("use_store_queues", True),
            retry_ttl=retry_ttl,
            main_ttl=main_ttl,
            max_retries=events.get("max_retries", 5),
            message_broker=events.get("message_broker", "not_implemented"),
            event_subscribers=event_subscribers,
            store_queue_subscriber=store_queue_subscriber,
            queues_subscribers=queues_subscribers,
            chaos=RabbitMqEventChaos(),
            queue_config=queue_config,
        )