def test_multiple_relaties(migrated_postgres, client): dataset = [ generate_citizen(citizen_id=1, birth_date="2019-12-31", relatives=[2, 3]), generate_citizen(citizen_id=2, birth_date="2020-02-11", relatives=[1]), generate_citizen(citizen_id=3, birth_date="2020-02-17", relatives=[1]), ] r = client.post("/imports", json={"data": dataset}) import_id = r.json()["data"]["import_id"] url = f"/imports/{import_id}/citizens/birthdays" expected = make_response({ "2": [{ "citizen_id": 1, "presents": 2 }], "12": [{ "citizen_id": 2, "presents": 1 }, { "citizen_id": 3, "presents": 1 }], }) response = client.get(url) assert response.status_code == 200 assert response.json()["data"] == expected
def test_import(): dataset = [ generate_citizen(citizen_id=1, relatives=[2, 3]), generate_citizen(citizen_id=2, relatives=[1]), generate_citizen(citizen_id=3, relatives=[1]), generate_citizen(citizen_id=4, relatives=[]), generate_citizen(citizen_id=5, name="Джейн", gender="male", birth_date="2020-02-17", relatives=[5]), ] import_obj = Import(data=dataset) for i, citizen in enumerate(dataset): for k, v in citizen.items(): value = getattr(import_obj.data[i], k) if isinstance(value, date): value = value.strftime("%Y-%m-%d") assert v == value with pytest.raises(ValidationError): dataset = [ generate_citizen(citizen_id=1), generate_citizen(citizen_id=1), ] Import(data=dataset) with pytest.raises(ValidationError): dataset = [ generate_citizen(citizen_id=1, relatives=[2, 3]), generate_citizen(citizen_id=2, relatives=[1]), generate_citizen(citizen_id=3, relatives=[]), ] Import(data=dataset)
def test_no_relatives(migrated_postgres, client): dataset = [ generate_citizen(citizen_id=1, birth_date="2019-12-31", relatives=[]), generate_citizen(citizen_id=2, birth_date="2020-02-11", relatives=[]), generate_citizen(citizen_id=3, birth_date="2020-02-17", relatives=[]), ] r = client.post("/imports", json={"data": dataset}) import_id = r.json()["data"]["import_id"] url = f"/imports/{import_id}/citizens/birthdays" expected = make_response() response = client.get(url) assert response.status_code == 200 assert response.json()["data"] == expected
async def test_patch_self_relative(database, migrated_postgres): """ Проверяем что жителю можно указать себя родственником. """ dataset = [ generate_citizen(citizen_id=1, name="Джейн", gender="male", birth_date="1945-03-13", town="Нью-Йорк", relatives=[]), ] dataset_import = Import(data=dataset) async with database: import_id = await analyzer.save_import(dataset_import, database) dataset[0]["relatives"] = [dataset[0]["citizen_id"]] data = {k: v for k, v in dataset[0].items() if k != "citizen_id"} patch = CitizenPatch(**data) async with database: actual = await analyzer.patch_citizen(import_id, dataset[0]["citizen_id"], patch, database) del actual["import_id"] assert compare_citizens(dataset[0], actual)
def test_wrong_patch(migrated_postgres, client): citizen = generate_citizen(citizen_id=1) r = client.post("/imports", json={"data": [citizen]}) import_id = r.json()["data"]["import_id"] url = f"/imports/{import_id}/citizens/1" patch = { "birth_date": (date.today() + timedelta(days=1)).strftime("%Y-%m-%d") } citizen.update(patch) response = client.patch(url, data=json.dumps(patch)) assert response.status_code == 400
async def test_get_birthdays(database, migrated_postgres, dataset): # Перед прогоном каждого теста добавляем в БД дополнительную выгрузку с # двумя родственниками, чтобы убедиться, что обработчик различает жителей # разных выгрузок. import_obj = Import(data=[ generate_citizen(citizen_id=1, relatives=[2]), generate_citizen(citizen_id=2, relatives=[1]) ]) async with database: await analyzer.save_import(import_obj, database) # Проверяем обработчик на указанных данных import_id = await analyzer.save_import( Import(data=dataset["citizens"]), database) result = await analyzer.get_birthdays(import_id, database) for month in dataset["expected"]: 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
def test_successful_patch(migrated_postgres, client): dataset = [ generate_citizen( citizen_id=1, name="Иванов Иван Иванович", gender="male", birth_date="2020-01-01", town="Некий город", street="Некая улица", building="Некое строение", apartment=1, relatives=[2], ), generate_citizen(citizen_id=2, relatives=[1]), generate_citizen(citizen_id=3, relatives=[]), ] r = client.post("/imports", json={"data": dataset}) import_id = r.json()["data"]["import_id"] url = f"/imports/{import_id}/citizens/1" dataset[0]["name"] = "Сидорова Василиса Петровна" patch = {"name": dataset[0]["name"]} response = client.patch(url, data=json.dumps(patch)) assert response.status_code == 200 assert response.json() == dataset[0] dataset[0]["gender"] = "female" dataset[0]["birth_date"] = "2020-01-02" dataset[0]["town"] = "Другой город" dataset[0]["street"] = "Другая улица" dataset[0]["building"] = "Другое строение" dataset[0]["apartment"] = 2 dataset[0]["relatives"] = [3] patch = dataset[0].copy() patch.pop("citizen_id") response = client.patch(url, data=json.dumps(patch)) assert response.status_code == 200 assert response.json() == dataset[0]
def test_self_relative(migrated_postgres, client): dataset = [ generate_citizen(citizen_id=1, name="Джейн", gender="male", birth_date="2020-02-17", relatives=[1]) ] r = client.post("/imports", json={"data": dataset}) import_id = r.json()["data"]["import_id"] url = f"/imports/{import_id}/citizens/birthdays" expected = make_response({"2": [{"citizen_id": 1, "presents": 1}]}) response = client.get(url) assert response.status_code == 200 assert response.json()["data"] == expected
async def test_get_ages(database, migrated_postgres, dataset): # Перед прогоном каждого теста добавим в БД дополнительную выгрузку с # жителем из другого города, чтобы убедиться, что обработчик различает # жителей разных выгрузок. import_obj = Import( data=[generate_citizen(citizen_id=1, town="Санкт-Петербург")]) async with database: await analyzer.save_import(import_obj, database) import_id = await analyzer.save_import( Import(data=dataset["citizens"]), database) result = await analyzer.get_age_statistics(import_id, database) 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]}")
def test_non_unique_ids(migrated_postgres, client): body = {"data": [generate_citizen(citizen_id=1), generate_citizen(citizen_id=1),]} response = client.post("/imports", json=body) assert response.status_code == 400
def test_wrong_dates(migrated_postgres, client): body = {"data": [generate_citizen(birth_date=(date.today() + timedelta(days=1)).strftime("%Y-%m-%d"))]} response = client.post("/imports", json=body) assert response.status_code == 400
import pytest from utils import LONGEST_STR, MAX_INT, compare_citizen_groups, generate_citizen, generate_citizens dataset = [ generate_citizen(citizen_id=1, relatives=[2, 3]), generate_citizen(citizen_id=2, relatives=[1]), generate_citizen(citizen_id=3, relatives=[1]), generate_citizen(citizen_id=4, relatives=[]), generate_citizen(citizen_id=5, name="Джейн", gender="male", birth_date="2020-02-17", relatives=[5]), ] def test_get_citizens(migrated_postgres, client): r = client.post("/imports", json={"data": dataset}) import_id = r.json()["data"]["import_id"] response = client.get(f"/imports/{import_id}/citizens") assert response.status_code == 200 assert compare_citizen_groups(response.json()["data"], dataset)
Позволяет записать ожидаемый ответ в краткой форме. """ 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="2019-12-31", relatives=[2, 3]), generate_citizen(citizen_id=2, birth_date="2020-02-11", relatives=[1]), generate_citizen(citizen_id=3, birth_date="2020-02-17", relatives=[1]), ], "expected": make_response({ "2": [{ "citizen_id": 1, "presents": 2 }], "12": [{
async def test_patch_citizen(database, migrated_postgres): """ Проверяет, что данные о жителе и его родственниках успешно обновляются. """ # Перед прогоном каждого теста добавляем в БД дополнительную выгрузку с # тремя жителями и одинаковыми идентификаторами, чтобы убедиться, что # обработчик различает жителей разных выгрузок и изменения не затронут # жителей другой выгрузки. side_dataset = [ generate_citizen(citizen_id=1), generate_citizen(citizen_id=2), generate_citizen(citizen_id=3) ] side_import = Import(data=side_dataset) async with database: side_dataset_id = await analyzer.save_import(side_import, database) # Создаем выгрузку с тремя жителями, два из которых родственники для # тестирования изменений. dataset = [ generate_citizen( citizen_id=1, name="Иванов Иван Иванович", gender="male", birth_date="2020-01-01", town="Некий город", street="Некая улица", building="Некое строение", apartment=1, relatives=[2], ), generate_citizen(citizen_id=2, relatives=[1]), generate_citizen(citizen_id=3, relatives=[]), ] import_obj = Import(data=dataset) async with database: import_id = await analyzer.save_import(import_obj, database) # Обновляем часть полей о жителе, чтобы убедиться что PATCH позволяет # передавать только некоторые поля. # Данные меняем сразу в выгрузке, чтобы потом было легче сравнивать. dataset[0]["name"] = "Иванова Иванна Ивановна" patch = CitizenPatch(name=dataset[0]["name"]) async with database: await analyzer.patch_citizen(import_id, dataset[0]["citizen_id"], patch, database) # Обновляем другую часть данных, чтобы проверить что данные обновляются. dataset[0]["gender"] = "female" dataset[0]["birth_date"] = "2020-02-02" 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"]) patch = CitizenPatch.parse_obj({ "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"], }) async with database: actual = await analyzer.patch_citizen(import_id, dataset[0]["citizen_id"], patch, database) # Проверяем, что житель корректно обновился del actual["import_id"] assert compare_citizens(dataset[0], actual) # Проверяем всю выгрузку, чтобы убедиться что родственные связи всех # жителей изменились корректно. async with database: actual_citizens = await analyzer.get_citizens(import_id, database) for citizen in actual_citizens: del citizen["import_id"] assert compare_citizen_groups(actual_citizens, dataset) # Проверяем, что изменение жителя в тестируемой выгрузке не испортило # данные в дополнительной выгрузке. async with database: actual_citizens = await analyzer.get_citizens(side_dataset_id, database) for citizen in actual_citizens: del citizen["import_id"] assert compare_citizen_groups(actual_citizens, side_dataset)
и days дней. Позволяет представлять дату рождения жителя в виде возраста человека в днях и годах, что гораздо нагляднее в тестах. """ _today = date.today() birth_date = _today.replace(year=_today.year - years) birth_date -= timedelta(days=days) return birth_date.strftime("%Y-%m-%d") 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.0, "p75": 40.0, "p99": 49.6 }], },