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)
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)
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" )
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"] == {}
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)
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 = [
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, )