def test_add_to_dead_letter(settings, replica_cursor, replica_channel): master_instance = FailModel.cqrs.create() transport_delay(5) queue = replica_channel.queue_declare('replica', durable=True, exclusive=False) assert queue.method.message_count == 0 dead_queue = replica_channel.queue_declare( 'dead_letter_replica', durable=True, exclusive=False, ) assert dead_queue.method.message_count == 1 consumer_generator = replica_channel.consume( queue=dead_queue.method.queue, auto_ack=True, exclusive=False, ) *_, body = next(consumer_generator) dead_letter = json.loads(body) assert dead_letter['instance_pk'] == master_instance.pk assert dead_letter['retries'] == 2
def test_de_duplication(replica_cursor, clean_rabbit_transport_connection): assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 0 assert count_replica_rows(replica_cursor, REPLICA_EVENT_TABLE) == 0 master_instance = BasicFieldsModel.objects.create(int_field=21, char_field='text') BasicFieldsModel.call_post_bulk_create([master_instance]) transport_delay(3) replica_cursor.execute('TRUNCATE TABLE {};'.format(REPLICA_EVENT_TABLE)) BasicFieldsModel.call_post_bulk_create( [master_instance for _ in range(10)]) transport_delay(3) assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 1 assert count_replica_rows(replica_cursor, REPLICA_EVENT_TABLE) == 10
def test_dead_letter_expire(settings, replica_cursor, replica_channel): FailModel.cqrs.create() transport_delay(5) dead_queue = replica_channel.queue_declare( 'dead_letter_replica', durable=True, exclusive=False, ) assert dead_queue.method.message_count == 1 transport_delay(5) dead_queue = replica_channel.queue_declare( 'dead_letter_replica', durable=True, exclusive=False, ) assert dead_queue.method.message_count == 0
def test_both_consumers_consume(replica_cursor, clean_rabbit_transport_connection): assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 0 assert count_replica_rows(replica_cursor, REPLICA_EVENT_TABLE) == 0 BasicFieldsModel.cqrs.bulk_create([ BasicFieldsModel( int_field=index, char_field='text', ) for index in range(1, 10) ]) transport_delay(3) assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 9 assert count_replica_rows(replica_cursor, REPLICA_EVENT_TABLE) == 9 events_data = get_replica_all( replica_cursor, REPLICA_EVENT_TABLE, ('pid', ), ) assert len({d[0] for d in events_data}) == 2
def test_both_consumers_consume(settings, replica_cursor, clean_rabbit_transport_connection): settings.CQRS['MESSAGE_TTL'] = '4000' assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 0 assert count_replica_rows(replica_cursor, REPLICA_EVENT_TABLE) == 0 master_instances = BasicFieldsModel.objects.bulk_create([ BasicFieldsModel( int_field=index, char_field='text', ) for index in range(1, 10) ]) BasicFieldsModel.call_post_bulk_create(master_instances) transport_delay(5) assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 9 assert count_replica_rows(replica_cursor, REPLICA_EVENT_TABLE) == 9 events_data = get_replica_all( replica_cursor, REPLICA_EVENT_TABLE, ('pid', ), ) assert len({d[0] for d in events_data}) == 2
def test_flow(replica_cursor, clean_rabbit_transport_connection): assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 0 # Create master_instances = BasicFieldsModel.objects.bulk_create([ BasicFieldsModel( int_field=index, char_field='text', ) for index in range(1, 4) ]) BasicFieldsModel.call_post_bulk_create(master_instances) transport_delay() assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 3 assert {'text'} == { t[0] for t in get_replica_all(replica_cursor, REPLICA_BASIC_TABLE, ( 'char_field', )) } # Update 1 and 2 BasicFieldsModel.cqrs.bulk_update( BasicFieldsModel.objects.filter(int_field__in=(1, 2)), char_field='new_text', ) transport_delay() assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 3 assert ['new_text', 'new_text', 'text'] == [ t[0] for t in get_replica_all( replica_cursor, REPLICA_BASIC_TABLE, ('char_field', ), order_asc_by='int_field', ) ] # Delete 1 and 3 BasicFieldsModel.objects.filter(int_field__in=(1, 3)).delete() transport_delay() assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 1 assert (2, 'new_text', 1) == get_replica_first( replica_cursor, REPLICA_BASIC_TABLE, ('int_field', 'char_field', 'cqrs_revision'), )
def test_flow(replica_cursor, mocker, clean_rabbit_transport_connection): assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 0 # Create master_instance = BasicFieldsModel.objects.create( int_field=1, char_field='text', ) assert master_instance.cqrs_revision == 0 transport_delay() assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 1 replica_tuple = get_replica_first( replica_cursor, REPLICA_BASIC_TABLE, ('int_field', 'char_field', 'cqrs_revision', 'cqrs_updated'), ) assert ( master_instance.int_field, master_instance.char_field, master_instance.cqrs_revision, master_instance.cqrs_updated, ) == replica_tuple # We simulate transport error mocker.patch('dj_cqrs.controller.producer.produce') master_instance.char_field = 'new' master_instance.save() mocker.stopall() master_instance.refresh_from_db() assert master_instance.cqrs_revision == 1 # Sync to other service master_instance.cqrs_sync(queue='other_replica') transport_delay() assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 1 replica_tuple = get_replica_first( replica_cursor, REPLICA_BASIC_TABLE, ('int_field', 'char_field', 'cqrs_revision', 'cqrs_updated'), ) assert replica_tuple[0] == 1 assert replica_tuple[1] == 'text' assert replica_tuple[2] == 0 # Sync to replica master_instance.cqrs_sync(queue='replica') transport_delay() assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 1 replica_tuple = get_replica_first( replica_cursor, REPLICA_BASIC_TABLE, ('int_field', 'char_field', 'cqrs_revision', 'cqrs_updated'), ) assert replica_tuple[0] == 1 assert replica_tuple[1] == 'new' assert replica_tuple[2] == 1 mocker.patch('dj_cqrs.controller.producer.produce') master_instance.char_field = 'new2' master_instance.save() mocker.stopall() # Sync to all master_instance.cqrs_sync() transport_delay() assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 1 replica_tuple = get_replica_first( replica_cursor, REPLICA_BASIC_TABLE, ('int_field', 'char_field', 'cqrs_revision', 'cqrs_updated'), ) assert replica_tuple[0] == 1 assert replica_tuple[1] == 'new2' assert replica_tuple[2] == 2
def test_flow(replica_cursor, clean_rabbit_transport_connection): assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 0 # Create master_instance = BasicFieldsModel.objects.create( int_field=1, char_field='text', date_field=now().date(), bool_field=False, ) assert master_instance.cqrs_revision == 0 transport_delay() assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 1 replica_tuple = get_replica_first( replica_cursor, REPLICA_BASIC_TABLE, ('int_field', 'char_field', 'date_field', 'cqrs_revision', 'cqrs_updated', 'bool_field'), ) assert ( master_instance.int_field, master_instance.char_field, master_instance.date_field, master_instance.cqrs_revision, master_instance.cqrs_updated, master_instance.bool_field, ) == replica_tuple # Update master_instance.bool_field = True master_instance.save() if hasattr(master_instance, 'get_tracked_fields_data'): previous_values = master_instance.get_tracked_fields_data() assert 'bool_field' in previous_values assert previous_values['bool_field'] is False master_instance.refresh_from_db() assert master_instance.cqrs_revision == 1 transport_delay() assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 1 updated_replica_tuple = get_replica_first( replica_cursor, REPLICA_BASIC_TABLE, ('int_field', 'cqrs_revision', 'cqrs_updated', 'bool_field'), ) assert ( master_instance.int_field, master_instance.cqrs_revision, master_instance.cqrs_updated, master_instance.bool_field, ) == updated_replica_tuple # Delete master_instance.delete() transport_delay() assert count_replica_rows(replica_cursor, REPLICA_BASIC_TABLE) == 0