Loading src/srm/application/bootstrap/__init__.py 0 → 100644 +1 −0 Original line number Diff line number Diff line """Application bootstrap tasks.""" src/srm/application/bootstrap/qod_catalog.py 0 → 100644 +72 −0 Original line number Diff line number Diff line from uuid import UUID import structlog from srm.domain.models.canonical_parameters.parameters import ( CapabilityParameters, CapabilityTarget, Parameters, SourceSpecification, SourceSpecificationFamily, ) from srm.domain.models.catalog import ( ServiceCapabilityRequirement, ServiceSpecification, ServiceSpecificationState, ) from srm.domain.models.topology import CapabilityKind, DomainKind from srm.domain.ports.database.catalog import ServiceSpecificationRepository logger: structlog.BoundLogger = structlog.get_logger(__name__) # This function may be deleted if the use of alembic is established async def ensure_default_qod_service_specification( repository: ServiceSpecificationRepository, *, service_specification_id: UUID, platform_app_provider_id: str, ) -> ServiceSpecification: existing = await repository.get_by_id(service_specification_id) if existing is not None: logger.info( "default_qod_service_specification_exists", service_specification_id=str(service_specification_id), ) return existing specification = ServiceSpecification( id=service_specification_id, app_provider_id=platform_app_provider_id, ref="qod-session", name="QoD Session", version="1", state=ServiceSpecificationState.ACTIVE, descriptor={}, deployment_units=[], capability_requirements=[ ServiceCapabilityRequirement( service_specification_id=service_specification_id, ref="qod-session", capability_kind=CapabilityKind.QOD_SESSION, domain_kind=DomainKind.NETWORK, is_required=True, parameters=Parameters( target=CapabilityTarget(), parameters=CapabilityParameters(), source_spec=SourceSpecification( family=SourceSpecificationFamily.CAMARA, api="quality-on-demand", version="0.10.0", ), ), policy={}, ) ], ) created = await repository.create(specification) logger.info( "default_qod_service_specification_created", service_specification_id=str(created.id), ) return created src/srm/config.py +7 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ Usage: from functools import lru_cache from typing import Literal from uuid import UUID from pydantic import BaseModel, Field from pydantic_settings import BaseSettings, SettingsConfigDict Loading @@ -36,6 +37,11 @@ class NatsSettings(BaseModel): drain_timeout: int = 30 class BootstrapSettings(BaseModel): qod_service_specification_id: UUID = UUID("7608e902-b927-559f-b448-e7e9061dfa5c") platform_app_provider_id: str = "platform" class Settings(BaseSettings): model_config = SettingsConfigDict(env_file=".env", env_nested_delimiter="__") Loading @@ -46,6 +52,7 @@ class Settings(BaseSettings): postgres_settings: PostgreSQLSettings nats_settings: NatsSettings zone_provider_name: str = Field(default="oop-provider", min_length=1) bootstrap_settings: BootstrapSettings = BootstrapSettings() @lru_cache() Loading src/srm/main.py +16 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ from srm.adapters.database.core import ( build_engine_and_session_maker, schema_initialization, ) from srm.adapters.database.repos.catalog import SqlServiceSpecificationRepository from srm.adapters.databus.nats_connection_manager import ( NatsConnectionManager, init_databus_manager, Loading @@ -29,6 +30,7 @@ from srm.api.databus.nats_subscriber import NatsSubscriber, subscribe_to_subject from srm.api.health import health_router from srm.api.middlewares.middlewares import register_middlewares from srm.api.rest.router import internal from srm.application.bootstrap.qod_catalog import ensure_default_qod_service_specification from srm.config import Settings, get_settings Loading @@ -52,6 +54,20 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]: if settings.postgres_settings.create_schema_on_startup: await schema_initialization(engine) async with session_maker() as session: try: await ensure_default_qod_service_specification( SqlServiceSpecificationRepository(session), service_specification_id=( settings.bootstrap_settings.qod_service_specification_id ), platform_app_provider_id=(settings.bootstrap_settings.platform_app_provider_id), ) await session.commit() except Exception: await session.rollback() raise except Exception as e: logger.error("Database engine init failed!", error=str(e)) raise Loading tests/api/test_app.py +7 −1 Original line number Diff line number Diff line Loading @@ -20,13 +20,19 @@ def stub_database() -> Iterator[AsyncMock]: """Lifespan builds the DB engine before touching NATS; stubbing it keeps these tests focused on the DataBus stage and off Docker.""" engine = AsyncMock() session = AsyncMock() session_context = MagicMock() session_context.__aenter__ = AsyncMock(return_value=session) session_context.__aexit__ = AsyncMock(return_value=None) session_maker = MagicMock(return_value=session_context) with ( patch( "srm.main.build_engine_and_session_maker", new_callable=AsyncMock, return_value=(engine, MagicMock()), return_value=(engine, session_maker), ), patch("srm.main.schema_initialization", new_callable=AsyncMock), patch("srm.main.ensure_default_qod_service_specification", new_callable=AsyncMock), ): yield engine Loading Loading
src/srm/application/bootstrap/__init__.py 0 → 100644 +1 −0 Original line number Diff line number Diff line """Application bootstrap tasks."""
src/srm/application/bootstrap/qod_catalog.py 0 → 100644 +72 −0 Original line number Diff line number Diff line from uuid import UUID import structlog from srm.domain.models.canonical_parameters.parameters import ( CapabilityParameters, CapabilityTarget, Parameters, SourceSpecification, SourceSpecificationFamily, ) from srm.domain.models.catalog import ( ServiceCapabilityRequirement, ServiceSpecification, ServiceSpecificationState, ) from srm.domain.models.topology import CapabilityKind, DomainKind from srm.domain.ports.database.catalog import ServiceSpecificationRepository logger: structlog.BoundLogger = structlog.get_logger(__name__) # This function may be deleted if the use of alembic is established async def ensure_default_qod_service_specification( repository: ServiceSpecificationRepository, *, service_specification_id: UUID, platform_app_provider_id: str, ) -> ServiceSpecification: existing = await repository.get_by_id(service_specification_id) if existing is not None: logger.info( "default_qod_service_specification_exists", service_specification_id=str(service_specification_id), ) return existing specification = ServiceSpecification( id=service_specification_id, app_provider_id=platform_app_provider_id, ref="qod-session", name="QoD Session", version="1", state=ServiceSpecificationState.ACTIVE, descriptor={}, deployment_units=[], capability_requirements=[ ServiceCapabilityRequirement( service_specification_id=service_specification_id, ref="qod-session", capability_kind=CapabilityKind.QOD_SESSION, domain_kind=DomainKind.NETWORK, is_required=True, parameters=Parameters( target=CapabilityTarget(), parameters=CapabilityParameters(), source_spec=SourceSpecification( family=SourceSpecificationFamily.CAMARA, api="quality-on-demand", version="0.10.0", ), ), policy={}, ) ], ) created = await repository.create(specification) logger.info( "default_qod_service_specification_created", service_specification_id=str(created.id), ) return created
src/srm/config.py +7 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ Usage: from functools import lru_cache from typing import Literal from uuid import UUID from pydantic import BaseModel, Field from pydantic_settings import BaseSettings, SettingsConfigDict Loading @@ -36,6 +37,11 @@ class NatsSettings(BaseModel): drain_timeout: int = 30 class BootstrapSettings(BaseModel): qod_service_specification_id: UUID = UUID("7608e902-b927-559f-b448-e7e9061dfa5c") platform_app_provider_id: str = "platform" class Settings(BaseSettings): model_config = SettingsConfigDict(env_file=".env", env_nested_delimiter="__") Loading @@ -46,6 +52,7 @@ class Settings(BaseSettings): postgres_settings: PostgreSQLSettings nats_settings: NatsSettings zone_provider_name: str = Field(default="oop-provider", min_length=1) bootstrap_settings: BootstrapSettings = BootstrapSettings() @lru_cache() Loading
src/srm/main.py +16 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ from srm.adapters.database.core import ( build_engine_and_session_maker, schema_initialization, ) from srm.adapters.database.repos.catalog import SqlServiceSpecificationRepository from srm.adapters.databus.nats_connection_manager import ( NatsConnectionManager, init_databus_manager, Loading @@ -29,6 +30,7 @@ from srm.api.databus.nats_subscriber import NatsSubscriber, subscribe_to_subject from srm.api.health import health_router from srm.api.middlewares.middlewares import register_middlewares from srm.api.rest.router import internal from srm.application.bootstrap.qod_catalog import ensure_default_qod_service_specification from srm.config import Settings, get_settings Loading @@ -52,6 +54,20 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]: if settings.postgres_settings.create_schema_on_startup: await schema_initialization(engine) async with session_maker() as session: try: await ensure_default_qod_service_specification( SqlServiceSpecificationRepository(session), service_specification_id=( settings.bootstrap_settings.qod_service_specification_id ), platform_app_provider_id=(settings.bootstrap_settings.platform_app_provider_id), ) await session.commit() except Exception: await session.rollback() raise except Exception as e: logger.error("Database engine init failed!", error=str(e)) raise Loading
tests/api/test_app.py +7 −1 Original line number Diff line number Diff line Loading @@ -20,13 +20,19 @@ def stub_database() -> Iterator[AsyncMock]: """Lifespan builds the DB engine before touching NATS; stubbing it keeps these tests focused on the DataBus stage and off Docker.""" engine = AsyncMock() session = AsyncMock() session_context = MagicMock() session_context.__aenter__ = AsyncMock(return_value=session) session_context.__aexit__ = AsyncMock(return_value=None) session_maker = MagicMock(return_value=session_context) with ( patch( "srm.main.build_engine_and_session_maker", new_callable=AsyncMock, return_value=(engine, MagicMock()), return_value=(engine, session_maker), ), patch("srm.main.schema_initialization", new_callable=AsyncMock), patch("srm.main.ensure_default_qod_service_specification", new_callable=AsyncMock), ): yield engine Loading