From 58d73d9b24ad04ec46bf8cdd2849b81cedd110fb Mon Sep 17 00:00:00 2001 From: Arkadiusz Kwasigroch Date: Tue, 25 Aug 2026 16:55:04 +0200 Subject: [PATCH] refactor(backend): extract test configuration crud Continues the incremental split of the crud monolith. TestConfiguration moves to its own module; callers switch to direct submodule imports. Pure move -- no logic changes. --- .../src/rhesis/backend/app/crud/__init__.py | 67 --------------- .../backend/app/crud/test_configuration.py | 81 +++++++++++++++++++ .../backend/app/routers/test_configuration.py | 15 ++-- .../rhesis/backend/app/services/test_run.py | 3 +- .../rhesis/backend/app/services/test_set.py | 9 ++- .../rhesis/backend/jobs/execution/config.py | 4 +- .../rhesis/backend/jobs/execution/modes.py | 5 +- .../routes/test_execute_dispatch_task_id.py | 2 +- tests/backend/services/test_rescore.py | 4 +- 9 files changed, 104 insertions(+), 86 deletions(-) create mode 100644 apps/backend/src/rhesis/backend/app/crud/test_configuration.py diff --git a/apps/backend/src/rhesis/backend/app/crud/__init__.py b/apps/backend/src/rhesis/backend/app/crud/__init__.py index 528228a0f7..1f928b2363 100644 --- a/apps/backend/src/rhesis/backend/app/crud/__init__.py +++ b/apps/backend/src/rhesis/backend/app/crud/__init__.py @@ -415,73 +415,6 @@ def get_test_set_tests( return items, total_count -# TestConfiguration CRUD -def get_test_configuration( - db: Session, test_configuration_id: uuid.UUID, organization_id: str = None, user_id: str = None -) -> Optional[models.TestConfiguration]: - return get_item_detail( - db, - models.TestConfiguration, - test_configuration_id, - organization_id=organization_id, - user_id=user_id, - ) - - -def get_test_configurations( - db: Session, - skip: int = 0, - limit: int = 10, - sort_by: str = "created_at", - sort_order: str = "desc", - filter: str | None = None, - organization_id: str = None, - user_id: str = None, -) -> List[models.TestConfiguration]: - return ( - QueryBuilder(db, models.TestConfiguration) - .with_organization_filter(organization_id) - .with_visibility_filter(user_id) - .with_odata_filter(filter) - .with_sorting(sort_by, sort_order) - .with_pagination(skip, limit) - .all() - ) - - -def create_test_configuration( - db: Session, - test_configuration: schemas.TestConfigurationCreate, - organization_id: str = None, - user_id: str = None, -) -> models.TestConfiguration: - return create_item( - db, - models.TestConfiguration, - test_configuration, - organization_id=organization_id, - user_id=user_id, - ) - - -def update_test_configuration( - db: Session, - test_configuration_id: uuid.UUID, - test_configuration: schemas.TestConfigurationUpdate, - organization_id: str = None, - user_id: str = None, -) -> Optional[models.TestConfiguration]: - """Update test_configuration.""" - return update_item( - db, - models.TestConfiguration, - test_configuration_id, - test_configuration, - organization_id, - user_id, - ) - - def get_test( db: Session, test_id: uuid.UUID, organization_id: str = None, user_id: str = None ) -> Optional[models.Test]: diff --git a/apps/backend/src/rhesis/backend/app/crud/test_configuration.py b/apps/backend/src/rhesis/backend/app/crud/test_configuration.py new file mode 100644 index 0000000000..5fa4011a60 --- /dev/null +++ b/apps/backend/src/rhesis/backend/app/crud/test_configuration.py @@ -0,0 +1,81 @@ +"""CRUD operations for test configurations. + +Part of the incremental split of the ``crud`` monolith: ``crud/__init__.py`` still holds +the bulk of the functions, and per-entity modules like this one take over as the code +around them is touched -- see ``apps/backend/AGENTS.md``'s crud-layout rule. +""" + +import uuid +from typing import List, Optional + +from sqlalchemy.orm import Session + +from rhesis.backend.app import models, schemas +from rhesis.backend.app.utils.crud_utils import create_item, get_item_detail, update_item +from rhesis.backend.app.utils.query_utils import QueryBuilder + + +def get_test_configuration( + db: Session, test_configuration_id: uuid.UUID, organization_id: str = None, user_id: str = None +) -> Optional[models.TestConfiguration]: + return get_item_detail( + db, + models.TestConfiguration, + test_configuration_id, + organization_id=organization_id, + user_id=user_id, + ) + + +def get_test_configurations( + db: Session, + skip: int = 0, + limit: int = 10, + sort_by: str = "created_at", + sort_order: str = "desc", + filter: str | None = None, + organization_id: str = None, + user_id: str = None, +) -> List[models.TestConfiguration]: + return ( + QueryBuilder(db, models.TestConfiguration) + .with_organization_filter(organization_id) + .with_visibility_filter(user_id) + .with_odata_filter(filter) + .with_sorting(sort_by, sort_order) + .with_pagination(skip, limit) + .all() + ) + + +def create_test_configuration( + db: Session, + test_configuration: schemas.TestConfigurationCreate, + organization_id: str = None, + user_id: str = None, +) -> models.TestConfiguration: + return create_item( + db, + models.TestConfiguration, + test_configuration, + organization_id=organization_id, + user_id=user_id, + ) + + +def update_test_configuration( + db: Session, + test_configuration_id: uuid.UUID, + test_configuration: schemas.TestConfigurationUpdate, + organization_id: str = None, + user_id: str = None, +) -> Optional[models.TestConfiguration]: + """Update test_configuration.""" + return update_item( + db, + models.TestConfiguration, + test_configuration_id, + test_configuration, + organization_id, + user_id, + ) diff --git a/apps/backend/src/rhesis/backend/app/routers/test_configuration.py b/apps/backend/src/rhesis/backend/app/routers/test_configuration.py index 4118ac947e..73fceb2272 100644 --- a/apps/backend/src/rhesis/backend/app/routers/test_configuration.py +++ b/apps/backend/src/rhesis/backend/app/routers/test_configuration.py @@ -10,6 +10,7 @@ from rhesis.backend.app.auth.capabilities import Permission, capability from rhesis.backend.app.auth.quota_gates import require_quota from rhesis.backend.app.auth.user_utils import require_current_user_or_token +from rhesis.backend.app.crud import test_configuration as test_configuration_crud from rhesis.backend.app.dependencies import ( get_tenant_context, get_tenant_db_session, @@ -62,7 +63,7 @@ def create_test_configuration( if not test_configuration.organization_id: test_configuration.organization_id = current_user.organization_id - return crud.create_test_configuration( + return test_configuration_crud.create_test_configuration( db=db, test_configuration=test_configuration, organization_id=organization_id, @@ -90,7 +91,7 @@ def read_test_configurations( ): """Get all test configurations with their related objects""" organization_id, user_id = tenant_context - results = crud.get_test_configurations( + results = test_configuration_crud.get_test_configurations( db, skip=skip, limit=limit, @@ -115,7 +116,7 @@ def read_test_configuration( ): """Get a specific test configuration by ID with its related objects""" organization_id, user_id = tenant_context - db_test_configuration = crud.get_test_configuration( + db_test_configuration = test_configuration_crud.get_test_configuration( db, test_configuration_id=test_configuration_id, organization_id=organization_id, @@ -136,7 +137,7 @@ def update_test_configuration( ): """Update an existing test configuration.""" organization_id, user_id = tenant_context - db_test_configuration = crud.get_test_configuration( + db_test_configuration = test_configuration_crud.get_test_configuration( db, test_configuration_id=test_configuration_id, organization_id=organization_id, @@ -145,7 +146,7 @@ def update_test_configuration( if db_test_configuration is None: raise HTTPException(status_code=404, detail="Test configuration not found") - return crud.update_test_configuration( + return test_configuration_crud.update_test_configuration( db=db, test_configuration_id=test_configuration_id, test_configuration=test_configuration, @@ -163,7 +164,7 @@ def delete_test_configuration( ): """Delete a test configuration""" organization_id, user_id = tenant_context - db_test_configuration = crud.get_test_configuration( + db_test_configuration = test_configuration_crud.get_test_configuration( db, test_configuration_id=test_configuration_id, organization_id=organization_id, @@ -196,7 +197,7 @@ def execute_test_configuration_endpoint( try: organization_id, user_id = tenant_context # Verify the test configuration exists - db_test_configuration = crud.get_test_configuration( + db_test_configuration = test_configuration_crud.get_test_configuration( db, test_configuration_id=test_configuration_id, organization_id=organization_id, diff --git a/apps/backend/src/rhesis/backend/app/services/test_run.py b/apps/backend/src/rhesis/backend/app/services/test_run.py index 3653f80c9d..e71e0563a3 100644 --- a/apps/backend/src/rhesis/backend/app/services/test_run.py +++ b/apps/backend/src/rhesis/backend/app/services/test_run.py @@ -8,6 +8,7 @@ from rhesis.backend.app import crud, models, schemas from rhesis.backend.app.crud import prompt as prompt_crud +from rhesis.backend.app.crud import test_configuration as test_configuration_crud from rhesis.backend.app.crud import test_result as test_result_crud from rhesis.backend.app.crud.metric import get_requirement_metrics from rhesis.backend.app.crud.test_run import get_test_run, get_test_run_requirements @@ -239,7 +240,7 @@ def rescore_test_run( organization_id=current_user.organization_id, attributes=attributes, ) - db_new_config = crud.create_test_configuration( + db_new_config = test_configuration_crud.create_test_configuration( db=db, test_configuration=new_config, organization_id=org_id, diff --git a/apps/backend/src/rhesis/backend/app/services/test_set.py b/apps/backend/src/rhesis/backend/app/services/test_set.py index 19c76df9ef..ec4b224aed 100644 --- a/apps/backend/src/rhesis/backend/app/services/test_set.py +++ b/apps/backend/src/rhesis/backend/app/services/test_set.py @@ -977,7 +977,8 @@ def _create_test_configuration( Returns: Test configuration ID as string """ - from rhesis.backend.app import crud, schemas + from rhesis.backend.app import schemas + from rhesis.backend.app.crud import test_configuration as test_configuration_crud logger.debug( f"Creating test configuration for test_set_id={test_set_id}, " @@ -1031,7 +1032,7 @@ def _create_test_configuration( logger.debug(f"Test configuration schema created: {test_config}") # Create the test configuration - db_test_config = crud.create_test_configuration( + db_test_config = test_configuration_crud.create_test_configuration( db=db, test_configuration=test_config, organization_id=organization_id, user_id=user_id ) # Access the ID immediately while we're still in the same transaction context @@ -1053,7 +1054,7 @@ def _submit_test_configuration_for_execution( Returns: Tuple of (celery_result, test_run_id_str) """ - from rhesis.backend.app import crud + from rhesis.backend.app.crud import test_configuration as test_configuration_crud from rhesis.backend.jobs import launch_job from rhesis.backend.jobs.execution.run import create_test_run from rhesis.backend.jobs.test_configuration import execute_test_configuration @@ -1063,7 +1064,7 @@ def _submit_test_configuration_for_execution( ) # Look up the test configuration to create the test run - db_test_config = crud.get_test_configuration( + db_test_config = test_configuration_crud.get_test_configuration( db, test_configuration_id=uuid.UUID(test_config_id), organization_id=str(current_user.organization_id), diff --git a/apps/backend/src/rhesis/backend/jobs/execution/config.py b/apps/backend/src/rhesis/backend/jobs/execution/config.py index 5edd976bb3..d8ced6326e 100644 --- a/apps/backend/src/rhesis/backend/jobs/execution/config.py +++ b/apps/backend/src/rhesis/backend/jobs/execution/config.py @@ -4,7 +4,7 @@ from sqlalchemy.orm import Session -from rhesis.backend.app import crud +from rhesis.backend.app.crud import test_configuration as test_configuration_crud from rhesis.backend.app.models.test_configuration import TestConfiguration @@ -12,7 +12,7 @@ def get_test_configuration( session: Session, test_configuration_id: str, organization_id: str = None ) -> TestConfiguration: """Retrieve and validate test configuration.""" - test_config = crud.get_test_configuration( + test_config = test_configuration_crud.get_test_configuration( session, test_configuration_id=UUID(test_configuration_id), organization_id=organization_id ) diff --git a/apps/backend/src/rhesis/backend/jobs/execution/modes.py b/apps/backend/src/rhesis/backend/jobs/execution/modes.py index 5fda6817c0..0112ff43c3 100644 --- a/apps/backend/src/rhesis/backend/jobs/execution/modes.py +++ b/apps/backend/src/rhesis/backend/jobs/execution/modes.py @@ -10,6 +10,7 @@ from sqlalchemy.orm import Session from rhesis.backend.app import crud +from rhesis.backend.app.crud import test_configuration as test_configuration_crud from rhesis.backend.app.models.test import Test from rhesis.backend.app.models.test_configuration import TestConfiguration from rhesis.backend.app.utils.uuid_utils import safe_uuid_convert @@ -73,7 +74,7 @@ def set_execution_mode( logger.error(f"Invalid test configuration ID: {test_config_id}") return False - test_config = crud.get_test_configuration( + test_config = test_configuration_crud.get_test_configuration( db, test_config_uuid, organization_id=organization_id, user_id=user_id ) if not test_config: @@ -86,7 +87,7 @@ def set_execution_mode( # Update the test configuration update_data = {"attributes": current_attributes} - crud.update_test_configuration( + test_configuration_crud.update_test_configuration( db, test_config.id, crud.schemas.TestConfigurationUpdate(**update_data), diff --git a/tests/backend/routes/test_execute_dispatch_task_id.py b/tests/backend/routes/test_execute_dispatch_task_id.py index 6bc21e2fd5..77cd6fb40b 100644 --- a/tests/backend/routes/test_execute_dispatch_task_id.py +++ b/tests/backend/routes/test_execute_dispatch_task_id.py @@ -42,7 +42,7 @@ def fake_create_test_run(db, config, task_info=None, current_user_id=None): with ( patch( - "rhesis.backend.app.routers.test_configuration.crud.get_test_configuration", + "rhesis.backend.app.routers.test_configuration.test_configuration_crud.get_test_configuration", return_value=MagicMock(), ), patch( diff --git a/tests/backend/services/test_rescore.py b/tests/backend/services/test_rescore.py index 5c22cc65bc..d1a5a8aec0 100644 --- a/tests/backend/services/test_rescore.py +++ b/tests/backend/services/test_rescore.py @@ -159,7 +159,7 @@ def test_creates_new_config_and_submits_task(self): return_value=mock_ref_run, ), patch( - "rhesis.backend.app.services.test_run.crud.create_test_configuration", + "rhesis.backend.app.services.test_run.test_configuration_crud.create_test_configuration", return_value=mock_new_config, ) as mock_create_config, # launch_job is imported locally inside rescore_test_run @@ -229,7 +229,7 @@ def test_includes_metrics_override(self): return_value=mock_ref_run, ), patch( - "rhesis.backend.app.services.test_run.crud.create_test_configuration", + "rhesis.backend.app.services.test_run.test_configuration_crud.create_test_configuration", return_value=mock_new_config, ) as mock_create_config, # launch_job is imported locally inside rescore_test_run