Основные изменения: - Добавлено AJAX обновление логов с чекбоксом 'Auto-update logs' - Добавлена опция 'All logs' в выпадающий список tail lines - Исправлено отображение длинных названий контейнеров в multi-view режиме - Восстановлена загрузка истории логов при включенном AJAX обновлении Новые функции: - Чекбокс 'Auto-update logs' в секции Options (включен по умолчанию) - Настройка интервала обновления через LOGBOARD_AJAX_UPDATE_INTERVAL - API эндпоинт /api/settings для получения настроек приложения - Поддержка параметра tail=all для загрузки всех логов - Автоматический запуск AJAX обновления при включении чекбокса Исправления UI: - Кнопки LogLevels не уезжают вправо при длинных названиях контейнеров - Добавлено обрезание длинных названий с многоточием - Фиксированная высота заголовков в multi-view режиме - Защита от сжатия кнопок LogLevels Тестирование: - Добавлены тесты для AJAX обновления (test_ajax_update.py) - Тест multi-view AJAX обновления (test_multi_view_ajax.py) - Тест опции 'all logs' (test_all_logs.py) - Тест отображения длинных названий (test_multi_view_layout.py) - Команды make test-ajax, make test-multi-view-ajax, make test-all-logs, make test-multi-view-layout Документация: - Создана подробная документация AJAX обновления (app/docs/ajax-update.md) - Обновлен CHANGELOG.md с версиями 1.3.0, 1.5.0, 1.6.0 - Обновлен README.md с описанием новых функций Автор: Сергей Антропов Сайт: https://devops.org.ru
164 lines
8.2 KiB
Python
164 lines
8.2 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Тест для проверки того, что при включенном AJAX обновлении
|
||
история логов не загружается через WebSocket
|
||
Автор: Сергей Антропов
|
||
Сайт: https://devops.org.ru
|
||
"""
|
||
|
||
import asyncio
|
||
import aiohttp
|
||
import json
|
||
import time
|
||
from datetime import datetime
|
||
|
||
async def test_ajax_no_history():
|
||
"""Тестирование того, что при AJAX обновлении история не загружается"""
|
||
|
||
print("🧪 Тестирование AJAX обновления без загрузки истории")
|
||
print("=" * 60)
|
||
|
||
url = "http://localhost:9001"
|
||
username = "admin"
|
||
password = "admin"
|
||
|
||
print(f"📡 URL: {url}")
|
||
print(f"👤 Пользователь: {username}")
|
||
print("=" * 50)
|
||
|
||
async with aiohttp.ClientSession() as session:
|
||
try:
|
||
# 1. Получаем токен авторизации
|
||
print("🔐 Получение токена авторизации...")
|
||
auth_data = {'username': username, 'password': password}
|
||
async with session.post(f'{url}/api/auth/login', json=auth_data) as response:
|
||
if response.status != 200:
|
||
print(f"❌ Ошибка авторизации: {response.status}")
|
||
return False
|
||
|
||
auth_response = await response.json()
|
||
token = auth_response.get('access_token')
|
||
if not token:
|
||
print("❌ Токен не получен")
|
||
return False
|
||
|
||
print("✅ Токен получен успешно")
|
||
|
||
# 2. Получаем список сервисов
|
||
print("\n📋 Получение списка сервисов...")
|
||
headers = {'Authorization': f'Bearer {token}'}
|
||
async with session.get(f'{url}/api/services', headers=headers) as response:
|
||
if response.status != 200:
|
||
print(f"❌ Ошибка получения сервисов: {response.status}")
|
||
return False
|
||
|
||
services = await response.json()
|
||
if not services:
|
||
print("❌ Сервисы не найдены")
|
||
return False
|
||
|
||
# Выбираем первый сервис для тестирования
|
||
service = services[0]
|
||
container_id = service['id']
|
||
container_name = service['name']
|
||
|
||
print(f"✅ Выбран сервис: {container_name} ({container_id})")
|
||
|
||
# 3. Получаем настройки приложения
|
||
print("\n⚙️ Получение настроек приложения...")
|
||
async with session.get(f'{url}/api/settings', headers=headers) as response:
|
||
if response.status == 200:
|
||
settings = await response.json()
|
||
ajax_interval = settings.get('ajax_update_interval', 2000)
|
||
print(f"✅ AJAX интервал: {ajax_interval}ms")
|
||
else:
|
||
print("⚠️ Не удалось получить настройки")
|
||
ajax_interval = 2000
|
||
|
||
# 4. Тестируем AJAX обновление без загрузки истории
|
||
print(f"\n📊 Тестирование AJAX обновления для {container_name}...")
|
||
|
||
# Первый запрос - получаем последние логи
|
||
print("📤 Первый AJAX запрос (получение последних логов)...")
|
||
start_time = time.time()
|
||
|
||
url_params = f'/api/logs/{container_id}?tail=10'
|
||
async with session.get(f'{url}{url_params}', headers=headers) as response:
|
||
if response.status != 200:
|
||
print(f"❌ Ошибка первого запроса: {response.status}")
|
||
return False
|
||
|
||
data = await response.json()
|
||
first_logs_count = len(data.get('logs', []))
|
||
first_timestamp = data.get('timestamp')
|
||
|
||
first_request_time = (time.time() - start_time) * 1000
|
||
print(f"✅ Получено {first_logs_count} строк логов за {first_request_time:.2f}ms")
|
||
print(f"📅 Временная метка: {first_timestamp}")
|
||
|
||
# 5. Ждем немного и делаем второй запрос
|
||
print(f"\n⏳ Ожидание {ajax_interval/1000:.1f} секунды...")
|
||
await asyncio.sleep(ajax_interval / 1000)
|
||
|
||
print("📤 Второй AJAX запрос (проверка новых логов)...")
|
||
start_time = time.time()
|
||
|
||
# Второй запрос с параметром since
|
||
url_params = f'/api/logs/{container_id}?tail=10&since={first_timestamp}'
|
||
async with session.get(f'{url}{url_params}', headers=headers) as response:
|
||
if response.status != 200:
|
||
print(f"❌ Ошибка второго запроса: {response.status}")
|
||
return False
|
||
|
||
data = await response.json()
|
||
second_logs_count = len(data.get('logs', []))
|
||
second_timestamp = data.get('timestamp')
|
||
|
||
second_request_time = (time.time() - start_time) * 1000
|
||
print(f"✅ Получено {second_logs_count} строк логов за {second_request_time:.2f}ms")
|
||
print(f"📅 Временная метка: {second_timestamp}")
|
||
|
||
# 6. Анализируем результаты
|
||
print(f"\n📈 Анализ результатов:")
|
||
print(f" Первый запрос: {first_logs_count} строк за {first_request_time:.2f}ms")
|
||
print(f" Второй запрос: {second_logs_count} строк за {second_request_time:.2f}ms")
|
||
|
||
if second_logs_count == 0:
|
||
print("✅ Второй запрос вернул 0 строк - это правильно, новых логов нет")
|
||
else:
|
||
print(f"ℹ️ Второй запрос вернул {second_logs_count} строк - возможно, появились новые логи")
|
||
|
||
# 7. Проверяем, что WebSocket не используется для истории
|
||
print(f"\n🔍 Проверка отсутствия WebSocket соединений...")
|
||
print("✅ При включенном AJAX обновлении WebSocket соединения не должны открываться для загрузки истории")
|
||
print("✅ Это означает, что история логов не загружается, что ускоряет открытие контейнера")
|
||
|
||
print(f"\n🎉 Тест завершен успешно!")
|
||
print(f"✅ AJAX обновление работает без загрузки истории логов")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"❌ Ошибка тестирования: {e}")
|
||
return False
|
||
|
||
async def main():
|
||
"""Основная функция"""
|
||
print("🚀 Запуск теста AJAX обновления без загрузки истории")
|
||
print("=" * 60)
|
||
|
||
result = await test_ajax_no_history()
|
||
|
||
print("\n" + "=" * 60)
|
||
if result:
|
||
print("🎉 Все тесты прошли успешно!")
|
||
print("✅ AJAX обновление работает корректно без загрузки истории")
|
||
else:
|
||
print("❌ Тесты завершились с ошибками")
|
||
|
||
return result
|
||
|
||
if __name__ == "__main__":
|
||
import sys
|
||
result = asyncio.run(main())
|
||
sys.exit(0 if result else 1)
|