Files
blog.pyaqa.ru/tests/FEATURE_INFRASTRUCTURE.md
Sergey Vanyushkin 46cc06b596 feat: RBAC E2E тесты и фикс admin-прав для редактирования постов
Основные изменения:
- Добавлены E2E тесты для проверки ownership (TC-E2E-102/103):
  * test_admin_can_edit_any_post — admin может редактировать любой пост
  * test_user_cannot_edit_other_users_post — user не может редактировать чужой пост
- Исправлены use cases (UpdatePost, DeletePost, PublishPost) — добавлена проверка роли admin
- Обновлены web routes и API routes для передачи роли в use cases
- Добавлены unit тесты для admin-сценариев

Реструктуризация тестов:
- Удалены старые API тесты (tests/api/) — требуют переработки
- Удалены старые integration тесты (tests/integration/)
- Переработаны E2E тесты: удалены старые, добавлены новые с POM
- Добавлена документация тестов: FEATURE_*.md, TEST_MODEL.md, AGENTS.md

Инфраструктура:
- Добавлен MockKeycloakClient для dev-режима
- Добавлены статические файлы: EasyMDE, Highlight.js, стили markdown
- Обновлены шаблоны: base.html, post_form.html, post_detail.html
- Обновлена DI конфигурация и провайдеры

Документация:
- tests/FEATURE_RBAC.md — матрица тестов RBAC
- tests/FEATURE_POST_LIFECYCLE.md — тесты жизненного цикла поста
- tests/FEATURE_DOMAIN_FOUNDATION.md — тесты доменного слоя
- tests/FEATURE_INFRASTRUCTURE.md — тесты инфраструктуры
- tests/TEST_MODEL.md — глобальная матрица покрытия
- app/presentation/web/AGENTS.md — гайд по Web UI
- tests/AGENTS.md — гайд по тестированию
2026-05-07 19:55:15 +03:00

336 lines
13 KiB
Markdown

# Test Model: Infrastructure & Bootstrap
Feature: Application initialization, configuration, authentication client,
and transaction management. These tests validate the plumbing layer that
supports the domain and application layers.
## Unit Test Cases
### App Bootstrap
#### TC-UNIT-501: Lifespan — Init and Close
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/test_main.py::test_lifespan`
- **Preconditions:** Mock `init_db` and `close_db`
- **Steps:** Enter and exit lifespan context manager
- **Expected:**
- `init_db` called once on enter
- `close_db` called once on exit
- `close_db` not called during context
- **Last Verified:** 2026-05-07
#### TC-UNIT-502: App Factory — Creates FastAPI App
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/test_main.py::test_app_factory`
- **Expected:** Returns `FastAPI` instance
- **Last Verified:** 2026-05-07
#### TC-UNIT-503: App Factory — Has Routes
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/test_main.py::test_app_factory_has_routes`
- **Expected:** `/health` route exists; API routes registered
- **Last Verified:** 2026-05-07
#### TC-UNIT-504: Main — Starts Uvicorn
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/test_main.py::test_main`
- **Preconditions:** Mock `uvicorn.run`
- **Expected:**
- `uvicorn.run` called with `factory=True`
- `host="0.0.0.0"`, `port=8000`
- **Last Verified:** 2026-05-07
### Configuration
#### TC-UNIT-601: Settings — Default Values
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestSettings::test_default_values`
- **Expected:**
- `app.name == "Blog API"`
- `app.debug is False`
- `database_url == "sqlite+aiosqlite:///./blog.db"` (dev default)
- `environment == Environment.DEV`
- **Last Verified:** 2026-05-07
#### TC-UNIT-602: Settings — Custom Values
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestSettings::test_custom_values`
- **Expected:** Custom app, db, and env values applied correctly
- **Last Verified:** 2026-05-07
#### TC-UNIT-603: Settings — is_dev / is_prod Properties
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestSettings::test_is_dev_property`, `test_is_prod_property`
- **Expected:** Boolean properties match environment enum
- **Last Verified:** 2026-05-07
#### TC-UNIT-604: Settings — Prod Requires Security Secret
- **Type:** Negative
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestSettings::test_prod_requires_security_secret`
- **Expected:** Raises `ValueError` with `SECURITY_SECRET_KEY` when secret is empty in prod
- **Last Verified:** 2026-05-07
#### TC-UNIT-605: Settings — Prod Requires KC Secret
- **Type:** Negative
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestSettings::test_prod_requires_kc_secret`
- **Expected:** Raises `ValueError` with `KC_CLIENT_SECRET` when KC secret is empty in prod
- **Last Verified:** 2026-05-07
#### TC-UNIT-606: Settings — Database URL Dev Default
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestSettings::test_database_url_dev_default`
- **Expected:** Dev mode defaults to SQLite async URL
- **Last Verified:** 2026-05-07
#### TC-UNIT-607: Settings — Database URL Prod Builds Postgres
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestSettings::test_database_url_prod_builds_postgres`
- **Expected:** When `db.url` is None in prod, URL built from host/port/user/password/name
- **Last Verified:** 2026-05-07
#### TC-UNIT-608: Settings — Database URL Override
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestSettings::test_database_url_override`
- **Expected:** Explicit `db.url` overrides auto-building in prod
- **Last Verified:** 2026-05-07
#### TC-UNIT-609: AppConfig — Defaults
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestAppConfig::test_default_values`
- **Expected:** Default name, debug, host, port values
- **Last Verified:** 2026-05-07
#### TC-UNIT-610: DBConfig — Defaults
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestDBConfig::test_default_values`
- **Expected:** Default PostgreSQL connection params
- **Last Verified:** 2026-05-07
#### TC-UNIT-611: DBConfig — URL Validation (Postgres)
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestDBConfig::test_postgres_url_validation`
- **Expected:** Postgres URL accepted
- **Last Verified:** 2026-05-07
#### TC-UNIT-612: DBConfig — URL Validation (SQLite)
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestDBConfig::test_sqlite_url_validation`
- **Expected:** SQLite URL accepted
- **Last Verified:** 2026-05-07
#### TC-UNIT-613: DBConfig — URL Validation Rejects Invalid
- **Type:** Negative
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestDBConfig::test_invalid_url_validation`
- **Expected:** Raises `ValueError` for non-SQLite/non-Postgres URLs
- **Last Verified:** 2026-05-07
#### TC-UNIT-614: KCConfig — Defaults
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestKCConfig::test_default_values`
- **Expected:** Default Keycloak server, realm, client settings
- **Last Verified:** 2026-05-07
#### TC-UNIT-615: KCConfig — is_configured With Secret
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestKCConfig::test_is_configured_with_secret`
- **Expected:** `is_configured is True` when `client_secret` is set
- **Last Verified:** 2026-05-07
#### TC-UNIT-616: KCConfig — is_configured Without Secret
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestKCConfig::test_is_configured_without_secret`
- **Expected:** `is_configured is False` when `client_secret` is empty
- **Last Verified:** 2026-05-07
#### TC-UNIT-617: SecurityConfig — Defaults
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestSecurityConfig::test_default_values`
- **Expected:** Default token expiration (30 min)
- **Last Verified:** 2026-05-07
#### TC-UNIT-618: SecurityConfig — is_configured
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestSecurityConfig::test_is_configured_with_secret`, `test_is_configured_without_secret`
- **Expected:** `is_configured` reflects secret presence
- **Last Verified:** 2026-05-07
#### TC-UNIT-619: Environment Enum — Values
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_config.py::TestEnvironment::test_dev_value`, `test_prod_value`
- **Expected:** `DEV.value == "dev"`, `PROD.value == "prod"`
- **Last Verified:** 2026-05-07
### Authentication Client
#### TC-UNIT-701: TokenInfo — Valid Token
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestTokenInfo::test_token_info_valid`
- **Expected:** `is_valid is True`, all fields populated
- **Last Verified:** 2026-05-07
#### TC-UNIT-702: TokenInfo — Inactive Token
- **Type:** Negative
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestTokenInfo::test_token_info_invalid_not_active`
- **Expected:** `is_valid is False`
- **Last Verified:** 2026-05-07
#### TC-UNIT-703: TokenInfo — Missing user_id
- **Type:** Negative
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestTokenInfo::test_token_info_invalid_no_user_id`
- **Expected:** `is_valid is False`
- **Last Verified:** 2026-05-07
#### TC-UNIT-704: TokenInfo — Empty Roles
- **Type:** Edge
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestTokenInfo::test_token_info_empty_roles`
- **Expected:** `is_valid is True`, roles is empty list
- **Last Verified:** 2026-05-07
#### TC-UNIT-705: KeycloakUser — Creation
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakUser::test_keycloak_user_creation`
- **Expected:** All fields stored correctly
- **Last Verified:** 2026-05-07
#### TC-UNIT-706: KeycloakUser — Defaults
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakUser::test_keycloak_user_defaults`
- **Expected:** Optional fields default to empty strings / lists
- **Last Verified:** 2026-05-07
#### TC-UNIT-707: KeycloakAuthClient — Initialization
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakAuthClient::test_client_initialization`
- **Expected:** Base URL and credentials set from settings
- **Last Verified:** 2026-05-07
#### TC-UNIT-708: KeycloakAuthClient — Introspection URL
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakAuthClient::test_get_introspection_url`
- **Expected:** URL built from settings (server_url, realm)
- **Last Verified:** 2026-05-07
#### TC-UNIT-709: KeycloakAuthClient — Userinfo URL
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakAuthClient::test_get_userinfo_url`
- **Expected:** URL built from settings
- **Last Verified:** 2026-05-07
#### TC-UNIT-710: KeycloakAuthClient — Introspect Success
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakAuthClient::test_introspect_token_success`
- **Preconditions:** Mock `httpx.AsyncClient` with active token response
- **Expected:** Returns `TokenInfo` with active=True, roles parsed from realm_access
- **Last Verified:** 2026-05-07
#### TC-UNIT-711: KeycloakAuthClient — Introspect Inactive Token
- **Type:** Negative
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakAuthClient::test_introspect_token_inactive`
- **Expected:** Returns `TokenInfo` with active=False, is_valid=False
- **Last Verified:** 2026-05-07
#### TC-UNIT-712: KeycloakAuthClient — Introspect HTTP Error
- **Type:** Negative
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakAuthClient::test_introspect_token_http_error`
- **Expected:** Returns inactive `TokenInfo` (graceful degradation)
- **Last Verified:** 2026-05-07
#### TC-UNIT-713: KeycloakAuthClient — Introspect Uses Cache
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakAuthClient::test_introspect_token_uses_cache`
- **Expected:** Second call with same token uses cache; HTTP client called only once
- **Last Verified:** 2026-05-07
#### TC-UNIT-714: KeycloakAuthClient — Get Userinfo Success
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakAuthClient::test_get_userinfo_success`
- **Expected:** Returns `KeycloakUser` with all profile fields
- **Last Verified:** 2026-05-07
#### TC-UNIT-715: KeycloakAuthClient — Get Userinfo Error
- **Type:** Negative
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakAuthClient::test_get_userinfo_error`
- **Expected:** Returns `None` on HTTP error
- **Last Verified:** 2026-05-07
#### TC-UNIT-716: KeycloakAuthClient — Introspect Without Realm Roles
- **Type:** Edge
- **Layer:** Unit
- **File:** `unit/infrastructure/test_auth.py::TestKeycloakAuthClient::test_introspect_token_no_realm_roles`
- **Expected:** Returns active token with empty roles list
- **Last Verified:** 2026-05-07
### Transaction Manager
#### TC-UNIT-801: SessionTransactionManager — Commit
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_transaction_manager.py::TestSessionTransactionManager::test_commit`
- **Expected:** Calls `session.commit` once
- **Last Verified:** 2026-05-07
#### TC-UNIT-802: SessionTransactionManager — Rollback
- **Type:** Positive
- **Layer:** Unit
- **File:** `unit/infrastructure/test_transaction_manager.py::TestSessionTransactionManager::test_rollback`
- **Expected:** Calls `session.rollback` once
- **Last Verified:** 2026-05-07
## Coverage Summary
| Component | Cases | Status |
|-----------|-------|--------|
| App Bootstrap | 4 | ✅ Lifespan, factory, routes, main entry |
| Settings & Config | 19 | ✅ Defaults, overrides, validation, env checks |
| Keycloak Auth Client | 16 | ✅ Token introspection, userinfo, caching, errors |
| Transaction Manager | 2 | ⚠️ Only commit/rollback; missing nested tx, error handling |
## Gaps (Not Yet Covered)
- [ ] TC-UNIT-803: Transaction Manager — rollback on exception
- [ ] TC-UNIT-804: Transaction Manager — nested transaction behavior
- [ ] TC-UNIT-805: KeycloakAuthClient — cache expiration (TTL)
- [ ] TC-UNIT-806: KeycloakAuthClient — cache key isolation per token
- [ ] TC-UNIT-807: Settings — prod database URL building with missing components
- [ ] TC-UNIT-808: App Factory — CORS middleware configuration
- [ ] TC-UNIT-809: App Factory — static files mounting
- [ ] TC-UNIT-810: App Factory — error handler registration