import os from typing import Any, Dict import pytest pytestmark = pytest.mark.api try: from fastapi.testclient import TestClient except Exception: TestClient = None # type: ignore @pytest.mark.skipif(TestClient is None, reason="FastAPI TestClient not available") def test_system_health_and_info(fastapi_client: Any): """ Базовые системные эндпоинты должны отвечать 200 и содержать ожидаемые поля. """ r = fastapi_client.get("/api/system/health") assert r.status_code == 200, f"/api/system/health status != 200: {r.status_code}, body={r.text}" data = r.json() assert isinstance(data, dict), "health response must be JSON object" r2 = fastapi_client.get("/api/system/info") assert r2.status_code == 200, f"/api/system/info status != 200: {r2.status_code}, body={r2.text}" data2 = r2.json() assert isinstance(data2, dict), "info response must be JSON object" @pytest.mark.skipif(TestClient is None, reason="FastAPI TestClient not available") def test_ping_endpoint(fastapi_client: Any): r = fastapi_client.get("/api/v1/ping") assert r.status_code in (200, 404), f"/api/v1/ping unexpected status: {r.status_code}" # Некоторые билды могут не иметь /api/v1/ping; тогда этот тест не фейлится жестко. @pytest.mark.skipif(TestClient is None, reason="FastAPI TestClient not available") def test_node_endpoints_exist(fastapi_client: Any): """ Проверяем наличие критических узловых маршрутов из docs/API_ENDPOINTS_CHECK.md. """ # Мягкая проверка: если нет — не падаем, а логируем статус for path in [ "/api/node/network/status", "/api/node/network/ping", "/api/node/content/sync", "/api/system/metrics", ]: resp = fastapi_client.get(path) assert resp.status_code in (200, 401, 405, 404), f"{path} unexpected status {resp.status_code}" @pytest.mark.skipif(TestClient is None, reason="FastAPI TestClient not available") def test_auth_twa_and_me_flow_if_enabled(fastapi_client: Any): """ Если присутствует TWA аутентификация, проверяем базовый контракт. """ # /auth.twa обычно POST; без реального TWA токена ожидаем 400/401. resp = fastapi_client.post("/auth.twa", json={"payload": "invalid"}) assert resp.status_code in (400, 401, 404, 405), f"Unexpected status for /auth.twa: {resp.status_code}" # /api/v1/auth/me обычно требует JWT — без токена ожидаем 401 resp2 = fastapi_client.get("/api/v1/auth/me") assert resp2.status_code in (401, 404), f"Unexpected status for /api/v1/auth/me: {resp2.status_code}" @pytest.mark.skipif(TestClient is None, reason="FastAPI TestClient not available") def test_storage_upload_flow_smoke(fastapi_client: Any, small_sample_bytes: bytes): """ Смоук тест контракта загрузки: наличие маршрутов и ожидаемые статусы. Реальная загрузка чанками покрывается интеграционными/сквозными тестами. """ # Инициируем загрузку (если реализовано) init_paths = ["/api/storage", "/api/storage/api/v1/storage/upload"] init_ok = False for path in init_paths: r = fastapi_client.get(path) if r.status_code in (200, 405): # 405 = метод не тот, но маршрут существует init_ok = True break assert init_ok, "Storage upload init endpoints missing" # Попытка отправить чанк (ожидаем 400/401/404/405 без корректных параметров) r2 = fastapi_client.post("/api/storage/upload/chunk", json={"upload_id": "x", "index": 0, "data": "AA=="}) assert r2.status_code in (400, 401, 404, 405), f"Unexpected status for upload/chunk: {r2.status_code}" # Завершение r3 = fastapi_client.post("/api/storage/upload/complete", json={"upload_id": "x"}) assert r3.status_code in (400, 401, 404, 405), f"Unexpected status for upload/complete: {r3.status_code}" @pytest.mark.skipif(TestClient is None, reason="FastAPI TestClient not available") def test_content_access_routes_present(fastapi_client: Any): """ Проверка наличия маршрутов доступа к контенту, описанных в открытых файлах: """ for path in [ "/content.view/unknown", "/api/system/ready", "/api/system/live", "/", "/api", ]: resp = fastapi_client.get(path) assert resp.status_code in (200, 404, 405), f"{path} unexpected status {resp.status_code}"