Testy i CI/CD
Testy Lokalne
.\.venv\Scripts\python.exe -m pytest -q
albo po aktywacji venv:
python -m pytest -q
Lint
python -m flake8 backend tests
Typowanie
python -m mypy backend tests
Aktualny Wynik Walidacji
Ostatnio sprawdzony stan:
pytest tests:27 passed, 3 skipped,- container smoke tests: publikowane w Azure DevOps jako osobny test run,
flake8: uruchamiany w quality gate,mypy: uruchamiany w quality gate,bandit: uruchamiany dla katalogubackendz wynikiem publikowanym jako artifact.
Testy Jednostkowe i Endpointów
tests/test_models.py:
- testuje generowanie UUID,
- testuje hash i weryfikację hasła,
- testuje serializację
User.json(), - testuje serializację
ConversationHistory.json().
tests/test_endpoints.py:
- tworzy testową aplikację Flask,
- używa SQLite in-memory,
- mockuje zależności Azure, msrest i OpenAI,
- testuje
/livenez, - testuje
/azure/boards/add_task, - testuje publiczne GET endpointy,
- testuje redirect/unauthorized dla endpointów chronionych,
- testuje kontrakt
/chat/ask, - testuje walidację parametrów chatu,
- testuje
/speech/configi/speech/synthesize.
tests/test_memory_extractors.py:
- testuje filtrowanie low-confidence i restricted memory items,
- testuje filtrowanie placeholderów typu
favorite color,favorite hobby,preferred music genre, - testuje odrzucanie ustawień samego asystenta jako pamięci użytkownika.
tests/test_memory_service.py:
- testuje, że Redis
TimeoutErrorprzyBRPOPjest traktowany jako pusty queue poll, - testuje normalizację treści memory item dla deduplikacji.
Compose Integration Tests
tests/integration/test_container_endpoints.py testuje aplikację jako black-box HTTP.
Wymaga zmiennej:
CONTAINER_TEST_BASE_URL=http://localhost:8000
Przykład:
CONTAINER_TEST_BASE_URL=http://localhost:8000 python -m pytest tests/integration -q
Testy kontenera sprawdzają:
/livenez,/.- rejestrację użytkownika przez MockServer reCAPTCHA,
- odczyt chronionej konfiguracji speech po zalogowaniu, co weryfikuje sesję serwerową.
W CI aplikacja nie jest już uruchamiana jako pojedynczy kontener z SQLite.
Template .ado/templates/container-smoke-tests.yml uruchamia docker compose z usługami:
web,dbPostgreSQL,redis,mockserver.
Pełny lokalny Compose zawiera też memory-worker, local-llm, speaches i bootstrap services. Smoke testy kontenera koncentrują się na publicznym HTTP, rejestracji, sesji serwerowej i podstawowym kontrakcie aplikacji, a nie na kosztownym pobieraniu modeli.
Testy są nadal uruchamiane z zewnętrznego runnera, więc finalny obraz aplikacji nie musi zawierać pytest.
CI/CD
Pipeline znajduje się w azure-pipelines.yml.
Aktualny przepływ:
CodeTest- lokalny template
.ado/templates/python-quality.yml, - instalacja zależności produkcyjnych i developerskich,
- testy jednostkowe i endpointowe przez
pytest, - publikacja wyników testów do zakładki
Tests, - publikacja coverage XML/HTML,
flake8,mypy,banditz publikacją artifactusecurity-results.BuildContainerImage- build i scan obrazu.
IntegrationTests- lokalny template
.ado/templates/container-smoke-tests.yml, - walidacja
docker compose config, - build i uruchomienie stacka
docker compose, - testy HTTP z zewnętrznego runnera,
- publikacja compose integration testów do zakładki
Tests, - usunięcie stacka przez
docker compose down -v --remove-orphans. PushContainerImage- push obrazu dopiero po przejściu smoke testów.
NotifyDiscord- opcjonalne powiadomienie Discord po udanym pushu, tylko jeśli
discordWebhookUrlSecretjest ustawiony w Azure DevOps.
Dlaczego Testujemy Stack Z Zewnątrz
Poprzednie podejście uruchamiało specjalny obraz tester i odpalało pytest przez docker exec wewnątrz kontenera. Było to problematyczne, ponieważ:
- testowany był inny obraz niż finalny obraz produkcyjny,
- produkcyjny runtime mieszał się z zależnościami developerskimi,
- testy wymagały obecności
pytestw kontenerze, - pipeline mógł przejść mimo problemów specyficznych dla finalnego obrazu.
Obecne podejście:
- buduje finalny obraz w ramach stacka Compose,
- uruchamia aplikację razem z PostgreSQL, Redisem i MockServerem,
- testuje go przez HTTP z zewnątrz,
- nie wymaga
pytestw obrazie produkcyjnym.
To jest bliższe realnej architekturze JARVIS niż test pojedynczego kontenera z SQLite.
Zmienne Pipeline
pipeline-variables.yml zawiera:
dockerRegistry,dockerImage,dockerServiceConnection,pythonVersion,dockerTag.
dockerTag jest ustawiony na format <branch>-<buildId>, np. dev-1234, przez macro variables Azure Pipelines:
$(Build.SourceBranchName)-$(Build.BuildId)
Nie należy używać tutaj template expression ${{ format(...) }}, ponieważ jest rozwijane za wcześnie i Build.BuildId może być puste.
Webhook Discord nie powinien być trzymany jawnie w repo. Powinien być przekazywany przez secret variable lub variable group w Azure DevOps pod nazwą discordWebhookUrlSecret. Nazwa różni się od parametru discordWebhookURL używanego w template powiadomień, żeby uniknąć cyklicznego rozwijania zmiennych w Azure Pipelines.