示例#1
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 = [
        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)

    consumer = RabbitMqEventConsumerMother.with_chaos(chaos, max_retries_allowed)
    consumer.add_subscribers(subscribers)
    consumer.start()

    sleep(1.0)

    consumer.stop()
    configurer.clear()
    spy.assert_count_by_event_id(event.event_id, expected_number_event_consumed)
 def add_subscriber_on_dead_letter(self, subscriber: EventSubscriber,
                                   handler: Callable):
     queue_name = RabbitMqEventSubscriberQueueNameFormatter.format_dead_letter(
         subscriber, exchange_name=self.exchange_name)
     for handler_name in subscriber.get_handlers_names():
         self.add_handler_on_queue(
             queue_name=f"{queue_name}.{handler_name}", handler=handler)
 def configure_event(self, event: Event):
     self.configure_subscribers([
         EventSubscriber(
             event_name=event.event_name,
             event_version=event.event_version,
             handlers=[],
         )
     ])
示例#4
0
def test_should_publish_consume_and_retry_event_with_two_handlers_from_rabbitmq_when_fail_consumer(
        max_retries_allowed, expected_number_event_consumed,
        simulated_results):

    spy_consumer_1 = SpyEvents()
    spy_consumer_2 = SpyEvents()

    simulated_results_1 = copy.deepcopy(simulated_results)
    simulated_results_2 = copy.deepcopy(simulated_results)

    def assert_consumer_1(event: Event) -> Result[bool, Error]:
        spy_consumer_1.append(event)
        result = simulated_results_1.pop(0)
        return result

    def assert_consumer_2(event: Event) -> Result[bool, Error]:
        spy_consumer_2.append(event)
        result = simulated_results_2.pop(0)
        return result

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

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

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

    consumer = RabbitMqEventConsumerMother.with_max_retries(
        max_retries_allowed)
    consumer.add_subscribers(subscribers)
    consumer.start()

    sleep(1.5)

    consumer.stop()
    configurer.clear()

    print(f"num events: {len(spy_consumer_1.events)} - {spy_consumer_1}")
    print(f"num events: {len(spy_consumer_2.events)} - {spy_consumer_2}")

    spy_consumer_1.assert_number_unique_events(1)
    spy_consumer_1.assert_first_event(event)
    spy_consumer_1.assert_count_by_event_id(event.event_id,
                                            expected_number_event_consumed)

    spy_consumer_2.assert_number_unique_events(1)
    spy_consumer_2.assert_first_event(event)
    spy_consumer_2.assert_count_by_event_id(event.event_id,
                                            expected_number_event_consumed)
示例#5
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)
示例#6
0
def test_should_publish_consume_with_event_handler_notify_when_fail_consumer_with_critical_error(
    given_any_petisco
):
    spy = SpyEvents()
    logger = FakeLogger()
    notifier = FakeNotifier()

    class MyCriticalError(CriticalError):
        pass

    @event_handler(logger=logger, notifier=notifier)
    def assert_consumer(event: Event) -> Result[bool, Error]:
        spy.append(event)
        return Failure(MyCriticalError(Exception()))

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

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

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

    consumer = RabbitMqEventConsumerMother.without_retry()
    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)

    first_logging_message = logger.get_logging_messages()[0]
    assert first_logging_message == (
        DEBUG,
        LogMessageMother.get_event_handler(
            operation="assert_consumer",
            message={"event": event.event_name, "body": event.to_json()},
        ).to_dict(),
    )
    assert notifier.publish_called
    assert notifier.publish_times_called == 1
示例#7
0
def test_should_publish_consume_and_retry_event_from_rabbitmq_when_a_queue_is_configured_with_specific_parameters(
    max_retries_allowed, expected_number_event_consumed, simulated_results
):
    spy = SpyEvents()
    spy_specific = SpyEvents()

    def assert_consumer(event: Event) -> Result[bool, Error]:
        spy.append(event)
        result = simulated_results.pop(0)
        return result

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

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

    specific_queue_config = SpecificQueueConfig(
        wildcard="*assert_specific_consumer",
        specific_retry_ttl=50,
        specific_main_ttl=75,
    )
    queue_config = QueueConfigMother.with_specific_queue_config(
        specific_queue_config, default_retry_ttl=100, default_main_ttl=100
    )

    configurer = RabbitMqEventConfigurerMother.with_queue_config(queue_config)
    configurer.configure_subscribers(subscribers)

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

    consumer = RabbitMqEventConsumerMother.with_max_retries(max_retries_allowed)
    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_last_event(event)
    spy.assert_count_by_event_id(event.event_id, expected_number_event_consumed)
    spy_specific.assert_number_unique_events(1)
示例#8
0
def test_should_publish_consume_retry_and_send_to_dead_letter_event_from_rabbitmq_when_fail_consumer(
):
    max_retries_allowed = 2
    expected_number_event_consumed = 3

    spy = SpyEvents()
    spy_dead_letter = SpyEvents()

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

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

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

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

    consumer = RabbitMqEventConsumerMother.with_max_retries(
        max_retries_allowed)
    consumer.add_subscribers(subscribers)

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

    consumer.add_subscriber_on_dead_letter(subscriber, dead_letter_consumer)

    consumer.start()

    sleep(1.5)

    consumer.stop()
    configurer.clear()

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

    spy_dead_letter.assert_number_unique_events(1)
    spy_dead_letter.assert_first_event(event)
    spy_dead_letter.assert_count_by_event_id(event.event_id, 1)
示例#9
0
def test_should_publish_consume_and_retry_event_not_affecting_store_queue_from_rabbitmq_when_fail_handler_consumer(
        max_retries_allowed, expected_number_event_consumed,
        simulated_results):

    spy_consumer_event_store = SpyEvents()
    spy_consumer_handler = SpyEvents()

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

    def assert_consumer_handler(event: Event) -> Result[bool, Error]:
        spy_consumer_handler.append(event)
        result = simulated_results.pop(0)
        return result

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

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

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

    consumer = RabbitMqEventConsumerMother.with_max_retries(
        max_retries_allowed)
    consumer.add_subscribers(subscribers)
    consumer.add_handler_on_queue("store", assert_consumer_event_store)

    consumer.start()

    sleep(1.0)

    consumer.stop()
    configurer.clear()

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

    spy_consumer_handler.assert_number_unique_events(1)
    spy_consumer_handler.assert_first_event(event)
    spy_consumer_handler.assert_count_by_event_id(
        event.event_id, expected_number_event_consumed)
示例#10
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"
    )
示例#11
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"] == {}
示例#12
0
def test_should_publish_consume_with_event_handler_when_fail_consumer():
    spy = SpyEvents()
    logger = FakeLogger()

    @event_handler(logger=logger)
    def assert_consumer(event: Event) -> Result[bool, Error]:
        spy.append(event)
        return isFailure

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

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

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

    consumer = RabbitMqEventConsumerMother.with_max_retries(1)
    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)

    first_logging_message = logger.get_logging_messages()[0]

    assert first_logging_message == (
        DEBUG,
        LogMessageMother.get_event_handler(
            operation="assert_consumer",
            message={"event": event.event_name, "body": event.to_json()},
        ).to_dict(),
    )
示例#13
0
def test_should_publish_consume_and_retry_event_with_two_handlers_from_rabbitmq(
):

    spy_consumer_1 = SpyEvents()
    spy_consumer_2 = SpyEvents()

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

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

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

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

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

    consumer = RabbitMqEventConsumerMother.default()
    consumer.add_subscribers(subscribers)
    consumer.start()

    sleep(1.0)

    consumer.stop()
    configurer.clear()

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

    spy_consumer_2.assert_number_unique_events(1)
    spy_consumer_2.assert_first_event(event)
    spy_consumer_2.assert_count_by_event_id(event.event_id, 1)
示例#14
0
def test_should_publish_consume_with_event_handler_with_default_parameters_when_success_consumer(
    given_any_petisco
):
    spy = SpyEvents()

    @event_handler()
    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.default()
    configurer.configure_subscribers(subscribers)

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

    consumer = RabbitMqEventConsumerMother.without_retry()
    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)
def test_should_publish_event_on_consumer_with_event_handler():
    spy = SpyEvents()

    @event_handler(logger=FakeLogger())
    def assert_consumer(event: Event, event_bus: IEventBus) -> BoolResult:
        spy.append(event)
        event = EventUserUpdatedMother.random()
        event_bus.publish(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)

    consumer = RabbitMqEventConsumerMother.with_max_retries(1)
    consumer.add_subscribers(subscribers)
    consumer.start()

    bus = RabbitMqEventBusMother.default()
    for _ in range(1):
        event = EventUserCreatedMother.random()
        bus.publish(event)

    sleep(1.0)

    consumer.stop()
    configurer.clear()

    spy.assert_number_unique_events(1)
示例#16
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,
        )