JARVIS Docs

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 katalogu backend z 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/config i /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 TimeoutError przy BRPOP jest 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,
  • db PostgreSQL,
  • 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:

  1. CodeTest
  2. lokalny template .ado/templates/python-quality.yml,
  3. instalacja zależności produkcyjnych i developerskich,
  4. testy jednostkowe i endpointowe przez pytest,
  5. publikacja wyników testów do zakładki Tests,
  6. publikacja coverage XML/HTML,
  7. flake8,
  8. mypy,
  9. bandit z publikacją artifactu security-results.
  10. BuildContainerImage
  11. build i scan obrazu.
  12. IntegrationTests
  13. lokalny template .ado/templates/container-smoke-tests.yml,
  14. walidacja docker compose config,
  15. build i uruchomienie stacka docker compose,
  16. testy HTTP z zewnętrznego runnera,
  17. publikacja compose integration testów do zakładki Tests,
  18. usunięcie stacka przez docker compose down -v --remove-orphans.
  19. PushContainerImage
  20. push obrazu dopiero po przejściu smoke testów.
  21. NotifyDiscord
  22. opcjonalne powiadomienie Discord po udanym pushu, tylko jeśli discordWebhookUrlSecret jest 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 pytest w 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 pytest w 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.