Пункт 12 ревью 2026-09-28 17:35 (docs/changes/026): tests/test_app.py (936 строк) разнесён на test_security, test_devices, test_operations, test_backups, test_events, test_ids_migrations, test_architecture; общие хелперы — tests/helpers.py. Тела тестов не менялись (AST совпадает). security.reset_all_failures() — фикстура сбрасывает счётчики попыток по всем ключам, тесты не зависят от порядка. Тесты: 36 из 36 полным прогоном, каждый модуль отдельно и в обратном порядке; тест-линтер после переноса проверен мутацией. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.6 KiB
План: 026 — тесты по модулям (п. 12 ревью)
Context
Ревью docs/reviews/2026-09-28-1735-codebase-review.md, п. 12: все тесты — в одном tests/test_app.py (936 строк, 36 тестов),
файл растёт с каждым изменением (570 → 753 → 936). Трудно найти тест по области, конфликтуют правки параллельных изменений.
Нужно разнести тесты по модулям предметных областей без изменения логики тестов.
Решений пользователя не требуется: чисто структурное изменение; код приложения и стенд не затрагиваются (тесты не входят в образ).
Изменения
Модули (tests/)
| Файл | Тесты |
|---|---|
test_security.py |
test_password_encryption_roundtrip, test_api_auth_and_no_password_leak, test_insecure_settings_rejects_weak_secrets_without_leaking_them, test_insecure_settings_rejects_invalid_trusted_proxies, test_client_ip_trusted_proxies, test_app_refuses_to_start_with_insecure_config, test_login_lockout_by_ip, test_login_lockout_by_ip_behind_trusted_proxy, test_move_redirect_rejects_open_redirect_next, test_process_lock_blocks_second_process |
test_devices.py |
test_status_parsing, test_chr_status_and_version_compare, test_groups_and_device_filters, test_create_device_via_ui_binds_group, test_device_name_is_immutable, test_poll_marks_offline_and_recovers, test_ros_state_values |
test_operations.py |
test_firmware_reboots_on_log_message, test_batch_channel_runs_as_jobs, test_run_ros_downgrade_order_and_failures, test_downgrade_api_endpoints, test_ui_downgrade_dialog_and_mismatch |
test_backups.py |
test_backup_flow, test_backup_filters, test_bulk_delete_backups, test_backup_files_get_ids_and_deletion_is_recorded, test_bucket_list_is_cached_between_reads |
test_events.py |
test_events_link_entities, test_events_api_and_id_validation, test_journal_rotation_by_age_and_count, test_journal_clear_requires_password_through_modal, test_journal_page_filters_cursor_dialogs_and_settings (+ хелпер _fill_events) |
test_ids_migrations.py |
test_ids_are_unique_typed_and_ordered, test_migration_replaces_numeric_ids, test_migration_adds_legacy_columns_before_id_migration (+ LEGACY_DDL, LEGACY_DDL_NO_EXTRA_COLUMNS) |
test_architecture.py |
test_no_sync_db_calls_in_async_functions (путь к app/ — через Path(__file__), работает и из нового файла) |
- Общие хелперы
ros_client,_request→tests/helpers.py(импортfrom tests.helpers import …); константы секретов остаются вconftest.py. - В каждом модуле — только нужные ему импорты (без «всё из всего»).
- Тела тестов переносятся без изменений. Допустимы только правки импортов и, при необходимости, изоляции (ниже).
tests/test_app.pyудаляется.
Изоляция тестов (tests/conftest.py)
- Счётчики неудачных попыток (
security._fails,security._locked_until) — состояние процесса; сейчас фикстура сбрасывает только ключиadminиlogin:testclient, а тесты используют и другие IP (10.0.0.x,1.1.1.1). После разбиения порядок выполнения меняется — сбрасывать все счётчики в автоиспользуемой фикстуре: добавить вapp/security.pyфункциюreset_all_failures()(для тестов и будущего администрирования) и вызывать её вместо двух точечных сбросов.
Тесты
Логика тестов не меняется. Критерий — тот же набор из 36 тестов, все зелёные, в том числе при запуске каждого модуля отдельно.
Документация
README: «Архитектура» (дерево — tests/ по модулям), «Тесты» (как запустить модуль), строка 026 в истории. summary.md — оркестратор.
Исполнение
Исполнитель (Sonnet): перенос, helpers.py, conftest.py, reset_all_failures, README. Тесты не запускает, не коммитит. Стенд не пересобирается
(код приложения меняется только добавлением reset_all_failures, которую приложение не вызывает).
Проверка (оркестратор)
- Набор имён тестов до и после совпадает (36; список «до» сохранён оркестратором).
pytest -q— все зелёные; каждый модуль отдельно — зелёный (ловит скрытые зависимости от порядка и импортов); обратный порядок модулей (pytest tests/test_security.py … в обратном порядке) — зелёный.tests/test_app.pyотсутствует;grepтел тестов: построчное сравнение тел функций до/после (AST-дамп тел тестов совпадает).