diff --git a/Makefile b/Makefile index 7cbaacb6c..3203af933 100644 --- a/Makefile +++ b/Makefile @@ -89,34 +89,34 @@ run-compose: docker compose up --wait .PHONY: psql -psql: CM_DATABASE_PORT=$(shell docker compose port postgresql 5432 | cut -d: -f2) -psql: export CM_DATABASE_PASSWORD=INSECURE-PASSWORD +psql: PGPORT=$(shell docker compose port postgresql 5432 | cut -d: -f2) +psql: export DB__PASSWORD=INSECURE-PASSWORD psql: run-compose - psql postgresql://cm-service:${CM_DATABASE_PASSWORD}@localhost:${CM_DATABASE_PORT}/cm-service + psql postgresql://cm-service:${DB__PASSWORD}@localhost:${PGPORT}/cm-service .PHONY: test -test: CM_DATABASE_PORT=$(shell docker compose port postgresql 5432 | cut -d: -f2) -test: export CM_DATABASE_URL=postgresql://cm-service@localhost:${CM_DATABASE_PORT}/cm-service -test: export CM_DATABASE_PASSWORD=INSECURE-PASSWORD -test: export CM_DATABASE_SCHEMA=cm_service_test +test: PGPORT=$(shell docker compose port postgresql 5432 | cut -d: -f2) +test: export DB__URL=postgresql://cm-service@localhost:${PGPORT}/cm-service +test: export DB__PASSWORD=INSECURE-PASSWORD +test: export DB__SCHEMA=cm_service_test test: run-compose python3 -m lsst.cmservice.cli.server init pytest -vvv --asyncio-mode=auto --cov=lsst.cmservice --cov-branch --cov-report=term --cov-report=html ${PYTEST_ARGS} .PHONY: run -run: CM_DATABASE_PORT=$(shell docker compose port postgresql 5432 | cut -d: -f2) -run: export CM_DATABASE_URL=postgresql://cm-service@localhost:${CM_DATABASE_PORT}/cm-service -run: export CM_DATABASE_PASSWORD=INSECURE-PASSWORD -run: export CM_DATABASE_ECHO=true +run: PGPORT=$(shell docker compose port postgresql 5432 | cut -d: -f2) +run: export DB__URL=postgresql://cm-service@localhost:${PGPORT}/cm-service +run: export DB__PASSWORD=INSECURE-PASSWORD +run: export DB__ECHO=true run: run-compose python3 -m lsst.cmservice.cli.server init python3 -m lsst.cmservice.cli.server run .PHONY: run-worker -run-worker: CM_DATABASE_PORT=$(shell docker compose port postgresql 5432 | cut -d: -f2) -run-worker: export CM_DATABASE_URL=postgresql://cm-service@localhost:${CM_DATABASE_PORT}/cm-service -run-worker: export CM_DATABASE_PASSWORD=INSECURE-PASSWORD -run-worker: export CM_DATABASE_ECHO=true +run-worker: PGPORT=$(shell docker compose port postgresql 5432 | cut -d: -f2) +run-worker: export DB__URL=postgresql://cm-service@localhost:${PGPORT}/cm-service +run-worker: export DB__PASSWORD=INSECURE-PASSWORD +run-worker: export DB__ECHO=true run-worker: run-compose python3 -m lsst.cmservice.cli.server init python3 -m lsst.cmservice.daemon @@ -128,21 +128,21 @@ run-worker: run-compose #------------------------------------------------------------------------------ .PHONY: test-sqlite -test-sqlite: export CM_DATABASE_URL=sqlite+aiosqlite://///test_cm.db +test-sqlite: export DB__URL=sqlite+aiosqlite://///test_cm.db test-sqlite: python3 -m lsst.cmservice.cli.server init pytest -vvv --asyncio-mode=auto --cov=lsst.cmservice --cov-branch --cov-report=term --cov-report=html ${PYTEST_ARGS} .PHONY: run-sqlite -run-sqlite: export CM_DATABASE_URL=sqlite+aiosqlite://///test_cm.db -run-sqlite: export CM_DATABASE_ECHO=true +run-sqlite: export DB__URL=sqlite+aiosqlite://///test_cm.db +run-sqlite: export DB__ECHO=true run-sqlite: python3 -m lsst.cmservice.cli.server init python3 -m lsst.cmservice.cli.server run .PHONY: run-worker-sqlite -run-worker-sqlite: export CM_DATABASE_URL=sqlite+aiosqlite://///test_cm.db -run-worker-sqlite: export CM_DATABASE_ECHO=true +run-worker-sqlite: export DB__URL=sqlite+aiosqlite://///test_cm.db +run-worker-sqlite: export DB__ECHO=true run-worker-sqlite: python3 -m lsst.cmservice.cli.server init python3 -m lsst.cmservice.daemon @@ -167,36 +167,36 @@ psql-usdf-dev: ## Connect psql client to backend Postgres (shared USDF) psql .PHONY: test-usdf-dev -test-usdf-dev: CM_DATABASE_HOST=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}')' -test-usdf-dev: export CM_DATABASE_URL=postgresql://cm-service@${CM_DATABASE_HOST}:5432/cm-service -test-usdf-dev: export CM_DATABASE_PASSWORD=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode) -test-usdf-dev: export CM_DATABASE_SCHEMA=cm_service_test +test-usdf-dev: DB__HOST=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}')' +test-usdf-dev: export DB__URL=postgresql://cm-service@${DB__HOST}:5432/cm-service +test-usdf-dev: export DB__PASSWORD=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode) +test-usdf-dev: export DB__SCHEMA=cm_service_test test-usdf-dev: pytest -vvv --cov=lsst.cmservice --cov-branch --cov-report=term --cov-report=html ${PYTEST_ARGS} .PHONY: run-usdf-dev -run-usdf-dev:CM_DATABASE_HOST=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}')' -run-usdf-dev: export CM_DATABASE_URL=postgresql://cm-service@${CM_DATABASE_HOST}:5432/cm-service -run-usdf-dev: export CM_DATABASE_PASSWORD=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode) -run-usdf-dev: export CM_DATABASE_ECHO=true +run-usdf-dev:DB__HOST=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}')' +run-usdf-dev: export DB__URL=postgresql://cm-service@${DB__HOST}:5432/cm-service +run-usdf-dev: export DB__PASSWORD=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode) +run-usdf-dev: export DB__ECHO=true run-usdf-dev: python3 -m lsst.cmservice.cli.server init python3 -m lsst.cmservice.cli.server run .PHONY: run-worker-usdf-dev -run-worker-usdf-dev: CM_DATABASE_HOST=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}') -run-worker-usdf-dev: export CM_DATABASE_URL=postgresql://cm-service@${CM_DATABASE_HOST}:5432/cm-service -run-worker-usdf-dev: export CM_DATABASE_PASSWORD=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode) -run-worker-usdf-dev: export CM_DATABASE_ECHO=true +run-worker-usdf-dev: DB__HOST=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}') +run-worker-usdf-dev: export DB__URL=postgresql://cm-service@${DB__HOST}:5432/cm-service +run-worker-usdf-dev: export DB__PASSWORD=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode) +run-worker-usdf-dev: export DB__ECHO=true run-worker-usdf-dev: python3 -m lsst.cmservice.daemon -get-env-%: CM_DATABASE_HOST=$(shell kubectl --cluster=$* -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}') -get-env-%: export CM_DATABASE_URL=postgresql://cm-servicer@${CM_DATABASE_HOST}:5432/cm-service -get-env-%: export CM_DATABASE_PASSWORD=$(shell kubectl --cluster=$* -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode) -get-env-%: export CM_DATABASE_ECHO=true +get-env-%: DB__HOST=$(shell kubectl --cluster=$* -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}') +get-env-%: export DB__URL=postgresql://cm-servicer@${DB__HOST}:5432/cm-service +get-env-%: export DB__PASSWORD=$(shell kubectl --cluster=$* -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode) +get-env-%: export DB__ECHO=true get-env-%: rm -f .env.$* - echo CM_DATABASE_URL=$${CM_DATABASE_URL} > .env.$* - echo CM_DATABASE_ECHO=$${CM_DATABASE_ECHO} >> .env.$* - echo CM_DATABASE_PASSWORD=$${CM_DATABASE_PASSWORD} >> .env.$* + echo DB__URL=$${DB__URL} > .env.$* + echo DB__ECHO=$${DB__ECHO} >> .env.$* + echo DB__PASSWORD=$${DB__PASSWORD} >> .env.$* diff --git a/docker-compose.yaml b/docker-compose.yaml index 9d3a05eee..45c8b74fe 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -18,10 +18,10 @@ services: - lsst.cmservice.cli.server - init environment: &cmenv - CM_DATABASE_HOST: postgresql - CM_DATABASE_ECHO: true - CM_DATABASE_URL: postgresql://cm-service@postgresql:5432/cm-service - CM_DATABASE_PASSWORD: INSECURE-PASSWORD + DB__HOST: postgresql + DB__ECHO: true + DB__URL: postgresql://cm-service@postgresql:5432/cm-service + DB__PASSWORD: INSECURE-PASSWORD depends_on: postgresql: condition: service_healthy diff --git a/pyproject.toml b/pyproject.toml index cce339085..1ab95c875 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -124,14 +124,14 @@ target-version = "py311" [tool.ruff.lint] ignore = [ - "COM812", - "N802", - "N803", - "N806", - "N812", - "N813", - "N815", - "N816", + "COM812", # missing-trailing-comma + "N802", # invalid-function-name + "N803", # invalid-argument-name + "N806", # non-lowercase-variable-in-function + "N812", # lowercase-imported-as-non-lowercase + "N813", # camelcase-imported-as-constant + "N815", # mixed-case-variable-in-class-scope + "N816", # mixed-case-variable-in-global-scope ] select = [ "E", # pycodestyle diff --git a/src/lsst/cmservice/cli/server.py b/src/lsst/cmservice/cli/server.py index 4dd8e8625..c1d29d50d 100644 --- a/src/lsst/cmservice/cli/server.py +++ b/src/lsst/cmservice/cli/server.py @@ -20,8 +20,8 @@ def server() -> None: @run_with_asyncio async def init(*, reset: bool) -> None: # pragma: no cover """Initialize the service database.""" - logger = structlog.get_logger(config.logger_name) - engine = create_database_engine(config.database_url, config.database_password) + logger = structlog.get_logger(__name__) + engine = create_database_engine(config.db.url, config.db.password) await initialize_database(engine, logger, schema=db.Base.metadata, reset=reset) await engine.dispose() diff --git a/src/lsst/cmservice/common/htcondor.py b/src/lsst/cmservice/common/htcondor.py index de8605d3a..0a639c943 100644 --- a/src/lsst/cmservice/common/htcondor.py +++ b/src/lsst/cmservice/common/htcondor.py @@ -3,6 +3,7 @@ import subprocess from typing import Any +from ..config import config from .enums import StatusEnum from .errors import CMHTCondorCheckError, CMHTCondorSubmitError @@ -49,9 +50,9 @@ def write_htcondor_script( should_transfer_files="Yes", when_to_transfer_output="ON_EXIT", get_env=True, - request_cpus=1, - request_memory="512M", - request_disk="1G", + request_cpus=config.htcondor.request_cpus, + request_memory=config.htcondor.request_mem, + request_disk=config.htcondor.request_disk, ) options.update(**kwargs) @@ -86,16 +87,16 @@ def submit_htcondor_job( try: with subprocess.Popen( [ - "condor_submit", + config.htcondor.condor_submit_bin, htcondor_script_path, ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, - ) as sbatch: # pragma: no cover - sbatch.wait() - if sbatch.returncode != 0: - assert sbatch.stderr - msg = sbatch.stderr.read().decode() + ) as condor_submit: # pragma: no cover + condor_submit.wait() + if condor_submit.returncode != 0: + assert condor_submit.stderr + msg = condor_submit.stderr.read().decode() raise CMHTCondorSubmitError(f"Bad htcondor submit: {msg}") except Exception as e: raise CMHTCondorSubmitError(f"Bad htcondor submit: {e}") from e @@ -126,7 +127,7 @@ def check_htcondor_job( if htcondor_id is None: # pragma: no cover raise CMHTCondorCheckError("No htcondor_id") with subprocess.Popen( - ["condor_q", "-userlog", htcondor_id, "-af", "JobStatus", "ExitCode"], + [config.htcondor.condor_q_bin, "-userlog", htcondor_id, "-af", "JobStatus", "ExitCode"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) as condor_q: # pragma: no cover diff --git a/src/lsst/cmservice/common/slurm.py b/src/lsst/cmservice/common/slurm.py index cca419a00..34ef76c9f 100644 --- a/src/lsst/cmservice/common/slurm.py +++ b/src/lsst/cmservice/common/slurm.py @@ -2,6 +2,7 @@ import subprocess +from ..config import config from .enums import StatusEnum from .errors import CMSlurmCheckError, CMSlurmSubmitError @@ -62,15 +63,15 @@ def submit_slurm_job( try: with subprocess.Popen( [ - "sbatch", + config.slurm.sbatch_bin, "-o", log_url, "--mem", - "16448", + config.slurm.memory, "--account", - "rubin:production", + config.slurm.account, "-p", - "milano", + config.slurm.partition, "--parsable", script_url, ], @@ -114,7 +115,7 @@ def check_slurm_job( return StatusEnum.running try: with subprocess.Popen( - ["sacct", "--parsable", "-b", "-j", slurm_id], stdout=subprocess.PIPE + [config.slurm.sacct_bin, "--parsable", "-b", "-j", slurm_id], stdout=subprocess.PIPE ) as sacct: # pragma: no cover sacct.wait() if sacct.returncode != 0: diff --git a/src/lsst/cmservice/config.py b/src/lsst/cmservice/config.py index 334d0d90e..aa0103618 100644 --- a/src/lsst/cmservice/config.py +++ b/src/lsst/cmservice/config.py @@ -1,61 +1,170 @@ -from pydantic import Field -from pydantic_settings import BaseSettings -from safir.logging import LogLevel, Profile +from pydantic import BaseModel, Field +from pydantic_settings import BaseSettings, SettingsConfigDict __all__ = ["Configuration", "config"] -class Configuration(BaseSettings): - """Configuration for cm-service.""" +class HTCondorConfiguration(BaseModel): + """Configuration settings for htcondor client operations. + + Set via HTCONDOR__FIELD environment variables. + """ + + condor_submit_bin: str = Field( + description="Name of condor_submit client binary", + default="condor_submit", + ) + + condor_q_bin: str = Field( + description="Name of condor_q client binary", + default="condor_q", + ) + + request_cpus: int = Field( + description="Number of cores to request when submitting an htcondor job.", + default=1, + ) + + request_mem: str = Field( + description="Amount of memory requested when submitting an htcondor job.", + default="512M", + ) + + request_disk: str = Field( + description="Amount of disk space requested when submitting an htcondor job.", + default="1G", + ) + + +class SlurmConfiguration(BaseModel): + """Configuration settings for slurm client operations. + + Set via SLURM__FIELD environment variables. + + Note + ---- + Default SBATCH_* variables could work just as well, but it is useful to + have this as a document of what settings are actually used. + """ + + sacct_bin: str = Field( + description="Name of sacct slurm client binary", + default="sacct", + ) + + sbatch_bin: str = Field( + description="Name of sbatch slurm client binary", + default="sbatch", + ) + + memory: str = Field( + description="Amount of memory requested when submitting a slurm job.", + default="16448", + ) + + account: str = Field( + description="Account used when submitting a slurm job.", + default="rubin:production", + ) + + partition: str = Field( + description="Partition requested when submitting a slurm job.", + default="milano", + ) + + +class AsgiConfiguration(BaseModel): + """Configuration for the application's ASGI web server.""" + + title: str = Field( + description="Title of the ASGI application", + default="cm-service", + ) + + host: str = Field( + description="The host address to which the asgi server should bind", + default="0.0.0.0", + ) + + port: int = Field( + description="Port number for the asgi server to listen on", + default=8080, + ) prefix: str = Field( + description="The URL prefix for the cm-service API", default="/cm-service/v1", - title="The URL prefix for the cm-service API", - validation_alias="CM_URL_PREFIX", ) - database_url: str = Field( + frontend_prefix: str = Field( + description="The URL prefix for the frontend web app", + default="/web_app", + ) + + +class LoggingConfiguration(BaseModel): + """Configuration for the application's logging facility.""" + + level: str = Field( + default="INFO", + title="Log level of the application's logger", + ) + + profile: str = Field( + default="development", + title="Application logging profile", + ) + + +class DatabaseConfiguration(BaseModel): + """Database configuration nested model. + + Set according to DB__FIELD environment variables. + """ + + url: str = Field( default="", - title="The URL for the cm-service database", - validation_alias="CM_DATABASE_URL", + description="The URL for the cm-service database", ) - database_password: str | None = Field( + password: str | None = Field( default=None, - title="The password for the cm-service database", - validation_alias="CM_DATABASE_PASSWORD", + description="The password for the cm-service database", ) - database_schema: str | None = Field( + table_schema: str | None = Field( default=None, - title="Schema to use for cm-service database", - validation_alias="CM_DATABASE_SCHEMA", + description="Schema to use for cm-service database", ) - database_echo: bool = Field( + echo: bool = Field( default=False, - title="SQLAlchemy engine echo setting for the cm-service database", - validation_alias="CM_DATABASE_ECHO", + description="SQLAlchemy engine echo setting for the cm-service database", ) - profile: Profile = Field( - default=Profile.development, - title="Application logging profile", - validation_alias="CM_LOG_PROFILE", - ) - logger_name: str = Field( - default="cmservice", - title="The root name of the application's logger", - validation_alias="CM_LOGGER", - ) +class Configuration(BaseSettings): + """Configuration for cm-service. - log_level: LogLevel = Field( - default=LogLevel.INFO, - title="Log level of the application's logger", - validation_alias="CM_LOG_LEVEL", + Nested models may be consumed from environment variables named according to + the pattern 'NESTED_MODEL__FIELD' or via any `validation_alias` applied to + a field. + """ + + model_config = SettingsConfigDict( + env_nested_delimiter="__", + nested_model_default_partial_update=True, + case_sensitive=False, + extra="ignore", ) + # Nested Models + asgi: AsgiConfiguration = AsgiConfiguration() + db: DatabaseConfiguration = DatabaseConfiguration() + htcondor: HTCondorConfiguration = HTCondorConfiguration() + logging: LoggingConfiguration = LoggingConfiguration() + slurm: SlurmConfiguration = SlurmConfiguration() + config = Configuration() """Configuration for cm-service.""" diff --git a/src/lsst/cmservice/daemon.py b/src/lsst/cmservice/daemon.py index deb237199..983bc9190 100644 --- a/src/lsst/cmservice/daemon.py +++ b/src/lsst/cmservice/daemon.py @@ -10,8 +10,8 @@ async def main_loop() -> None: - logger = structlog.get_logger(config.logger_name) - engine = create_database_engine(config.database_url, config.database_password) + logger = structlog.get_logger(__name__) + engine = create_database_engine(config.db.url, config.db.password) async with engine.begin(): session = await create_async_session(engine, logger) diff --git a/src/lsst/cmservice/db/base.py b/src/lsst/cmservice/db/base.py index e4cd85ade..912d7af7b 100644 --- a/src/lsst/cmservice/db/base.py +++ b/src/lsst/cmservice/db/base.py @@ -7,4 +7,4 @@ class Base(DeclarativeBase): """Base class for DB tables""" - metadata = MetaData(schema=config.database_schema) + metadata = MetaData(schema=config.db.table_schema) diff --git a/src/lsst/cmservice/db/row.py b/src/lsst/cmservice/db/row.py index bbe2b3baa..1c9ca6160 100644 --- a/src/lsst/cmservice/db/row.py +++ b/src/lsst/cmservice/db/row.py @@ -16,9 +16,8 @@ CMMissingFullnameError, CMMissingIDError, ) -from ..config import config -logger = get_logger(config.logger_name) +logger = get_logger(__name__) T = TypeVar("T", bound="RowMixin") diff --git a/src/lsst/cmservice/main.py b/src/lsst/cmservice/main.py index c9260bbc8..ae72914cd 100644 --- a/src/lsst/cmservice/main.py +++ b/src/lsst/cmservice/main.py @@ -36,8 +36,8 @@ __all__ = ["app", "config"] -configure_logging(profile=config.profile, log_level=config.log_level, name=config.logger_name) -configure_uvicorn_logging(config.log_level) +configure_logging(profile=config.logging.profile, log_level=config.logging.level, name=__name__) +configure_uvicorn_logging(config.logging.level) tags_metadata = [ @@ -121,9 +121,9 @@ async def lifespan(_: FastAPI) -> AsyncGenerator: """Hook FastAPI init/cleanups.""" # Dependency inits before app starts running - await db_session_dependency.initialize(config.database_url, config.database_password) - assert db_session_dependency._engine is not None # pylint: disable=protected-access - db_session_dependency._engine.echo = config.database_echo # pylint: disable=protected-access + await db_session_dependency.initialize(config.db.url, config.db.password) + assert db_session_dependency._engine is not None + db_session_dependency._engine.echo = config.db.echo # App runs here... yield @@ -135,43 +135,43 @@ async def lifespan(_: FastAPI) -> AsyncGenerator: app = FastAPI( lifespan=lifespan, - title="cm-service", + title=config.asgi.title, version=__version__, - openapi_url=f"{config.prefix}/openapi.json", + openapi_url=f"{config.asgi.prefix}/openapi.json", openapi_tags=tags_metadata, - docs_url=f"{config.prefix}/docs", - redoc_url=f"{config.prefix}/redoc", + docs_url=f"{config.asgi.prefix}/docs", + redoc_url=f"{config.asgi.prefix}/redoc", ) app.add_middleware(XForwardedMiddleware) app.include_router(index.router) -app.include_router(loaders.router, prefix=config.prefix) -app.include_router(actions.router, prefix=config.prefix) +app.include_router(loaders.router, prefix=config.asgi.prefix) +app.include_router(actions.router, prefix=config.asgi.prefix) -app.include_router(productions.router, prefix=config.prefix) -app.include_router(campaigns.router, prefix=config.prefix) -app.include_router(steps.router, prefix=config.prefix) -app.include_router(groups.router, prefix=config.prefix) -app.include_router(jobs.router, prefix=config.prefix) -app.include_router(scripts.router, prefix=config.prefix) +app.include_router(productions.router, prefix=config.asgi.prefix) +app.include_router(campaigns.router, prefix=config.asgi.prefix) +app.include_router(steps.router, prefix=config.asgi.prefix) +app.include_router(groups.router, prefix=config.asgi.prefix) +app.include_router(jobs.router, prefix=config.asgi.prefix) +app.include_router(scripts.router, prefix=config.asgi.prefix) -app.include_router(specifications.router, prefix=config.prefix) -app.include_router(spec_blocks.router, prefix=config.prefix) -app.include_router(script_templates.router, prefix=config.prefix) +app.include_router(specifications.router, prefix=config.asgi.prefix) +app.include_router(spec_blocks.router, prefix=config.asgi.prefix) +app.include_router(script_templates.router, prefix=config.asgi.prefix) -app.include_router(pipetask_error_types.router, prefix=config.prefix) -app.include_router(pipetask_errors.router, prefix=config.prefix) -app.include_router(script_errors.router, prefix=config.prefix) +app.include_router(pipetask_error_types.router, prefix=config.asgi.prefix) +app.include_router(pipetask_errors.router, prefix=config.asgi.prefix) +app.include_router(script_errors.router, prefix=config.asgi.prefix) -app.include_router(task_sets.router, prefix=config.prefix) -app.include_router(product_sets.router, prefix=config.prefix) -app.include_router(wms_task_reports.router, prefix=config.prefix) +app.include_router(task_sets.router, prefix=config.asgi.prefix) +app.include_router(product_sets.router, prefix=config.asgi.prefix) +app.include_router(wms_task_reports.router, prefix=config.asgi.prefix) -app.include_router(script_dependencies.router, prefix=config.prefix) -app.include_router(step_dependencies.router, prefix=config.prefix) -app.include_router(queues.router, prefix=config.prefix) +app.include_router(script_dependencies.router, prefix=config.asgi.prefix) +app.include_router(step_dependencies.router, prefix=config.asgi.prefix) +app.include_router(queues.router, prefix=config.asgi.prefix) # Start the frontend web application. -app.mount("/web_app", web_app) +app.mount(config.asgi.frontend_prefix, web_app) diff --git a/src/lsst/cmservice/routers/wrappers.py b/src/lsst/cmservice/routers/wrappers.py index 732c39c8d..99b41e664 100644 --- a/src/lsst/cmservice/routers/wrappers.py +++ b/src/lsst/cmservice/routers/wrappers.py @@ -20,9 +20,8 @@ from .. import db, models from ..common.enums import StatusEnum from ..common.errors import CMMissingFullnameError, CMMissingIDError -from ..config import config -logger = get_logger(config.logger_name) +logger = get_logger(__name__) def get_rows_no_parent_function( diff --git a/src/lsst/cmservice/web_app/app.py b/src/lsst/cmservice/web_app/app.py index cd802d617..c5f54af92 100644 --- a/src/lsst/cmservice/web_app/app.py +++ b/src/lsst/cmservice/web_app/app.py @@ -31,9 +31,9 @@ async def lifespan(_: FastAPI) -> AsyncGenerator: """Hook FastAPI init/cleanups.""" # Dependency inits before app starts running - await db_session_dependency.initialize(config.database_url, config.database_password) + await db_session_dependency.initialize(config.db.url, config.db.password) assert db_session_dependency._engine is not None # pylint: disable=protected-access - db_session_dependency._engine.echo = config.database_echo # pylint: disable=protected-access + db_session_dependency._engine.echo = config.db.echo # pylint: disable=protected-access # App runs here... yield diff --git a/tests/cli/test_campaigns.py b/tests/cli/test_campaigns.py index fc2a018a4..88e813de9 100644 --- a/tests/cli/test_campaigns.py +++ b/tests/cli/test_campaigns.py @@ -26,7 +26,7 @@ async def test_campaign_cli(uvicorn: UvicornProcess) -> None: """Test `campaign` CLI command""" - client_config.service_url = f"{uvicorn.url}{config.prefix}" + client_config.service_url = f"{uvicorn.url}{config.asgi.prefix}" runner = CliRunner() # generate a uuid to avoid collisions diff --git a/tests/cli/test_commands.py b/tests/cli/test_commands.py index 0add8a494..964bf33f5 100644 --- a/tests/cli/test_commands.py +++ b/tests/cli/test_commands.py @@ -9,7 +9,7 @@ def test_commands_cli(uvicorn: UvicornProcess) -> None: """Test miscellaneous CLI commands""" - client_config.service_url = f"{uvicorn.url}{config.prefix}" + client_config.service_url = f"{uvicorn.url}{config.asgi.prefix}" runner = CliRunner() result = runner.invoke(server, "--version") diff --git a/tests/cli/test_errors.py b/tests/cli/test_errors.py index 5a68ad499..75fa5f827 100644 --- a/tests/cli/test_errors.py +++ b/tests/cli/test_errors.py @@ -21,7 +21,7 @@ async def test_error_create_cli(uvicorn: UvicornProcess) -> None: fake error which is not in the database. """ - client_config.service_url = f"{uvicorn.url}{config.prefix}" + client_config.service_url = f"{uvicorn.url}{config.asgi.prefix}" runner = CliRunner() result = runner.invoke( @@ -41,7 +41,7 @@ async def test_error_create_cli(uvicorn: UvicornProcess) -> None: async def test_load_error_types_cli(uvicorn: UvicornProcess) -> None: """Test `error_type` db table.""" - client_config.service_url = f"{uvicorn.url}{config.prefix}" + client_config.service_url = f"{uvicorn.url}{config.asgi.prefix}" runner = CliRunner() result = runner.invoke(client_top, "load error-types --yaml_file examples/error_types.yaml") diff --git a/tests/cli/test_groups.py b/tests/cli/test_groups.py index 94912b63e..500b27986 100644 --- a/tests/cli/test_groups.py +++ b/tests/cli/test_groups.py @@ -23,7 +23,7 @@ async def test_group_cli(uvicorn: UvicornProcess) -> None: """Test `group` CLI command""" - client_config.service_url = f"{uvicorn.url}{config.prefix}" + client_config.service_url = f"{uvicorn.url}{config.asgi.prefix}" runner = CliRunner() # generate a uuid to avoid collisions diff --git a/tests/cli/test_jobs.py b/tests/cli/test_jobs.py index e297cf738..4784f862e 100644 --- a/tests/cli/test_jobs.py +++ b/tests/cli/test_jobs.py @@ -23,7 +23,7 @@ async def test_job_cli(uvicorn: UvicornProcess) -> None: """Test `job` CLI command""" - client_config.service_url = f"{uvicorn.url}{config.prefix}" + client_config.service_url = f"{uvicorn.url}{config.asgi.prefix}" runner = CliRunner() # generate a uuid to avoid collisions diff --git a/tests/cli/test_others.py b/tests/cli/test_others.py index 881ca228b..873dde115 100644 --- a/tests/cli/test_others.py +++ b/tests/cli/test_others.py @@ -12,7 +12,7 @@ async def test_others_cli(uvicorn: UvicornProcess) -> None: """Test `other` CLI command""" - client_config.service_url = f"{uvicorn.url}{config.prefix}" + client_config.service_url = f"{uvicorn.url}{config.asgi.prefix}" runner = CliRunner() result = runner.invoke(client_top, "pipetask_error list --output yaml") diff --git a/tests/cli/test_productions.py b/tests/cli/test_productions.py index 74e851e6d..04c5259ed 100644 --- a/tests/cli/test_productions.py +++ b/tests/cli/test_productions.py @@ -15,7 +15,7 @@ async def test_production_cli(uvicorn: UvicornProcess) -> None: """Test `production` CLI command""" - client_config.service_url = f"{uvicorn.url}{config.prefix}" + client_config.service_url = f"{uvicorn.url}{config.asgi.prefix}" runner = CliRunner() # generate a uuid to avoid collisions diff --git a/tests/cli/test_steps.py b/tests/cli/test_steps.py index a21d22b02..459f083de 100644 --- a/tests/cli/test_steps.py +++ b/tests/cli/test_steps.py @@ -23,7 +23,7 @@ async def test_step_cli(uvicorn: UvicornProcess) -> None: """Test `step` CLI command""" - client_config.service_url = f"{uvicorn.url}{config.prefix}" + client_config.service_url = f"{uvicorn.url}{config.asgi.prefix}" runner = CliRunner() # generate a uuid to avoid collisions diff --git a/tests/cli/test_trivial.py b/tests/cli/test_trivial.py index c95c2ccab..da5b41925 100644 --- a/tests/cli/test_trivial.py +++ b/tests/cli/test_trivial.py @@ -17,7 +17,7 @@ async def test_cli_trivial_campaign(uvicorn: UvicornProcess) -> None: """Test fake end to end run using example/example_trivial.yaml""" - client_config.service_url = f"{uvicorn.url}{config.prefix}" + client_config.service_url = f"{uvicorn.url}{config.asgi.prefix}" runner = CliRunner() yaml_file = "examples/example_trivial.yaml" diff --git a/tests/common/test_config.py b/tests/common/test_config.py new file mode 100644 index 000000000..40c9f539a --- /dev/null +++ b/tests/common/test_config.py @@ -0,0 +1,30 @@ +from typing import Any + +from lsst.cmservice.config import Configuration + + +def test_config_nested_partial_update(monkeypatch: Any) -> None: + """Tests the nested config modules for partial updates from environment + variables. + """ + # An all-defaults configuration + config_a = Configuration() + assert not config_a.db.echo + assert config_a.htcondor.condor_q_bin == "condor_q" + assert config_a.slurm.sacct_bin == "sacct" + assert config_a.asgi.port == 8080 + assert config_a.logging.profile == "development" + + monkeypatch.setenv("LOGGING__PROFILE", "production") + monkeypatch.setenv("ASGI__PORT", "5000") + monkeypatch.setenv("HTCONDOR__CONDOR_Q_BIN", "/usr/local/bin/condor_q") + monkeypatch.setenv("SLURM__SACCT_BIN", "/opt/slurm/bin/sacct") + monkeypatch.setenv("DB__ECHO", "1") + + # Partial updates in nested configuration models + config_b = Configuration() + assert config_b.db.echo + assert config_b.htcondor.condor_q_bin == "/usr/local/bin/condor_q" + assert config_b.slurm.sacct_bin == "/opt/slurm/bin/sacct" + assert config_b.asgi.port == 5000 + assert config_b.logging.profile == "production" diff --git a/tests/conftest.py b/tests/conftest.py index 9e2e258a6..c197785d9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -19,8 +19,8 @@ @pytest_asyncio.fixture(name="engine") async def engine_fixture() -> AsyncIterator[AsyncEngine]: """Return a SQLAlchemy AsyncEngine configured to talk to the app db.""" - logger = structlog.get_logger(config.logger_name) - the_engine = create_database_engine(config.database_url, config.database_password) + logger = structlog.get_logger(__name__) + the_engine = create_database_engine(config.db.url, config.db.password) await initialize_database(the_engine, logger, schema=db.Base.metadata, reset=True) yield the_engine await the_engine.dispose() diff --git a/tests/db/test_campaign.py b/tests/db/test_campaign.py index f8d9d92cc..31608f465 100644 --- a/tests/db/test_campaign.py +++ b/tests/db/test_campaign.py @@ -10,7 +10,6 @@ from lsst.cmservice import db from lsst.cmservice.common import errors from lsst.cmservice.common.enums import LevelEnum -from lsst.cmservice.config import config from lsst.cmservice.handlers import interface from .util_functions import ( @@ -31,7 +30,7 @@ async def test_campaign_db(engine: AsyncEngine) -> None: # generate a uuid to avoid collisions uuid_int = uuid.uuid1().int - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/db/test_daemon.py b/tests/db/test_daemon.py index cce97a63e..d226f0d4a 100644 --- a/tests/db/test_daemon.py +++ b/tests/db/test_daemon.py @@ -10,7 +10,6 @@ from lsst.cmservice import db from lsst.cmservice.common.daemon import daemon_iteration from lsst.cmservice.common.enums import StatusEnum -from lsst.cmservice.config import config from lsst.cmservice.handlers import interface from .util_functions import cleanup @@ -20,7 +19,7 @@ async def test_daemon_db(engine: AsyncEngine) -> None: """Test creating a job, add it to the work queue, and start processing.""" - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) CM_CONFIGS = "examples" diff --git a/tests/db/test_group.py b/tests/db/test_group.py index 5a16b2429..28ac0a421 100644 --- a/tests/db/test_group.py +++ b/tests/db/test_group.py @@ -10,7 +10,6 @@ from lsst.cmservice import db from lsst.cmservice.common import errors from lsst.cmservice.common.enums import LevelEnum -from lsst.cmservice.config import config from .util_functions import ( check_get_methods, @@ -28,7 +27,7 @@ async def test_group_db(engine: AsyncEngine) -> None: # generate a uuid to avoid collisions uuid_int = uuid.uuid1().int - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/db/test_handlers.py b/tests/db/test_handlers.py index 3ddbc5788..177dd09e7 100644 --- a/tests/db/test_handlers.py +++ b/tests/db/test_handlers.py @@ -9,7 +9,6 @@ from lsst.cmservice import db from lsst.cmservice.common.enums import LevelEnum, StatusEnum -from lsst.cmservice.config import config from lsst.cmservice.handlers import interface, jobs from .util_functions import cleanup, create_tree @@ -94,7 +93,7 @@ async def test_handlers_campaign_level_db( """Test to run the write and purge methods of various scripts""" temp_dir = str(tmp_path / "archive") - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" @@ -177,7 +176,7 @@ async def test_handlers_step_level_db( """Test to run the write and purge methods of various scripts""" temp_dir = str(tmp_path / "archive") - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" @@ -215,7 +214,7 @@ async def test_handlers_group_level_db( """Test to run the write and purge methods of various scripts""" temp_dir = str(tmp_path / "archive") - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" @@ -273,7 +272,7 @@ async def test_handlers_job_level_db( """Test to run the write and purge methods of various scripts""" temp_dir = str(tmp_path / "archive") - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/db/test_job.py b/tests/db/test_job.py index bd99623cd..573152604 100644 --- a/tests/db/test_job.py +++ b/tests/db/test_job.py @@ -10,7 +10,6 @@ from lsst.cmservice import db from lsst.cmservice.common import errors from lsst.cmservice.common.enums import LevelEnum, StatusEnum -from lsst.cmservice.config import config from lsst.cmservice.handlers import interface from .util_functions import ( @@ -29,7 +28,7 @@ async def test_job_db(engine: AsyncEngine) -> None: # generate a uuid to avoid collisions uuid_int = uuid.uuid1().int - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/db/test_micro.py b/tests/db/test_micro.py index 624242d97..c2f84de19 100644 --- a/tests/db/test_micro.py +++ b/tests/db/test_micro.py @@ -8,7 +8,6 @@ from lsst.cmservice.common import errors from lsst.cmservice.common.enums import ScriptMethodEnum, StatusEnum -from lsst.cmservice.config import config from lsst.cmservice.handlers import interface from lsst.cmservice.handlers.script_handler import ScriptHandler @@ -29,7 +28,7 @@ async def test_micro_db( orig_method = ScriptHandler.default_method ScriptHandler.default_method = script_method - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/db/test_pipetask_error_type.py b/tests/db/test_pipetask_error_type.py index eda1d47ec..1674b8aa0 100644 --- a/tests/db/test_pipetask_error_type.py +++ b/tests/db/test_pipetask_error_type.py @@ -7,7 +7,6 @@ from sqlalchemy.ext.asyncio import AsyncEngine from lsst.cmservice import db -from lsst.cmservice.config import config from lsst.cmservice.handlers import functions, interface from .util_functions import cleanup, delete_all_rows @@ -21,7 +20,7 @@ async def test_error_match_db(engine: AsyncEngine) -> None: fake error which is not in the database. """ - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" @@ -112,7 +111,7 @@ async def test_error_match_db(engine: AsyncEngine) -> None: async def test_error_type_db(engine: AsyncEngine) -> None: """Test `error_type` db table.""" - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/db/test_production.py b/tests/db/test_production.py index 1986bceb1..83eb8e8ba 100644 --- a/tests/db/test_production.py +++ b/tests/db/test_production.py @@ -10,7 +10,6 @@ from lsst.cmservice import db from lsst.cmservice.common import errors from lsst.cmservice.common.enums import LevelEnum -from lsst.cmservice.config import config from .util_functions import cleanup, create_tree @@ -21,7 +20,7 @@ async def test_production_db(engine: AsyncEngine) -> None: # generate a uuid to avoid collisions uuid_int = uuid.uuid1().int - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/db/test_reports.py b/tests/db/test_reports.py index a571e87ae..952ffdde8 100644 --- a/tests/db/test_reports.py +++ b/tests/db/test_reports.py @@ -8,7 +8,6 @@ from lsst.cmservice import db from lsst.cmservice.common.enums import LevelEnum, StatusEnum -from lsst.cmservice.config import config from lsst.cmservice.handlers import functions, interface from .util_functions import ( @@ -23,7 +22,7 @@ async def test_reports_db(engine: AsyncEngine) -> None: # generate a uuid to avoid collisions uuid_int = uuid.uuid1().int - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/db/test_step.py b/tests/db/test_step.py index 5c32afc32..5c95aff20 100644 --- a/tests/db/test_step.py +++ b/tests/db/test_step.py @@ -10,7 +10,6 @@ from lsst.cmservice import db from lsst.cmservice.common import errors from lsst.cmservice.common.enums import LevelEnum -from lsst.cmservice.config import config from .util_functions import ( check_get_methods, @@ -28,7 +27,7 @@ async def test_step_db(engine: AsyncEngine) -> None: # generate a uuid to avoid collisions uuid_int = uuid.uuid1().int - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/routers/test_campaigns.py b/tests/routers/test_campaigns.py index 5def157a5..2ce8bc889 100644 --- a/tests/routers/test_campaigns.py +++ b/tests/routers/test_campaigns.py @@ -31,7 +31,7 @@ async def test_campaign_routes(client: AsyncClient) -> None: # intialize a tree down to one level lower await create_tree(client, LevelEnum.step, uuid_int) - response = await client.get(f"{config.prefix}/campaign/list") + response = await client.get(f"{config.asgi.prefix}/campaign/list") campaigns = check_and_parse_response(response, list[models.Campaign]) entry = campaigns[0] @@ -41,7 +41,7 @@ async def test_campaign_routes(client: AsyncClient) -> None: ) response = await client.post( - f"{config.prefix}/load/steps", + f"{config.asgi.prefix}/load/steps", content=add_steps_query.model_dump_json(), ) campaign_check = check_and_parse_response(response, models.Campaign) diff --git a/tests/routers/test_errors.py b/tests/routers/test_errors.py index 1aa3ca253..4b6c7b297 100644 --- a/tests/routers/test_errors.py +++ b/tests/routers/test_errors.py @@ -19,7 +19,7 @@ async def test_load_error_types_routes(client: AsyncClient) -> None: ) response = await client.post( - f"{config.prefix}/load/error_types", + f"{config.asgi.prefix}/load/error_types", content=yaml_file_query.model_dump_json(), ) error_types = check_and_parse_response(response, list[models.PipetaskErrorType]) @@ -29,7 +29,7 @@ async def test_load_error_types_routes(client: AsyncClient) -> None: rematch=True, ) response = await client.post( - f"{config.prefix}/actions/rematch_errors", + f"{config.asgi.prefix}/actions/rematch_errors", content=rematch_query.model_dump_json(), ) matched_errors = check_and_parse_response(response, list[models.PipetaskError]) diff --git a/tests/routers/test_groups.py b/tests/routers/test_groups.py index cb173e643..01c83dd8d 100644 --- a/tests/routers/test_groups.py +++ b/tests/routers/test_groups.py @@ -31,7 +31,7 @@ async def test_group_routes(client: AsyncClient) -> None: # intialize a tree down to one level lower await create_tree(client, LevelEnum.job, uuid_int) - response = await client.get(f"{config.prefix}/group/list") + response = await client.get(f"{config.asgi.prefix}/group/list") groups = check_and_parse_response(response, list[models.Group]) entry = groups[0] diff --git a/tests/routers/test_jobs.py b/tests/routers/test_jobs.py index 0ff366b00..2f4ce9c5e 100644 --- a/tests/routers/test_jobs.py +++ b/tests/routers/test_jobs.py @@ -33,7 +33,7 @@ async def test_job_routes(client: AsyncClient) -> None: # intialize a tree down to one level lower await create_tree(client, LevelEnum.job, uuid_int) - response = await client.get(f"{config.prefix}/job/list") + response = await client.get(f"{config.asgi.prefix}/job/list") jobs = check_and_parse_response(response, list[models.Job]) entry = jobs[0] @@ -51,18 +51,18 @@ async def test_job_routes(client: AsyncClient) -> None: # test some job-specific stuff response = await client.get( - f"{config.prefix}/job/get/{entry.id}/parent", + f"{config.asgi.prefix}/job/get/{entry.id}/parent", ) parent = check_and_parse_response(response, models.Group) response = await client.get( - f"{config.prefix}/job/get/{entry.id}/errors", + f"{config.asgi.prefix}/job/get/{entry.id}/errors", ) check_errors = check_and_parse_response(response, list[models.PipetaskError]) assert len(check_errors) == 0 response = await client.get( - f"{config.prefix}/job/get/-1/errors", + f"{config.asgi.prefix}/job/get/-1/errors", ) expect_failed_response(response, 404) @@ -71,67 +71,67 @@ async def test_job_routes(client: AsyncClient) -> None: status=StatusEnum.rescuable, ) response = await client.put( - f"{config.prefix}/job/update/{entry.id}", + f"{config.asgi.prefix}/job/update/{entry.id}", content=update_model.model_dump_json(), ) response = await client.put( - f"{config.prefix}/job/update/-1", + f"{config.asgi.prefix}/job/update/-1", content=update_model.model_dump_json(), ) expect_failed_response(response, 404) response = await client.post( - f"{config.prefix}/group/action/{parent.id}/rescue_job", + f"{config.asgi.prefix}/group/action/{parent.id}/rescue_job", ) rescue_job = check_and_parse_response(response, models.Job) assert rescue_job.attempt == 1 response = await client.put( - f"{config.prefix}/job/update/{rescue_job.id}", + f"{config.asgi.prefix}/job/update/{rescue_job.id}", content=update_model.model_dump_json(), ) rescue_node_model = models.NodeQuery(fullname=parent.fullname) response = await client.post( - f"{config.prefix}/actions/rescue_job", content=rescue_node_model.model_dump_json() + f"{config.asgi.prefix}/actions/rescue_job", content=rescue_node_model.model_dump_json() ) rescue_job = check_and_parse_response(response, models.Job) assert rescue_job.attempt == 2 response = await client.get( - f"{config.prefix}/group/get/{parent.id}/jobs", + f"{config.asgi.prefix}/group/get/{parent.id}/jobs", ) check_jobs = check_and_parse_response(response, list[models.Job]) assert len(check_jobs) == 3 new_job = check_jobs[-1] response = await client.get( - f"{config.prefix}/group/get/-1/jobs", + f"{config.asgi.prefix}/group/get/-1/jobs", ) expect_failed_response(response, 404) update_model.status = StatusEnum.accepted response = await client.put( - f"{config.prefix}/job/update/{new_job.id}", + f"{config.asgi.prefix}/job/update/{new_job.id}", content=update_model.model_dump_json(), ) response = await client.post( - f"{config.prefix}/group/action/{parent.id}/mark_rescued", + f"{config.asgi.prefix}/group/action/{parent.id}/mark_rescued", ) check_jobs = check_and_parse_response(response, list[models.Job]) assert len(check_jobs) == 2 update_model.status = StatusEnum.rescuable response = await client.put( - f"{config.prefix}/job/update/{entry.id}", + f"{config.asgi.prefix}/job/update/{entry.id}", content=update_model.model_dump_json(), ) response = await client.post( - f"{config.prefix}/actions/mark_job_rescued", + f"{config.asgi.prefix}/actions/mark_job_rescued", content=rescue_node_model.model_dump_json(), ) check_jobs = check_and_parse_response(response, list[models.Job]) diff --git a/tests/routers/test_reports.py b/tests/routers/test_reports.py index 1ae9c785d..4f4851573 100644 --- a/tests/routers/test_reports.py +++ b/tests/routers/test_reports.py @@ -27,7 +27,7 @@ async def test_report_routes(client: AsyncClient) -> None: # intialize a tree down to one level lower await create_tree(client, LevelEnum.job, uuid_int) - response = await client.get(f"{config.prefix}/job/list") + response = await client.get(f"{config.asgi.prefix}/job/list") jobs = check_and_parse_response(response, list[models.Job]) entry = jobs[0] @@ -37,7 +37,7 @@ async def test_report_routes(client: AsyncClient) -> None: ) response = await client.post( - f"{config.prefix}/load/manifest_report", + f"{config.asgi.prefix}/load/manifest_report", content=manifest_report_query.model_dump_json(), ) assert response.is_success diff --git a/tests/routers/test_steps.py b/tests/routers/test_steps.py index b39b543c7..700683184 100644 --- a/tests/routers/test_steps.py +++ b/tests/routers/test_steps.py @@ -31,7 +31,7 @@ async def test_step_routes(client: AsyncClient) -> None: # intialize a tree down to one level lower await create_tree(client, LevelEnum.group, uuid_int) - response = await client.get(f"{config.prefix}/step/list") + response = await client.get(f"{config.asgi.prefix}/step/list") steps = check_and_parse_response(response, list[models.Step]) entry = steps[0] diff --git a/tests/routers/test_trivial.py b/tests/routers/test_trivial.py index f13f39824..b0b756d23 100644 --- a/tests/routers/test_trivial.py +++ b/tests/routers/test_trivial.py @@ -25,7 +25,7 @@ async def test_routers_trivial_campaign( ) response = await client.post( - f"{config.prefix}/load/specification", + f"{config.asgi.prefix}/load/specification", content=spec_load_model.model_dump_json(), ) specification = check_and_parse_response(response, models.Specification) @@ -39,7 +39,7 @@ async def test_routers_trivial_campaign( ) response = await client.post( - f"{config.prefix}/load/campaign", + f"{config.asgi.prefix}/load/campaign", content=campaign_load_model.model_dump_json(), ) campaign = check_and_parse_response(response, models.Campaign) diff --git a/tests/routers/util_functions.py b/tests/routers/util_functions.py index 49eb0e4f8..1679bc5b7 100644 --- a/tests/routers/util_functions.py +++ b/tests/routers/util_functions.py @@ -40,7 +40,7 @@ async def add_scripts( ) response = await client.post( - f"{config.prefix}/script/create", + f"{config.asgi.prefix}/script/create", content=prep_script_model.model_dump_json(), ) prep_script = check_and_parse_response(response, models.Script) @@ -52,7 +52,7 @@ async def add_scripts( spec_block_name="null_script", ) response = await client.post( - f"{config.prefix}/script/create", + f"{config.asgi.prefix}/script/create", content=collect_script_model.model_dump_json(), ) collect_script = check_and_parse_response(response, models.Script) @@ -62,7 +62,7 @@ async def add_scripts( depend_id=collect_script.id, ) response = await client.post( - f"{config.prefix}/script_dependency/create", + f"{config.asgi.prefix}/script_dependency/create", content=script_depend_model.model_dump_json(), ) script_depend = check_and_parse_response(response, models.Dependency) @@ -78,7 +78,7 @@ async def create_tree( yaml_file="examples/empty_config.yaml", ) response = await client.post( - f"{config.prefix}/load/specification", + f"{config.asgi.prefix}/load/specification", content=specification_load_model.model_dump_json(), ) check_and_parse_response(response, models.Specification) @@ -87,7 +87,7 @@ async def create_tree( production_model = models.ProductionCreate(name=pname) response = await client.post( - f"{config.prefix}/production/create", + f"{config.asgi.prefix}/production/create", content=production_model.model_dump_json(), ) check_and_parse_response(response, models.Production) @@ -99,7 +99,7 @@ async def create_tree( parent_name=pname, ) response = await client.post( - f"{config.prefix}/campaign/create", + f"{config.asgi.prefix}/campaign/create", content=campaign_model.model_dump_json(), ) camp = check_and_parse_response(response, models.Campaign) @@ -118,7 +118,7 @@ async def create_tree( parent_name=camp.fullname, ) response = await client.post( - f"{config.prefix}/step/create", + f"{config.asgi.prefix}/step/create", content=step_model.model_dump_json(), ) step = check_and_parse_response(response, models.Step) @@ -132,7 +132,7 @@ async def create_tree( depend_id=steps[1].id, ) response = await client.post( - f"{config.prefix}/step_dependency/create", + f"{config.asgi.prefix}/step_dependency/create", content=step_depend_model.model_dump_json(), ) step_depend = check_and_parse_response(response, models.Dependency) @@ -154,7 +154,7 @@ async def create_tree( parent_name=steps[1].fullname, ) response = await client.post( - f"{config.prefix}/group/create", + f"{config.asgi.prefix}/group/create", content=group_model.model_dump_json(), ) group = check_and_parse_response(response, models.Group) @@ -174,7 +174,7 @@ async def create_tree( parent_name=group_.fullname, ) response = await client.post( - f"{config.prefix}/job/create", + f"{config.asgi.prefix}/job/create", content=job_model.model_dump_json(), ) job = check_and_parse_response(response, models.Job) @@ -191,13 +191,13 @@ async def delete_all_rows( entry_class_name: str, entry_class: TypeAlias = models.ElementMixin, ) -> None: - response = await client.get(f"{config.prefix}/{entry_class_name}/list") + response = await client.get(f"{config.asgi.prefix}/{entry_class_name}/list") rows = check_and_parse_response(response, list[entry_class]) for row_ in rows: - await client.delete(f"{config.prefix}/{entry_class_name}/delete/{row_.id}") + await client.delete(f"{config.asgi.prefix}/{entry_class_name}/delete/{row_.id}") - response = await client.get(f"{config.prefix}/{entry_class_name}/list") + response = await client.get(f"{config.asgi.prefix}/{entry_class_name}/list") rows_check = check_and_parse_response(response, list[entry_class]) assert len(rows_check) == 0, f"Failed to delete all {entry_class_name}" @@ -210,7 +210,7 @@ async def delete_all_productions( ) -> None: await delete_all_rows(client, "production", models.Production) if check_cascade: - response = await client.get(f"{config.prefix}/campaign/list") + response = await client.get(f"{config.asgi.prefix}/campaign/list") n_campaigns = len(check_and_parse_response(response, list[models.Campaign])) assert n_campaigns == 0 @@ -250,26 +250,26 @@ async def check_update_methods( update_dict=dict(test="dummy"), ) response = await client.post( - f"{config.prefix}/{entry_class_name}/update/{entry.id}/data_dict", + f"{config.asgi.prefix}/{entry_class_name}/update/{entry.id}/data_dict", content=update_model.model_dump_json(), ) check = check_and_parse_response(response, entry_class) assert check.data["test"] == "dummy", "update_data_dict failed" response = await client.post( - f"{config.prefix}/{entry_class_name}/update/-1/data_dict", + f"{config.asgi.prefix}/{entry_class_name}/update/-1/data_dict", content=update_model.model_dump_json(), ) expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/data_dict", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/data_dict", ) check = check_and_parse_response(response, dict) assert check["test"] == "dummy", "get_data_dict failed" response = await client.get( - f"{config.prefix}/{entry_class_name}/get/-1/data_dict", + f"{config.asgi.prefix}/{entry_class_name}/get/-1/data_dict", ) expect_failed_response(response, 404) @@ -278,37 +278,37 @@ async def check_update_methods( update_dict=dict(test="dummy"), ) response = await client.post( - f"{config.prefix}/{entry_class_name}/update/{entry.id}/collections", + f"{config.asgi.prefix}/{entry_class_name}/update/{entry.id}/collections", content=update_model.model_dump_json(), ) check = check_and_parse_response(response, entry_class) assert check.collections["test"] == "dummy", "update_collections failed" response = await client.post( - f"{config.prefix}/{entry_class_name}/update/-1/collections", + f"{config.asgi.prefix}/{entry_class_name}/update/-1/collections", content=update_model.model_dump_json(), ) expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/collections", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/collections", ) check = check_and_parse_response(response, dict) assert check["test"] == "dummy", "get_collections failed" response = await client.get( - f"{config.prefix}/{entry_class_name}/get/-1/collections", + f"{config.asgi.prefix}/{entry_class_name}/get/-1/collections", ) expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/resolved_collections", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/resolved_collections", ) check = check_and_parse_response(response, dict) assert check["test"] == "dummy", "get_resolved_collections failed" response = await client.get( - f"{config.prefix}/{entry_class_name}/get/-1/resolved_collections", + f"{config.asgi.prefix}/{entry_class_name}/get/-1/resolved_collections", ) expect_failed_response(response, 404) @@ -317,26 +317,26 @@ async def check_update_methods( update_dict=dict(test="dummy"), ) response = await client.post( - f"{config.prefix}/{entry_class_name}/update/{entry.id}/child_config", + f"{config.asgi.prefix}/{entry_class_name}/update/{entry.id}/child_config", content=update_model.model_dump_json(), ) check = check_and_parse_response(response, entry_class) assert check.child_config["test"] == "dummy", "update_child_config failed" response = await client.post( - f"{config.prefix}/{entry_class_name}/update/-1/child_config", + f"{config.asgi.prefix}/{entry_class_name}/update/-1/child_config", content=update_model.model_dump_json(), ) expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/child_config", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/child_config", ) check = check_and_parse_response(response, dict) assert check["test"] == "dummy", "get_child_config failed" response = await client.get( - f"{config.prefix}/{entry_class_name}/get/-1/child_config", + f"{config.asgi.prefix}/{entry_class_name}/get/-1/child_config", ) expect_failed_response(response, 404) @@ -345,26 +345,26 @@ async def check_update_methods( update_dict=dict(test="dummy"), ) response = await client.post( - f"{config.prefix}/{entry_class_name}/update/{entry.id}/spec_aliases", + f"{config.asgi.prefix}/{entry_class_name}/update/{entry.id}/spec_aliases", content=update_model.model_dump_json(), ) check = check_and_parse_response(response, entry_class) assert check.spec_aliases["test"] == "dummy", "update_spec_aliases failed" response = await client.post( - f"{config.prefix}/{entry_class_name}/update/-1/spec_aliases", + f"{config.asgi.prefix}/{entry_class_name}/update/-1/spec_aliases", content=update_model.model_dump_json(), ) expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/spec_aliases", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/spec_aliases", ) check = check_and_parse_response(response, dict) assert check["test"] == "dummy", "get_spec_aliases failed" response = await client.get( - f"{config.prefix}/{entry_class_name}/get/-1/spec_aliases", + f"{config.asgi.prefix}/{entry_class_name}/get/-1/spec_aliases", ) expect_failed_response(response, 404) @@ -374,14 +374,14 @@ async def check_update_methods( ) response = await client.post( - f"{config.prefix}/{entry_class_name}/update/{entry.id}/status", + f"{config.asgi.prefix}/{entry_class_name}/update/{entry.id}/status", content=update_status_model.model_dump_json(), ) check_update = check_and_parse_response(response, entry_class) assert check_update.status == StatusEnum.reviewable response = await client.post( - f"{config.prefix}/{entry_class_name}/action/{entry.id}/reject", + f"{config.asgi.prefix}/{entry_class_name}/action/{entry.id}/reject", ) check_update = check_and_parse_response(response, entry_class) assert check_update.status == StatusEnum.rejected, "reject() failed" @@ -391,33 +391,33 @@ async def check_update_methods( ) response = await client.post( - f"{config.prefix}/{entry_class_name}/action/{entry.id}/reset", + f"{config.asgi.prefix}/{entry_class_name}/action/{entry.id}/reset", content=reset_model.model_dump_json(), ) check_update = check_and_parse_response(response, entry_class) assert check_update.status == StatusEnum.waiting, "reset() failed" response = await client.post( - f"{config.prefix}/{entry_class_name}/action/{entry.id}/accept", + f"{config.asgi.prefix}/{entry_class_name}/action/{entry.id}/accept", ) expect_failed_response(response, 500) update_status_model.status = StatusEnum.running response = await client.post( - f"{config.prefix}/{entry_class_name}/update/{entry.id}/status", + f"{config.asgi.prefix}/{entry_class_name}/update/{entry.id}/status", content=update_status_model.model_dump_json(), ) check_update = check_and_parse_response(response, entry_class) assert check_update.status == StatusEnum.running response = await client.post( - f"{config.prefix}/{entry_class_name}/action/{entry.id}/run_check", + f"{config.asgi.prefix}/{entry_class_name}/action/{entry.id}/run_check", ) check_run_check = check_and_parse_response(response, tuple[bool, StatusEnum]) assert check_run_check[1] == StatusEnum.running response = await client.post( - f"{config.prefix}/{entry_class_name}/action/{entry.id}/process", + f"{config.asgi.prefix}/{entry_class_name}/action/{entry.id}/process", ) check_process = check_and_parse_response(response, tuple[bool, StatusEnum]) assert check_process[1] == StatusEnum.running @@ -426,7 +426,7 @@ async def check_update_methods( fullname=entry.fullname, ) response = await client.post( - f"{config.prefix}/actions/process", + f"{config.asgi.prefix}/actions/process", content=process_query.model_dump_json(), ) check_process = check_and_parse_response(response, tuple[bool, StatusEnum]) @@ -434,62 +434,62 @@ async def check_update_methods( process_query.fake_status = StatusEnum.running.value response = await client.post( - f"{config.prefix}/actions/process", + f"{config.asgi.prefix}/actions/process", content=process_query.model_dump_json(), ) check_process = check_and_parse_response(response, tuple[bool, StatusEnum]) assert check_process[1] == StatusEnum.running response = await client.post( - f"{config.prefix}/{entry_class_name}/action/{entry.id}/accept", + f"{config.asgi.prefix}/{entry_class_name}/action/{entry.id}/accept", ) check_update = check_and_parse_response(response, entry_class) assert check_update.status == StatusEnum.accepted response = await client.delete( - f"{config.prefix}/{entry_class_name}/delete/{entry.id}", + f"{config.asgi.prefix}/{entry_class_name}/delete/{entry.id}", ) expect_failed_response(response, 500) response = await client.post( - f"{config.prefix}/{entry_class_name}/action/{entry.id}/reject", + f"{config.asgi.prefix}/{entry_class_name}/action/{entry.id}/reject", ) expect_failed_response(response, 500) response = await client.post( - f"{config.prefix}/{entry_class_name}/action/{entry.id}/reset", + f"{config.asgi.prefix}/{entry_class_name}/action/{entry.id}/reset", content=reset_model.model_dump_json(), ) expect_failed_response(response, 500) response = await client.post( - f"{config.prefix}/{entry_class_name}/action/-1/accept", + f"{config.asgi.prefix}/{entry_class_name}/action/-1/accept", ) expect_failed_response(response, 404) response = await client.delete( - f"{config.prefix}/{entry_class_name}/delete/-1", + f"{config.asgi.prefix}/{entry_class_name}/delete/-1", ) expect_failed_response(response, 404) response = await client.post( - f"{config.prefix}/{entry_class_name}/action/-1/reject", + f"{config.asgi.prefix}/{entry_class_name}/action/-1/reject", ) expect_failed_response(response, 404) response = await client.post( - f"{config.prefix}/{entry_class_name}/action/-1/reset", + f"{config.asgi.prefix}/{entry_class_name}/action/-1/reset", content=reset_model.model_dump_json(), ) expect_failed_response(response, 404) response = await client.post( - f"{config.prefix}/{entry_class_name}/action/-1/process", + f"{config.asgi.prefix}/{entry_class_name}/action/-1/process", ) expect_failed_response(response, 404) response = await client.post( - f"{config.prefix}/{entry_class_name}/action/-1/run_check", + f"{config.asgi.prefix}/{entry_class_name}/action/-1/run_check", ) expect_failed_response(response, 404) @@ -504,7 +504,7 @@ async def check_scripts( script_name=None, ) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/scripts", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/scripts", params=query_model.model_dump(), ) scripts = check_and_parse_response(response, list[models.Script]) @@ -512,18 +512,18 @@ async def check_scripts( for script_ in scripts: response = await client.get( - f"{config.prefix}/script/get/{script_.id}/parent", + f"{config.asgi.prefix}/script/get/{script_.id}/parent", ) parent_check = check_and_parse_response(response, models.ElementMixin) assert parent_check.id == entry.id response = await client.get( - f"{config.prefix}/script/get/-1/parent", + f"{config.asgi.prefix}/script/get/-1/parent", ) expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/-1/scripts", + f"{config.asgi.prefix}/{entry_class_name}/get/-1/scripts", params=query_model.model_dump(), ) expect_failed_response(response, 404) @@ -533,7 +533,7 @@ async def check_scripts( script_name="bad", ) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/scripts", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/scripts", params=query_model.model_dump(), ) @@ -545,14 +545,14 @@ async def check_scripts( script_name=None, ) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/all_scripts", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/all_scripts", params=query_model1.model_dump(), ) all_scripts = check_and_parse_response(response, list[models.Script]) assert len(all_scripts) != 0, "get_all_scripts with failed" response = await client.get( - f"{config.prefix}/{entry_class_name}/get/-1/all_scripts", + f"{config.asgi.prefix}/{entry_class_name}/get/-1/all_scripts", params=query_model1.model_dump(), ) expect_failed_response(response, 404) @@ -565,19 +565,19 @@ async def check_scripts( script1 = scripts[0] response = await client.get( - f"{config.prefix}/script/get/{script0.id}/check_prerequisites", + f"{config.asgi.prefix}/script/get/{script0.id}/check_prerequisites", ) script0_prereq = check_and_parse_response(response, bool) response = await client.get( - f"{config.prefix}/script/get/{script1.id}/check_prerequisites", + f"{config.asgi.prefix}/script/get/{script1.id}/check_prerequisites", ) script1_prereq = check_and_parse_response(response, bool) assert script0_prereq assert not script1_prereq response = await client.get( - f"{config.prefix}/script/get/-1/check_prerequisites", + f"{config.asgi.prefix}/script/get/-1/check_prerequisites", ) expect_failed_response(response, 404) @@ -587,13 +587,14 @@ async def check_scripts( ) response = await client.post( - f"{config.prefix}/script/update/{script0.id}/status", content=update_status_model.model_dump_json() + f"{config.asgi.prefix}/script/update/{script0.id}/status", + content=update_status_model.model_dump_json(), ) update_check = check_and_parse_response(response, models.Script) assert update_check.status == StatusEnum.failed response = await client.post( - f"{config.prefix}/script/update/-1/status", content=update_status_model.model_dump_json() + f"{config.asgi.prefix}/script/update/-1/status", content=update_status_model.model_dump_json() ) expect_failed_response(response, 404) @@ -605,20 +606,20 @@ async def check_scripts( ) response = await client.post( - f"{config.prefix}/{entry_class_name}/action/{entry.id}/retry_script", + f"{config.asgi.prefix}/{entry_class_name}/action/{entry.id}/retry_script", content=query_model2.model_dump_json(), ) retry_check = check_and_parse_response(response, models.Script) assert retry_check.status == StatusEnum.waiting response = await client.post( - f"{config.prefix}/{entry_class_name}/action/-1/retry_script", + f"{config.asgi.prefix}/{entry_class_name}/action/-1/retry_script", content=query_model2.model_dump_json(), ) expect_failed_response(response, 404) response = await client.post( - f"{config.prefix}/script/update/{script0.id}/status", + f"{config.asgi.prefix}/script/update/{script0.id}/status", content=update_status_model.model_dump_json(), ) update_check = check_and_parse_response(response, models.Script) @@ -630,14 +631,14 @@ async def check_scripts( ) response = await client.post( - f"{config.prefix}/script/action/{script0.id}/reset_script", + f"{config.asgi.prefix}/script/action/{script0.id}/reset_script", content=reset_query.model_dump_json(), ) status_check = check_and_parse_response(response, StatusEnum) assert status_check == StatusEnum.waiting response = await client.post( - f"{config.prefix}/script/update/{script0.id}/status", + f"{config.asgi.prefix}/script/update/{script0.id}/status", content=update_status_model.model_dump_json(), ) update_check = check_and_parse_response(response, models.Script) @@ -649,26 +650,26 @@ async def check_scripts( ) response = await client.post( - f"{config.prefix}/actions/reset_script", + f"{config.asgi.prefix}/actions/reset_script", content=script_reset_status_model.model_dump_json(), ) reset_check = check_and_parse_response(response, models.Script) assert reset_check.status == StatusEnum.waiting response = await client.post( - f"{config.prefix}/script/action/-1/reset_script", + f"{config.asgi.prefix}/script/action/-1/reset_script", content=update_status_model.model_dump_json(), ) expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/script/get/{script0.id}/script_errors", + f"{config.asgi.prefix}/script/get/{script0.id}/script_errors", ) check_errors = check_and_parse_response(response, list[models.ScriptError]) assert len(check_errors) == 1 response = await client.get( - f"{config.prefix}/script/get/-1/script_errors", + f"{config.asgi.prefix}/script/get/-1/script_errors", ) expect_failed_response(response, 404) @@ -680,14 +681,14 @@ async def check_get_methods( entry_class: TypeAlias = models.ElementMixin, ) -> None: response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}", ) check_get = check_and_parse_response(response, entry_class) assert check_get.id == entry.id, "pulled row should be identical" assert check_get.level == entry.level, "pulled row db_id should be identical" # type: ignore - response = await client.get(f"{config.prefix}/{entry_class_name}/get/-1") + response = await client.get(f"{config.asgi.prefix}/{entry_class_name}/get/-1") expect_failed_response(response, 404) get_fullname_model = models.FullnameQuery( @@ -701,72 +702,72 @@ async def check_get_methods( bad_name_model = models.NameQuery(name="bad") response = await client.get( - f"{config.prefix}/{entry_class_name}/get_row_by_fullname", + f"{config.asgi.prefix}/{entry_class_name}/get_row_by_fullname", params=get_fullname_model.model_dump(), ) check_other = check_and_parse_response(response, entry_class) assert check_get.id == check_other.id response = await client.get( - f"{config.prefix}/{entry_class_name}/get_row_by_fullname", + f"{config.asgi.prefix}/{entry_class_name}/get_row_by_fullname", params=bad_fullname_model.model_dump(), ) expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get_row_by_name", + f"{config.asgi.prefix}/{entry_class_name}/get_row_by_name", params=get_name_model.model_dump(), ) check_other = check_and_parse_response(response, entry_class) assert check_get.id == check_other.id response = await client.get( - f"{config.prefix}/{entry_class_name}/get_row_by_name", + f"{config.asgi.prefix}/{entry_class_name}/get_row_by_name", params=bad_name_model.model_dump(), ) expect_failed_response(response, 404) - response = await client.get(f"{config.prefix}/{entry_class_name}/get/{entry.id}/spec_block") + response = await client.get(f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/spec_block") spec_block_check = check_and_parse_response(response, models.SpecBlock) assert spec_block_check.name - response = await client.get(f"{config.prefix}/{entry_class_name}/get/-1/spec_block") + response = await client.get(f"{config.asgi.prefix}/{entry_class_name}/get/-1/spec_block") expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/specification", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/specification", ) specification_check = check_and_parse_response(response, models.Specification) assert specification_check.name - response = await client.get(f"{config.prefix}/{entry_class_name}/get/-1/specification") + response = await client.get(f"{config.asgi.prefix}/{entry_class_name}/get/-1/specification") expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/tasks", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/tasks", ) check1 = check_and_parse_response(response, models.MergedTaskSetDict) assert len(check1.reports) == 0, "length of tasks should be 0" - response = await client.get(f"{config.prefix}/{entry_class_name}/get/-1/tasks") + response = await client.get(f"{config.asgi.prefix}/{entry_class_name}/get/-1/tasks") expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/wms_task_reports", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/wms_task_reports", ) check2 = check_and_parse_response(response, models.MergedWmsTaskReportDict) assert len(check2.reports) == 0, "length of reports should be 0" - response = await client.get(f"{config.prefix}/{entry_class_name}/get/-1/wms_task_reports") + response = await client.get(f"{config.asgi.prefix}/{entry_class_name}/get/-1/wms_task_reports") expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/products", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/products", ) check3 = check_and_parse_response(response, models.MergedProductSetDict) assert len(check3.reports) == 0, "length of products should be 0" - response = await client.get(f"{config.prefix}/{entry_class_name}/get/-1/products") + response = await client.get(f"{config.asgi.prefix}/{entry_class_name}/get/-1/products") expect_failed_response(response, 404) sleep_time_query = models.SleepTimeQuery( @@ -776,14 +777,14 @@ async def check_get_methods( ) response = await client.post( - f"{config.prefix}/{entry_class_name}/get/{entry.id}/sleep_time", + f"{config.asgi.prefix}/{entry_class_name}/get/{entry.id}/sleep_time", content=sleep_time_query.model_dump_json(), ) check_sleep_time = check_and_parse_response(response, int) assert check_sleep_time == 10 response = await client.post( - f"{config.prefix}/{entry_class_name}/get/-1/sleep_time", + f"{config.asgi.prefix}/{entry_class_name}/get/-1/sleep_time", content=sleep_time_query.model_dump_json(), ) @@ -801,30 +802,30 @@ async def check_queue( ) response = await client.post( - f"{config.prefix}/queue/create", + f"{config.asgi.prefix}/queue/create", content=fullname_model.model_dump_json(), ) queue = check_and_parse_response(response, models.Queue) response = await client.get( - f"{config.prefix}/queue/sleep_time/{queue.id}", + f"{config.asgi.prefix}/queue/sleep_time/{queue.id}", ) sleep_time = check_and_parse_response(response, int) assert sleep_time == 10 response = await client.get( - f"{config.prefix}/queue/sleep_time/-1", + f"{config.asgi.prefix}/queue/sleep_time/-1", ) expect_failed_response(response, 404) response = await client.get( - f"{config.prefix}/queue/process/{queue.id}", + f"{config.asgi.prefix}/queue/process/{queue.id}", ) changed = check_and_parse_response(response, bool) assert not changed response = await client.get( - f"{config.prefix}/queue/process/-1", + f"{config.asgi.prefix}/queue/process/-1", ) expect_failed_response(response, 404) diff --git a/tests/web_app/test_group_details_page.py b/tests/web_app/test_group_details_page.py index 40151beb2..61e5384d4 100644 --- a/tests/web_app/test_group_details_page.py +++ b/tests/web_app/test_group_details_page.py @@ -9,7 +9,6 @@ from lsst.cmservice import db from lsst.cmservice.common.enums import LevelEnum -from lsst.cmservice.config import config from lsst.cmservice.web_app.pages.group_details import get_group_by_id from tests.db.util_functions import create_tree, delete_all_productions @@ -20,7 +19,7 @@ async def test_get_group_details_by_id(engine: AsyncEngine) -> None: # generate a uuid to avoid collisions uuid_int = uuid.uuid1().int - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/web_app/test_job_details_page.py b/tests/web_app/test_job_details_page.py index 79c70b7bb..71313302a 100644 --- a/tests/web_app/test_job_details_page.py +++ b/tests/web_app/test_job_details_page.py @@ -9,7 +9,6 @@ from lsst.cmservice import db from lsst.cmservice.common.enums import LevelEnum -from lsst.cmservice.config import config from lsst.cmservice.web_app.pages.job_details import get_job_by_id from tests.db.util_functions import create_tree, delete_all_productions @@ -20,7 +19,7 @@ async def test_get_job_by_id(engine: AsyncEngine) -> None: # generate a uuid to avoid collisions uuid_int = uuid.uuid1().int - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples" diff --git a/tests/web_app/test_step_details_page.py b/tests/web_app/test_step_details_page.py index a2149a428..df79313b2 100644 --- a/tests/web_app/test_step_details_page.py +++ b/tests/web_app/test_step_details_page.py @@ -9,7 +9,6 @@ from lsst.cmservice import db from lsst.cmservice.common.enums import LevelEnum -from lsst.cmservice.config import config from lsst.cmservice.web_app.pages.step_details import get_step_details_by_id from tests.db.util_functions import create_tree, delete_all_productions @@ -21,7 +20,7 @@ async def test_get_step_details_by_id(engine: AsyncEngine) -> None: # generate a uuid to avoid collisions uuid_int = uuid.uuid1().int - logger = structlog.get_logger(config.logger_name) + logger = structlog.get_logger(__name__) async with engine.begin(): session = await create_async_session(engine, logger) os.environ["CM_CONFIGS"] = "examples"