citesting-fix1
Some checks failed
Deploy on push / deploy (push) Failing after 2m0s

This commit is contained in:
2025-08-17 11:37:55 +03:00
parent 4b88a8c449
commit bc8447a444
6 changed files with 648 additions and 227 deletions

View File

@@ -578,3 +578,28 @@ def redis_client():
redis_service = RedisService()
return redis_service._client
# Mock для Redis если он недоступен
@pytest.fixture(autouse=True)
def mock_redis_if_unavailable():
"""Автоматически мокает Redis если он недоступен"""
try:
import redis
# Пробуем подключиться к Redis
r = redis.Redis(host='localhost', port=6379, socket_connect_timeout=1)
r.ping()
# Redis доступен, не мокаем
yield
except Exception:
# Redis недоступен, мокаем
with patch('services.redis.RedisService') as mock_redis:
# Создаем базовый mock для Redis методов
mock_redis.return_value.get.return_value = None
mock_redis.return_value.set.return_value = True
mock_redis.return_value.delete.return_value = True
mock_redis.return_value.exists.return_value = False
mock_redis.return_value.ping.return_value = True
mock_redis.return_value.is_connected = False
yield

View File

@@ -6,41 +6,81 @@
import asyncio
import time
import os
import requests
from playwright.async_api import async_playwright
async def wait_for_server_ready(url: str, timeout: int = 60) -> bool:
"""Ждем готовности сервера"""
start_time = time.time()
while time.time() - start_time < timeout:
try:
response = requests.get(url, timeout=5)
if response.status_code == 200:
return True
except:
pass
await asyncio.sleep(2)
return False
async def test_delete_button(frontend_url):
"""Тест поиска кнопки удаления с улучшенной обработкой ошибок"""
# Проверяем готовность фронтенда
print(f"🌐 Проверяем готовность фронтенда {frontend_url}...")
if not await wait_for_server_ready(frontend_url):
print(f"❌ Фронтенд {frontend_url} не готов в течение 60 секунд")
return False
print(f"✅ Фронтенд {frontend_url} готов")
async with async_playwright() as p:
# Определяем headless режим из переменной окружения
headless_mode = os.getenv("PLAYWRIGHT_HEADLESS", "false").lower() == "true"
headless_mode = os.getenv("PLAYWRIGHT_HEADLESS", "true").lower() == "true"
print(f"🔧 Headless режим: {headless_mode}")
browser = await p.chromium.launch(headless=headless_mode)
browser = await p.chromium.launch(
headless=headless_mode,
args=['--no-sandbox', '--disable-dev-shm-usage']
)
page = await browser.new_page()
# Увеличиваем таймауты для CI
page.set_default_timeout(30000) # 30 секунд
page.set_default_navigation_timeout(30000)
try:
print(f"🌐 Открываем админ-панель на {frontend_url}...")
await page.goto(f"{frontend_url}/login")
await page.wait_for_load_state("networkidle")
await page.goto(f"{frontend_url}/login", wait_until="networkidle")
print("✅ Страница логина загружена")
print("🔐 Авторизуемся...")
# Ждем появления полей ввода
await page.wait_for_selector('input[type="email"]', timeout=15000)
await page.wait_for_selector('input[type="password"]', timeout=15000)
await page.fill('input[type="email"]', "test_admin@discours.io")
await page.fill('input[type="password"]', "password123")
await page.click('button[type="submit"]')
# Ждем авторизации
await page.wait_for_url(f"{frontend_url}/admin/**", timeout=10000)
# Ждем авторизации с увеличенным таймаутом
await page.wait_for_url(f"{frontend_url}/admin/**", timeout=20000)
print("✅ Авторизация успешна")
print("📋 Переходим на страницу сообществ...")
await page.goto(f"{frontend_url}/admin/communities")
await page.wait_for_load_state("networkidle")
await page.goto(f"{frontend_url}/admin/communities", wait_until="networkidle")
print("✅ Страница сообществ загружена")
print("🔍 Ищем таблицу сообществ...")
await page.wait_for_selector("table", timeout=10000)
await page.wait_for_selector("table tbody tr", timeout=10000)
await page.wait_for_selector("table", timeout=15000)
await page.wait_for_selector("table tbody tr", timeout=15000)
print("✅ Таблица сообществ найдена")
# Создаем папку для скриншотов если её нет
os.makedirs("test-results", exist_ok=True)
print("📸 Делаем скриншот таблицы...")
await page.screenshot(path="test-results/communities_table_debug.png")
@@ -112,15 +152,25 @@ async def test_delete_button(frontend_url):
class_name = await btn.get_attribute("class")
print(f" Кнопка {i}: текст='{text}', класс='{class_name}'")
return True
else:
print("❌ Строка с Test Community не найдена")
return False
except Exception as e:
print(f"❌ Ошибка: {e}")
# Создаем папку для скриншотов если её нет
os.makedirs("test-results", exist_ok=True)
await page.screenshot(path=f"test-results/error_{int(time.time())}.png")
return False
finally:
await browser.close()
if __name__ == "__main__":
asyncio.run(test_delete_button())
result = asyncio.run(test_delete_button("http://localhost:3000"))
if result:
print("✅ Тест завершен успешно")
else:
print("❌ Тест завершен с ошибками")
exit(1)

View File

@@ -4,41 +4,72 @@
"""
import json
import time
import requests
def wait_for_server_ready(url: str, timeout: int = 60) -> bool:
"""Ждем готовности сервера"""
start_time = time.time()
while time.time() - start_time < timeout:
try:
response = requests.get(url, timeout=10)
if response.status_code == 200:
return True
except:
pass
time.sleep(2)
return False
def test_delete_new_community():
"""Тестируем удаление нового сообщества через API"""
# Проверяем готовность бэкенда
print("🌐 Проверяем готовность бэкенда...")
if not wait_for_server_ready("http://localhost:8000"):
print("❌ Бэкенд не готов в течение 60 секунд")
return False
print("✅ Бэкенд готов")
# 1. Авторизуемся как test_admin@discours.io
print("🔐 Авторизуемся как test_admin@discours.io...")
login_response = requests.post(
"http://localhost:8000/graphql",
headers={"Content-Type": "application/json"},
json={
"query": """
mutation Login($email: String!, $password: String!) {
login(email: $email, password: $password) {
success
token
author {
id
name
email
try:
login_response = requests.post(
"http://localhost:8000/graphql",
headers={"Content-Type": "application/json"},
json={
"query": """
mutation Login($email: String!, $password: String!) {
login(email: $email, password: $password) {
success
token
author {
id
name
email
}
error
}
}
error
}
}
""",
"variables": {"email": "test_admin@discours.io", "password": "password123"},
},
)
""",
"variables": {"email": "test_admin@discours.io", "password": "password123"},
},
timeout=30 # Увеличиваем таймаут
)
except requests.exceptions.Timeout:
print("❌ Таймаут при авторизации")
return False
except requests.exceptions.ConnectionError:
print("❌ Ошибка подключения к бэкенду")
return False
login_data = login_response.json()
if not login_data.get("data", {}).get("login", {}).get("success"):
print("❌ Ошибка авторизации test_admin@discours.io")
return
print(f"Ответ: {json.dumps(login_data, indent=2, ensure_ascii=False)}")
return False
token = login_data["data"]["login"]["token"]
user_id = login_data["data"]["login"]["author"]["id"]
@@ -46,26 +77,31 @@ def test_delete_new_community():
# 2. Проверяем, что сообщество существует
print("🔍 Проверяем существование сообщества...")
communities_response = requests.post(
"http://localhost:8000/graphql",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={
"query": """
query GetCommunities {
get_communities_all {
id
name
slug
created_by {
id
name
email
try:
communities_response = requests.post(
"http://localhost:8000/graphql",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={
"query": """
query GetCommunities {
get_communities_all {
id
name
slug
created_by {
id
name
email
}
}
}
}
}
"""
},
)
""",
},
timeout=30 # Увеличиваем таймаут
)
except requests.exceptions.Timeout:
print("❌ Таймаут при получении списка сообществ")
return False
communities_data = communities_response.json()
target_community = None
@@ -76,29 +112,37 @@ def test_delete_new_community():
if not target_community:
print("❌ Сообщество test-admin-community-e2e-1754005730 не найдено")
return
print("Доступные сообщества:")
for community in communities_data.get("data", {}).get("get_communities_all", []):
print(f" - {community['name']} (slug: {community['slug']})")
return False
print(f"✅ Найдено сообщество: {target_community['name']} (ID: {target_community['id']})")
print(f" Создатель: {target_community['created_by']['name']} (ID: {target_community['created_by']['id']})")
# 3. Пытаемся удалить сообщество
print("🗑️ Пытаемся удалить сообщество...")
delete_response = requests.post(
"http://localhost:8000/graphql",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={
"query": """
mutation DeleteCommunity($slug: String!) {
delete_community(slug: $slug) {
success
message
error
}
}
""",
"variables": {"slug": "test-admin-community-e2e-1754005730"},
},
)
try:
delete_response = requests.post(
"http://localhost:8000/graphql",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={
"query": """
mutation DeleteCommunity($slug: String!) {
delete_community(slug: $slug) {
success
message
error
}
}
""",
"variables": {"slug": "test-admin-community-e2e-1754005730"},
},
timeout=30 # Увеличиваем таймаут
)
except requests.exceptions.Timeout:
print("❌ Таймаут при удалении сообщества")
return False
delete_data = delete_response.json()
print(f"📡 Ответ удаления: {json.dumps(delete_data, indent=2, ensure_ascii=False)}")
@@ -108,21 +152,26 @@ def test_delete_new_community():
# 4. Проверяем, что сообщество действительно удалено
print("🔍 Проверяем, что сообщество удалено...")
check_response = requests.post(
"http://localhost:8000/graphql",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={
"query": """
query GetCommunities {
get_communities_all {
id
name
slug
}
}
"""
},
)
try:
check_response = requests.post(
"http://localhost:8000/graphql",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={
"query": """
query GetCommunities {
get_communities_all {
id
name
slug
}
}
""",
},
timeout=30 # Увеличиваем таймаут
)
except requests.exceptions.Timeout:
print("❌ Таймаут при проверке удаления")
return False
check_data = check_response.json()
still_exists = False
@@ -133,13 +182,20 @@ def test_delete_new_community():
if still_exists:
print("❌ Сообщество все еще существует после удаления")
return False
else:
print("✅ Сообщество успешно удалено из базы данных")
return True
else:
print("❌ Ошибка удаления")
error = delete_data.get("data", {}).get("delete_community", {}).get("error")
print(f"Ошибка: {error}")
return False
if __name__ == "__main__":
test_delete_new_community()
if test_delete_new_community():
print("✅ Тест завершен успешно")
else:
print("❌ Тест завершен с ошибками")
exit(1)

View File

@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""
Тест здоровья серверов для CI
"""
import time
import requests
import pytest
def test_backend_health():
"""Проверяем здоровье бэкенда"""
max_retries = 10
for attempt in range(1, max_retries + 1):
try:
response = requests.get("http://localhost:8000/", timeout=10)
if response.status_code == 200:
print(f"✅ Бэкенд готов (попытка {attempt})")
return
except requests.exceptions.RequestException as e:
print(f"⚠️ Попытка {attempt}/{max_retries}: Бэкенд не готов - {e}")
if attempt < max_retries:
time.sleep(3)
else:
pytest.fail(f"Бэкенд не готов после {max_retries} попыток")
def test_frontend_health():
"""Проверяем здоровье фронтенда"""
max_retries = 10
for attempt in range(1, max_retries + 1):
try:
response = requests.get("http://localhost:3000/", timeout=10)
if response.status_code == 200:
print(f"✅ Фронтенд готов (попытка {attempt})")
return
except requests.exceptions.RequestException as e:
print(f"⚠️ Попытка {attempt}/{max_retries}: Фронтенд не готов - {e}")
if attempt < max_retries:
time.sleep(3)
else:
pytest.fail(f"Фронтенд не готов после {max_retries} попыток")
def test_graphql_endpoint():
"""Проверяем доступность GraphQL endpoint"""
try:
response = requests.post(
"http://localhost:8000/graphql",
headers={"Content-Type": "application/json"},
json={"query": "{ __schema { types { name } } }"},
timeout=15
)
if response.status_code == 200:
print("✅ GraphQL endpoint доступен")
return
else:
pytest.fail(f"GraphQL endpoint вернул статус {response.status_code}")
except requests.exceptions.RequestException as e:
pytest.fail(f"GraphQL endpoint недоступен: {e}")
def test_admin_panel_access():
"""Проверяем доступность админ-панели"""
try:
response = requests.get("http://localhost:3000/admin", timeout=15)
if response.status_code == 200:
print("✅ Админ-панель доступна")
return
else:
pytest.fail(f"Админ-панель вернула статус {response.status_code}")
except requests.exceptions.RequestException as e:
pytest.fail(f"Админ-панель недоступна: {e}")
if __name__ == "__main__":
print("🧪 Проверяем здоровье серверов...")
try:
test_backend_health()
test_frontend_health()
test_graphql_endpoint()
test_admin_panel_access()
print("Все серверы здоровы!")
except Exception as e:
print(f"❌ Ошибка проверки здоровья: {e}")
exit(1)