"""Фоновая инициализация и /api/startup/status.""" from __future__ import annotations import os import tempfile import unittest from unittest.mock import patch from app import create_app, db from app.services.startup_background import is_reloader_parent_process, schedule_background_startup from app.services.startup_state import mark_startup_ready, reset_startup_state from config import TestingConfig class StartupBgConfig(TestingConfig): _TMP = tempfile.mkdtemp(prefix="wesp-startup-bg-") BASE_DIR = _TMP DATA_DIR = os.path.join(_TMP, "data") SQLALCHEMY_DATABASE_URI = f"sqlite:///{os.path.join(_TMP, 'recipes_test.db')}" SQLALCHEMY_BINDS = {"reports": f"sqlite:///{os.path.join(_TMP, 'reports_test.db')}"} WESP_BACKGROUND_STARTUP = False class StartupBackgroundTests(unittest.TestCase): def setUp(self) -> None: reset_startup_state() self.app = create_app(StartupBgConfig) self.client = self.app.test_client() self.ctx = self.app.app_context() self.ctx.push() mark_startup_ready() db.create_all() def tearDown(self) -> None: db.session.remove() db.drop_all() self.ctx.pop() reset_startup_state() def test_startup_status_ready(self) -> None: r = self.client.get("/api/startup/status") self.assertEqual(r.status_code, 200) body = r.get_json() self.assertTrue(body.get("ready")) def test_reloader_parent_skips_blocking_startup(self) -> None: app = create_app(StartupBgConfig) app.debug = True with patch.dict(os.environ, {}, clear=False): os.environ.pop("WERKZEUG_RUN_MAIN", None) with patch( "app.services.startup_background.is_running_from_reloader", create=True, return_value=False, ): self.assertTrue(is_reloader_parent_process(app)) with patch("app.services.startup_background.run_blocking_startup_tasks") as blocked: self.assertFalse(schedule_background_startup(app)) blocked.assert_not_called() def test_health_during_starting(self) -> None: reset_startup_state() from app.services.startup_state import set_startup_phase set_startup_phase("migrations", "Тест") with self.app.app_context(): self.app.config["WESP_DEFERRED_STARTUP"] = True from app.services.update_health import build_health_payload payload = build_health_payload(self.app) self.assertTrue(payload.get("starting")) self.assertFalse(payload.get("ok")) def test_scales_not_redirected_to_starting_while_migrations(self) -> None: reset_startup_state() from app.services.startup_state import set_startup_phase set_startup_phase("migrations", "Тест") self.app.config["WESP_DEFERRED_STARTUP"] = True r = self.client.get("/scales", follow_redirects=False) loc = r.headers.get("Location") or "" self.assertNotIn("/starting", loc) def test_stream_weight_not_redirected_while_migrations(self) -> None: reset_startup_state() from app.services.startup_state import set_startup_phase set_startup_phase("migrations", "Тест") self.app.config["WESP_DEFERRED_STARTUP"] = True r = self.client.get("/stream_weight") self.assertNotEqual(r.status_code, 302) loc = r.headers.get("Location") or "" self.assertNotIn("/starting", loc) if __name__ == "__main__": unittest.main()