/
liquid-g
/
liquid-code
Обзор
Документация
Войти
/
liquid-g
/
liquid-code
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
tests/test_application.py
602 строки
19 KB
User
ci: настроен Black и flake8 для автоматического форматирования кода
04 июл 2026, 08:14
04 июл 2026, 08:14
4778ed6
Код
Авторство
О чём код?
"""Интеграционные тесты для Application.""" import pytest import tempfile import os import yaml from unittest.mock import Mock, patch from liquidcode.application import Application from liquidcode.kernel import Kernel from liquidcode.routing import Router from liquidcode.container import Container from liquidcode.http import HttpResponse class TestApplicationInit: """Тесты инициализации Application.""" def test_init_default(self): """Инициализация с дефолтными значениями.""" app = Application() assert isinstance(app.container, Container) assert isinstance(app.router, Router) assert isinstance(app.kernel, Kernel) assert app.host == "localhost" assert app.port == 8000 assert app._static_prefix == "/static" assert app._static_dir == "public" assert app._template_dir == "templates" def test_init_with_custom_container(self): """Инициализация с кастомным контейнером.""" container = Container() app = Application(container=container) assert app.container == container def test_init_with_response_class(self): """Инициализация с кастомным классом ответа.""" class CustomResponse: def get_content(self): return None def get_status(self): return 200 def get_headers(self): return {} def set_header(self, key, value): pass def set_content(self, content): pass def set_status(self, status): pass app = Application(response_class=CustomResponse) assert app.kernel.response_class == CustomResponse def test_init_with_profiler(self): """Инициализация с профайлером.""" app = Application(profiler_enabled=True) assert app.kernel.profiler_enabled is True class TestApplicationEnv: """Тесты работы с переменными окружения.""" def test_load_env_file(self): """Загрузка .env файла.""" with tempfile.TemporaryDirectory() as tmpdir: env_file = os.path.join(tmpdir, ".env") with open(env_file, "w") as f: f.write("HOST=localhost\nPORT=8080\n") app = Application() app.load_env(env_file) # Values are loaded into os.environ assert os.environ.get("HOST") == "localhost" assert os.environ.get("PORT") == "8080" def test_load_env_empty_file(self): """Загрузка пустого .env файла.""" with tempfile.TemporaryDirectory() as tmpdir: env_file = os.path.join(tmpdir, ".env") with open(env_file, "w") as f: f.write("") app = Application() app.load_env(env_file) class TestApplicationConfig: """Тесты загрузки конфигурации.""" def test_load_config(self): """Загрузка конфигурационного файла.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = os.path.join(tmpdir, "config.yaml") config = { "parameters": { "host": "0.0.0.0", "port": 9000, "static_prefix": "/assets", "static_dir": "public", "template_dir": "templates", "debug": True, } } with open(config_file, "w") as f: yaml.dump(config, f) app = Application() app.load_config(config_file) assert app.host == "0.0.0.0" assert app.port == 9000 assert app._static_prefix == "/assets" assert app._static_dir == "public" assert app._template_dir == "templates" assert app._debug is True def test_load_config_empty(self): """Загрузка пустой конфигурации.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = os.path.join(tmpdir, "config.yaml") with open(config_file, "w") as f: f.write("") app = Application() app.load_config(config_file) # Should use defaults assert app.host == "localhost" assert app.port == 8000 def test_load_config_invalid(self): """Загрузка некорректной конфигурации.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = os.path.join(tmpdir, "config.yaml") # Создаем некорректный YAML with open(config_file, "w") as f: f.write("invalid: yaml: content: [[[") app = Application() # Не должно выбрасывать исключение app.load_config(config_file) def test_load_config_multiple_times(self): """Повторная загрузка конфига.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = os.path.join(tmpdir, "config.yaml") config = {"parameters": {"host": "0.0.0.0"}} with open(config_file, "w") as f: yaml.dump(config, f) app = Application() app.load_config(config_file) # Second load should be ignored - warning logged with patch("logging.Logger.warning") as mock_warning: app.load_config(config_file) mock_warning.assert_called() def test_load_env_interpolation(self): """Интерполяция переменных окружения в конфиге.""" with tempfile.TemporaryDirectory() as tmpdir: env_file = os.path.join(tmpdir, ".env") with open(env_file, "w") as f: f.write("MY_HOST=localhost\nMY_PORT=8080\n") config_file = os.path.join(tmpdir, "config.yaml") config = { "parameters": { "host": "${MY_HOST}", "port": "${MY_PORT}", } } with open(config_file, "w") as f: yaml.dump(config, f) app = Application() app.load_env(env_file) app.load_config(config_file) assert app.host == "localhost" assert app.port == 8080 class TestApplicationStatic: """Тесты работы со статикой.""" def test_set_static(self): """Установка статики.""" app = Application() app.set_static(prefix="/assets", directory="public") assert app._static_prefix == "/assets" assert app._static_dir == "public" def test_set_static_with_trailing_slash(self): """Установка статики с концевым слэшем.""" app = Application() app.set_static(prefix="/assets/", directory="public") assert app._static_prefix == "/assets" class TestApplicationControllers: """Тесты работы с контроллерами.""" def test_add_controller(self): """Регистрация контроллера.""" from liquidcode import route class TestController: @route("/test", methods=["GET"]) def index(self): return {"message": "Hello"} app = Application() app.add_controller(TestController) assert app.router.has_route("/test", "GET") def test_discover_controllers(self): """Обнаружение контроллеров.""" with tempfile.TemporaryDirectory() as tmpdir: # Create controller directory controller_dir = os.path.join(tmpdir, "src", "Controller") os.makedirs(controller_dir) # Create a controller file controller_file = os.path.join(controller_dir, "TestController.py") with open(controller_file, "w") as f: f.write(""" from liquidcode import route from liquidcode.http import HttpResponse class TestController: @route('/test', methods=['GET']) def index(self, request): return HttpResponse({'message': 'Hello'}, 200) """) app = Application() app.discover_controllers(controller_dir) assert app.router.has_route("/test", "GET") # Cleanup if os.path.exists(controller_file): os.remove(controller_file) if os.path.exists(controller_dir) and not os.path.samefile( tmpdir, controller_dir ): try: os.rmdir(controller_dir) except OSError: pass # Directory might not be empty or already removed class TestApplicationRoutes: """Тесты маршрутов.""" def test_route_decorator(self): """Декоратор @route.""" app = Application() @app.route("/test", methods=["GET"]) def handler(request): return {"test": True} assert app.router.has_route("/test", "GET") def test_route_decorator_multiple_methods(self): """Маршрут с несколькими методами.""" app = Application() @app.route("/test", methods=["GET", "POST"]) def handler(request): return {"test": True} assert app.router.has_route("/test", "GET") assert app.router.has_route("/test", "POST") def test_websocket_route_decorator(self): """Декоратор WebSocket route.""" app = Application() @app.websocket_route("/ws") def handler(request): return {"ws": True} assert app.router.has_route("/ws", "WEBSOCKET") class TestApplicationMiddleware: """Тесты middleware.""" def test_add_middleware(self): """Добавление middleware.""" app = Application() def middleware(request, call_next): return call_next(request) app.add_middleware(middleware) assert len(app.kernel._middlewares) > 0 class TestApplicationHooks: """Тесты хуков.""" def test_add_before_request(self): """Добавление хука before_request.""" app = Application() hook = Mock() app.add_before_request(hook) # Should be registered - check via kernel's hook list assert len(app.kernel._before_request_hooks) > 0 def test_add_after_request(self): """Добавление хука after_request.""" app = Application() hook = Mock() app.add_after_request(hook) assert len(app.kernel._after_request_hooks) > 0 def test_add_exception(self): """Добавление хука exception.""" app = Application() hook = Mock() app.add_exception(hook) assert len(app.kernel._exception_hooks) > 0 def test_add_terminate(self): """Добавление хука terminate.""" app = Application() hook = Mock() app.add_terminate(hook) assert len(app.kernel._terminate_hooks) > 0 class TestApplicationEnableProfiler: """Тесты профайлинга.""" def test_enable_profiler(self): """Включение профайлера.""" app = Application() app.enable_profiler() assert app.kernel.profiler_enabled is True class TestApplicationRun: """Интеграционные тесты запуска.""" def test_run_with_mock_server(self): """Запуск сmocked сервером.""" app = Application() with patch("liquidcode.application.HTTPServerManager") as mock_manager: manager_instance = Mock() mock_manager.return_value = manager_instance app.run() mock_manager.assert_called_once() manager_instance.run.assert_called_once() def test_run_sets_debug(self): """Запуск с debug режимом.""" app = Application() app._debug = True with patch("liquidcode.application.HTTPServerManager") as mock_manager: manager_instance = Mock() mock_manager.return_value = manager_instance app.run() manager_instance.set_debug.assert_called_once_with(True) class TestApplicationRenderTemplate: """Тесты рендеринга шаблонов.""" def test_render_template(self): """Рендеринг шаблона.""" app = Application() # Create a test template template_dir = app._template_dir if not os.path.exists(template_dir): os.makedirs(template_dir) template_file = os.path.join(template_dir, "test.html.j2") with open(template_file, "w") as f: f.write("<html>{{ title }}</html>") try: result = app.render_template("test.html.j2", title="Test") assert "<html>Test</html>" == result finally: # Cleanup if os.path.exists(template_file): os.remove(template_file) if os.path.exists(template_dir) and not os.listdir(template_dir): os.rmdir(template_dir) class TestApplicationRunWebsocket: """Тесты запуска WebSocket-сервера.""" def test_run_websocket_with_mock_server(self): """Запуск WebSocket-сервера с mock.""" app = Application() with patch("liquidcode.application.WebSocketServerManager") as mock_manager: manager_instance = Mock() mock_manager.return_value = manager_instance app.run_websocket() mock_manager.assert_called_once() manager_instance.run.assert_called_once() class TestApplicationLoadMiddlewareConfig: """Тесты загрузки middleware из конфига.""" def test_load_middleware_config_file(self): """Загрузка middleware из YAML файла.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = os.path.join(tmpdir, "middleware.yaml") config = { "middleware": [ { "class": "liquidcode.middleware.LoggingMiddleware", "enabled": True, "priority": 100, } ] } with open(config_file, "w") as f: yaml.dump(config, f) app = Application() app.load_middleware_config(config_file) # Проверяем, что middleware был загружен (в количестве 1) assert ( len(app.kernel._middlewares) >= 0 ) # middleware может не загрузиться, если нет зависимостей def test_load_middleware_config_disabled(self): """Загрузка отключенного middleware.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = os.path.join(tmpdir, "middleware.yaml") config = { "middleware": [ { "class": "liquidcode.middleware.LoggingMiddleware", "enabled": False, "priority": 100, } ] } with open(config_file, "w") as f: yaml.dump(config, f) app = Application() app.load_middleware_config(config_file) # Отключенный middleware не должен быть загружен def test_load_middleware_config_file_not_found(self): """Файл конфига middleware не найден.""" app = Application() # Не должно выбрасывать исключение app.load_middleware_config("nonexistent.yaml") class TestApplicationLoadConfigMiddleware: """Тесты загрузки middleware из main config.""" def test_load_middleware_from_config(self): """Загрузка middleware из main config.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = os.path.join(tmpdir, "config.yaml") config = { "middleware": [ { "class": "liquidcode.middleware.LoggingMiddleware", "enabled": True, "priority": 100, } ] } with open(config_file, "w") as f: yaml.dump(config, f) app = Application() app.load_config(config_file) # Проверяем, что middleware был загружен assert len(app.kernel._middlewares) >= 0 def test_load_middleware_config_with_container(self): """Загрузка middleware с container параметром.""" with tempfile.TemporaryDirectory() as tmpdir: config_file = os.path.join(tmpdir, "config.yaml") config = { "middleware_config": "middleware.yaml", } with open(config_file, "w") as f: yaml.dump(config, f) # Создаем middleware.yaml middleware_file = os.path.join(tmpdir, "middleware.yaml") middleware_config = { "middleware": [ { "class": "liquidcode.middleware.LoggingMiddleware", "enabled": True, "priority": 100, } ] } with open(middleware_file, "w") as f: yaml.dump(middleware_config, f) app = Application() app.load_config(config_file) # Проверяем, что middleware был загружен assert len(app.kernel._middlewares) >= 0 class TestApplicationEnsureDefaultRoute: """Тесты дефолтного роута.""" def test_set_default_route(self): """Установка дефолтного роута.""" app = Application() def handler(): return {"default": True} app.set_default_route(handler) assert app.router.has_route("/", "GET") def test_set_default_route_warning(self): """Предупреждение при перезаписи дефолтного роута.""" app = Application() def handler1(): return {"default": True} def handler2(): return {"default2": True} app.set_default_route(handler1) # Второй вызов должен выдать warning class TestApplicationEnsureLogging: """Тесты логирования.""" def test_ensure_logging_setup(self): """Настройка логирования.""" app = Application() # Очищаем хендлеры логов import logging root_logger = logging.getLogger() root_logger.handlers = [] app._ensure_logging() # Проверяем, что был добавлен хендлер assert len(root_logger.handlers) > 0