123 lines
4.5 KiB
Python
123 lines
4.5 KiB
Python
"""Чистая установка: пустой data/, Alembic, bootstrap, health."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import shutil
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from app import create_app, db
|
|
from app.models.auto_update_settings import AutoUpdateSettings
|
|
from app.services.update_health import migrations_ok_for_app
|
|
from config import Config, ProductionConfig
|
|
|
|
|
|
class FreshInstallTest(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
self._tmp = tempfile.mkdtemp(prefix="wesp-fresh-install-")
|
|
self._base = Path(self._tmp) / "wesp_home"
|
|
self._base.mkdir()
|
|
data = self._base / "data"
|
|
data.mkdir()
|
|
recipes = data / "recipes.db"
|
|
reports = data / "reports.db"
|
|
|
|
class FreshConfig(ProductionConfig):
|
|
BASE_DIR = str(self._base)
|
|
DATA_DIR = str(data)
|
|
SQLALCHEMY_DATABASE_URI = f"sqlite:///{recipes}"
|
|
SQLALCHEMY_BINDS = {"reports": f"sqlite:///{reports}"}
|
|
SECRET_KEY = "fresh-install-test-secret"
|
|
AUTH_LOGIN = "install-admin"
|
|
AUTH_PASSWORD = "install-secret"
|
|
SYNC_BACKGROUND_REQUEUE = False
|
|
SYNC_CLIENT_AUTOSTART = False
|
|
WESP_ADMIN_LOG_PATH = ""
|
|
WESP_ADMIN_HARDWARE_LOG_PATH = ""
|
|
WESP_ADMIN_UI_ACTIVITY_LOG_PATH = ""
|
|
WESP_LLM_AUTOSTART = False
|
|
WESP_BACKGROUND_STARTUP = False
|
|
|
|
self.app = create_app(FreshConfig, run_migrations=True)
|
|
self.client = self.app.test_client()
|
|
self._ctx = self.app.app_context()
|
|
self._ctx.push()
|
|
|
|
def tearDown(self) -> None:
|
|
self._ctx.pop()
|
|
shutil.rmtree(self._tmp, ignore_errors=True)
|
|
|
|
def test_ensure_auto_update_row_idempotent(self) -> None:
|
|
from sqlalchemy import func, select
|
|
|
|
from app.services.auto_update_settings_service import ensure_auto_update_row
|
|
|
|
ensure_auto_update_row()
|
|
ensure_auto_update_row()
|
|
n = db.session.scalar(select(func.count()).select_from(AutoUpdateSettings))
|
|
self.assertEqual(int(n or 0), 1)
|
|
|
|
def test_databases_and_auto_update_bootstrap(self) -> None:
|
|
from app.services.auto_update_settings_service import bootstrap_update_environment
|
|
|
|
recipes = Path(self.app.config["DATA_DIR"]) / "recipes.db"
|
|
reports = Path(self.app.config["DATA_DIR"]) / "reports.db"
|
|
self.assertTrue(recipes.is_file())
|
|
self.assertTrue(reports.is_file())
|
|
|
|
# Как при prod-старте, но синхронно: отложенный поток под нагрузкой pytest может не успеть за 5 с.
|
|
bootstrap_update_environment(self.app)
|
|
row = db.session.get(AutoUpdateSettings, 1)
|
|
self.assertIsNotNone(row)
|
|
|
|
config_json = Path(self.app.config["DATA_DIR"]) / "config.json"
|
|
self.assertTrue(config_json.is_file())
|
|
|
|
def test_migrations_at_head(self) -> None:
|
|
self.assertTrue(migrations_ok_for_app(self.app))
|
|
|
|
def test_health_after_fresh_install(self) -> None:
|
|
r = self.client.get("/api/health")
|
|
self.assertEqual(r.status_code, 200)
|
|
body = r.get_json()
|
|
self.assertTrue(body.get("ok"))
|
|
self.assertTrue(body.get("db_ok"))
|
|
self.assertTrue(body.get("migrations_ok"))
|
|
self.assertEqual(body.get("migration_head"), body.get("migration_revision"))
|
|
|
|
def test_setup_not_completed_by_default(self) -> None:
|
|
from app.services.setup_state import is_setup_completed
|
|
|
|
self.assertFalse(is_setup_completed(self.app))
|
|
|
|
def test_alembic_env_does_not_bootstrap_before_upgrade(self) -> None:
|
|
"""create_app(run_migrations=False) не обращается к таблицам до upgrade (как migrations/env.py)."""
|
|
empty = Path(self._tmp) / "empty"
|
|
empty.mkdir()
|
|
data = empty / "data"
|
|
data.mkdir()
|
|
recipes = data / "recipes.db"
|
|
reports = data / "reports.db"
|
|
|
|
class EmptyConfig(Config):
|
|
BASE_DIR = str(empty)
|
|
DATA_DIR = str(data)
|
|
SQLALCHEMY_DATABASE_URI = f"sqlite:///{recipes}"
|
|
SQLALCHEMY_BINDS = {"reports": f"sqlite:///{reports}"}
|
|
SECRET_KEY = "empty"
|
|
SYNC_BACKGROUND_REQUEUE = False
|
|
WESP_ADMIN_LOG_PATH = ""
|
|
|
|
os.environ["WESP_ALEMBIC"] = "1"
|
|
try:
|
|
app = create_app(EmptyConfig, run_migrations=False)
|
|
self.assertIsNotNone(app)
|
|
finally:
|
|
os.environ.pop("WESP_ALEMBIC", None)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|