e5514fe3bf
- App factory pattern (FUND-8): create_app() produces fresh app per test
- Logging config (structured, no secrets)
- Config validation: SLAB_AES_KEY required, WOO_BASE_URL HTTPS-only
- GET /api/health returns 200 {status: ok, version, woo_reachable: false}
- SQLite + alembic skeleton: full DATA-MODEL schema, initial migration
- API contract tests via httpx TestClient: 5 cases all green
- test_returns_200, test_returns_ok_status, test_woo_reachable_false
- test_response_shape, test_with_test_client_lifespan (FUND-9/10)
50 lines
1.2 KiB
Python
50 lines
1.2 KiB
Python
"""App factory and lifespan."""
|
|
|
|
import logging
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
|
|
from app.api import health
|
|
from app.config import Settings
|
|
from app.db.engine import close_db_connection, init_db
|
|
from app.logging_config import configure_logging
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
"""Application lifespan: startup and shutdown hooks.
|
|
|
|
Handles database initialization, logging configuration,
|
|
and cleanup on shutdown.
|
|
"""
|
|
configure_logging()
|
|
logging.info("SlabUploader starting up")
|
|
await init_db()
|
|
yield
|
|
logging.info("SlabUploader shutting down")
|
|
await close_db_connection()
|
|
|
|
|
|
def create_app(settings: Settings | None = None) -> FastAPI:
|
|
"""Create a fresh FastAPI app instance.
|
|
|
|
Each call produces an independent app with its own database connection
|
|
and cleared dependency overrides. This is the factory used by tests.
|
|
|
|
Args:
|
|
settings: Application settings. Uses env vars if None.
|
|
|
|
Returns:
|
|
Configured FastAPI application.
|
|
"""
|
|
if settings is None:
|
|
settings = Settings()
|
|
settings.validate()
|
|
|
|
app = FastAPI(title="SlabUploader", version="0.1.0", lifespan=lifespan)
|
|
|
|
app.include_router(health.router)
|
|
|
|
return app
|