def make_dataset(self): citizens = [ # Первого жителя создаем с родственником. В запросе к # PATCH-обработчику список relatives будет содержать только другого # жителя, что потребует выполнения максимального кол-ва запросов # (как на добавление новой родственной связи, так и на удаление # существующей). generate_citizen(citizen_id=1, relatives=[2]), generate_citizen(citizen_id=2, relatives=[1]), *generate_citizens( citizens_num=9998, relations_num=1000, start_citizen_id=3) ] return {citizen['citizen_id']: citizen for citizen in citizens}
async def test_get_citizens_birthdays(api_client, dataset): # Перед прогоном каждого теста добавляем в БД дополнительную выгрузку с # двумя родственниками, чтобы убедиться, что обработчик различает жителей # разных выгрузок. await import_data(api_client, [ generate_citizen(citizen_id=1, relatives=[2]), generate_citizen(citizen_id=2, relatives=[1]) ]) # Проверяем обработчик на указанных данных import_id = await import_data(api_client, dataset['citizens']) result = await get_citizens_birthdays(api_client, import_id) for month in dataset['expected']: assert month in result, f'Month {month} is missing' actual = {(citizen['citizen_id'], citizen['presents']) for citizen in result[month]} expected = {(citizen['citizen_id'], citizen['presents']) for citizen in dataset['expected'][month]} assert actual == expected
async def test_get_ages(api_client, dataset): # Перед прогоном каждого теста добавим в БД дополнительную выгрузку с # жителем из другого города, чтобы убедиться, что обработчик различает # жителей разных выгрузок. await import_data(api_client, [generate_citizen(citizen_id=1, town='Санкт-Петербург')]) import_id = await import_data(api_client, dataset['citizens']) result = await get_citizens_ages(api_client, import_id) assert len(dataset['expected']) == len(result), 'Towns number is different' actual_towns_map = {town['town']: town for town in result} for town in dataset['expected']: assert town['town'] in actual_towns_map actual_town = actual_towns_map[town['town']] for percentile in ['p50', 'p75', 'p99']: assert town[percentile] == actual_town[percentile], ( f"{town['town']} {percentile} {actual_town[percentile]} does " f"not match expected value {town[percentile]}")
async def test_patch_self_relative(api_client): """ Проверяем что жителю можно указать себя родственником. Напоминает фильм Патруль времени, не так ли? """ dataset = [ generate_citizen(citizen_id=1, name='Джейн', gender='male', birth_date='13.09.1945', town='Нью-Йорк', relatives=[]), ] import_id = await import_data(api_client, dataset) dataset[0]['relatives'] = [dataset[0]['citizen_id']] actual = await patch_citizen( api_client, import_id, dataset[0]['citizen_id'], data={k: v for k, v in dataset[0].items() if k != 'citizen_id'}) assert compare_citizens(dataset[0], actual)
async def test_patch_citizen(api_client): """ Проверяет, что данные о жителе и его родственниках успешно обновляются. """ # Перед прогоном каждого теста добавляем в БД дополнительную выгрузку с # тремя жителями и одинаковыми идентификаторами, чтобы убедиться, что # обработчик различает жителей разных выгрузок и изменения не затронут # жителей другой выгрузки. side_dataset = [ generate_citizen(citizen_id=1), generate_citizen(citizen_id=2), generate_citizen(citizen_id=3) ] side_dataset_id = await import_data(api_client, side_dataset) # Создаем выгрузку с тремя жителями, два из которых родственники для # тестирования изменений. dataset = [ generate_citizen(citizen_id=1, name='Иванов Иван Иванович', gender=Gender.male.value, birth_date='01.01.2000', town='Некий город', street='Некая улица', building='Некое строение', apartment=1, relatives=[2]), generate_citizen(citizen_id=2, relatives=[1]), generate_citizen(citizen_id=3, relatives=[]), ] import_id = await import_data(api_client, dataset) # Обновляем часть полей о жителе, чтобы убедиться что PATCH позволяет # передавать только некоторые поля. # Данные меняем сразу в выгрузке, чтобы потом было легче сравнивать. dataset[0]['name'] = 'Иванова Иванна Ивановна' await patch_citizen(api_client, import_id, dataset[0]['citizen_id'], data={'name': dataset[0]['name']}) # Обновляем другую часть данных, чтобы проверить что данные обновляются. dataset[0]['gender'] = Gender.female.value dataset[0]['birth_date'] = '02.02.2002' dataset[0]['town'] = 'Другой город' dataset[0]['street'] = 'Другая улица' dataset[0]['building'] = 'Другое строение' dataset[0]['apartment'] += 1 # У жителя #1 одна родственная связь должна исчезнуть (с жителем #2), # и одна появиться (с жителем #3). dataset[0]['relatives'] = [dataset[2]['citizen_id']] # Родственные связи должны быть двусторонними: # - у жителя #2 родственная связь с жителем #1 удаляется # - у жителя #3 родственная связь с жителем #1 добавляется. dataset[2]['relatives'].append(dataset[0]['citizen_id']) dataset[1]['relatives'].remove(dataset[0]['citizen_id']) actual = await patch_citizen(api_client, import_id, dataset[0]['citizen_id'], data={ 'gender': dataset[0]['gender'], 'birth_date': dataset[0]['birth_date'], 'town': dataset[0]['town'], 'street': dataset[0]['street'], 'building': dataset[0]['building'], 'apartment': dataset[0]['apartment'], 'relatives': dataset[0]['relatives'], }) # Проверяем, что житель корректно обновился assert compare_citizens(dataset[0], actual) # Проверяем всю выгрузку, чтобы убедиться что родственные связи всех # жителей изменились корректно. actual_citizens = await get_citizens(api_client, import_id) assert compare_citizen_groups(actual_citizens, dataset) # Проверяем, что изменение жителя в тестируемой выгрузке не испортило # данные в дополнительной выгрузке. actual_citizens = await get_citizens(api_client, side_dataset_id) assert compare_citizen_groups(actual_citizens, side_dataset)
from analyzer.api.schema import BIRTH_DATE_FORMAT from analyzer.utils.pg import MAX_INTEGER from analyzer.utils.testing import ( compare_citizen_groups, generate_citizen, generate_citizens, get_citizens, import_data, ) LONGEST_STR = 'ё' * 256 CASES = ( # Житель без родственников. # Обработчик должен корректно создавать выгрузку с одним жителем. ([generate_citizen(relatives=[])], HTTPStatus.CREATED), # Житель с несколькими родственниками. # Обработчик должен корректно добавлять жителей и создавать # родственные связи. ([ generate_citizen(citizen_id=1, relatives=[2, 3]), generate_citizen(citizen_id=2, relatives=[1]), generate_citizen(citizen_id=3, relatives=[1]) ], HTTPStatus.CREATED), # Житель сам себе родственник. # Обработчик должен позволять создавать такие родственные связи. ([ generate_citizen(citizen_id=1, name='Джейн',
Позволяет записать ожидаемый ответ в краткой форме. """ return { str(month): values.get(str(month), []) if values else [] for month in range(1, 13) } datasets = [ # Житель, у которого несколько родственников. # Обработчик должен корректно показывать сколько подарков приобретет # житель #1 своим родственникам в каждом месяце. { 'citizens': [ generate_citizen(citizen_id=1, birth_date='31.12.2019', relatives=[2, 3]), generate_citizen(citizen_id=2, birth_date='11.02.2020', relatives=[1]), generate_citizen(citizen_id=3, birth_date='17.02.2020', relatives=[1]) ], 'expected': make_response({ '2': [{ 'citizen_id': 1, 'presents': 2 }], '12': [{
Позволяет представлять дату рождения жителя в виде возраста человека в днях и годах, что гораздо нагляднее в тестах. """ birth_date = copy(base_date).replace(year=base_date.year - years) birth_date -= timedelta(days=days) return birth_date.strftime(BIRTH_DATE_FORMAT) datasets = [ # Несколько жителей у которых завтра день рождения. # Проверяется что обработчик использует в рассчетах количество полных лет. { 'citizens': [ generate_citizen(birth_date=age2date(years=10, days=364), town='Москва', citizen_id=1), generate_citizen(birth_date=age2date(years=30, days=364), town='Москва', citizen_id=2), generate_citizen(birth_date=age2date(years=50, days=364), town='Москва', citizen_id=3) ], 'expected': [{ 'town': 'Москва', 'p50': 30., 'p75': 40., 'p99': 49.6 }] },