From b90fad5926107383fcdf8e07f5f076ac49d2ad9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linn=C3=A9a=20L=C3=B6fdahl?= Date: Fri, 19 Dec 2025 09:34:58 +0100 Subject: [PATCH 1/2] Create analysis in Trailblazer first --- cg/cli/workflow/raw_data/raw_data_service.py | 2 +- tests/cli/workflow/fastq/test_fastq_base.py | 44 ++++++++++++-------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/cg/cli/workflow/raw_data/raw_data_service.py b/cg/cli/workflow/raw_data/raw_data_service.py index b04648b29f4..bb9f12b7cf3 100644 --- a/cg/cli/workflow/raw_data/raw_data_service.py +++ b/cg/cli/workflow/raw_data/raw_data_service.py @@ -16,8 +16,8 @@ def __init__(self, store: Store, trailblazer_api: TrailblazerAPI): def store_analysis(self, case_id: str) -> None: case: Case = self._get_case(case_id) - self._add_analysis_to_store(case) self._add_analysis_to_trailblazer(case) + self._add_analysis_to_store(case) def _get_case(self, case_id: str) -> Case: if case := self.store.get_case_by_internal_id(case_id): diff --git a/tests/cli/workflow/fastq/test_fastq_base.py b/tests/cli/workflow/fastq/test_fastq_base.py index 76e22d87c10..78a53d77bc9 100644 --- a/tests/cli/workflow/fastq/test_fastq_base.py +++ b/tests/cli/workflow/fastq/test_fastq_base.py @@ -1,24 +1,34 @@ +from unittest.mock import create_autospec + +from click.testing import CliRunner, Result +from pytest_mock import MockerFixture + +from cg.cli.workflow.raw_data import base from cg.cli.workflow.raw_data.base import store_raw_data_analysis -from cg.store.models import Analysis, Case +from cg.cli.workflow.raw_data.raw_data_service import RawDataAnalysisService +from cg.models.cg_config import CGConfig -def test_store_raw_data_analysis(another_case_id: str, cli_runner, raw_data_fastq_context, helpers): +def test_store_raw_data_analysis( + cli_runner: CliRunner, + mocker: MockerFixture, +): """Test for CLI command creating an analysis object for a fastq case""" # GIVEN a raw data fastq context - helpers.ensure_case(raw_data_fastq_context.status_db, case_id=another_case_id) - case_obj: Case = raw_data_fastq_context.status_db.get_case_by_internal_id(another_case_id) - assert not case_obj.analyses - - # WHEN a command is run to create an analysis for the case - cli_runner.invoke(store_raw_data_analysis, [another_case_id], obj=raw_data_fastq_context) - - # THEN the analysis is created - assert ( - len( - raw_data_fastq_context.status_db._get_query(table=Analysis) - .filter(Analysis.case_id == case_obj.id) - .all() - ) - > 0 + case_id = "fastq_raw_data_case" + context = create_autospec(CGConfig) + created_raw_data_analysis_service = create_autospec(RawDataAnalysisService) + + # GIVEN a raw data analaysis service can be instantiated + raw_data_analysis_service_class = mocker.patch.object( + base, "RawDataAnalysisService", autospec=True ) + raw_data_analysis_service_class.return_value = created_raw_data_analysis_service + + # WHEN a command is run to create and store an analysis for the case + result: Result = cli_runner.invoke(store_raw_data_analysis, [case_id], obj=context) + + # THEN the analysis is stored by the RawDataAnalysisService + assert not result.exception + created_raw_data_analysis_service.store_analysis.assert_called_once_with(case_id) From 61efa65e78a8e59ba80d639fcc53cc6252c7c405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linn=C3=A9a=20L=C3=B6fdahl?= Date: Fri, 19 Dec 2025 17:01:11 +0100 Subject: [PATCH 2/2] Tests for raw_data_analysis_service.store_analysis --- .../test_raw_data_analysis_service.py | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 tests/cli/workflow/raw_data/test_raw_data_analysis_service.py diff --git a/tests/cli/workflow/raw_data/test_raw_data_analysis_service.py b/tests/cli/workflow/raw_data/test_raw_data_analysis_service.py new file mode 100644 index 00000000000..e809ab86dcf --- /dev/null +++ b/tests/cli/workflow/raw_data/test_raw_data_analysis_service.py @@ -0,0 +1,95 @@ +from datetime import datetime +from unittest.mock import Mock, create_autospec + +import pytest + +from cg.apps.tb.api import TrailblazerAPI +from cg.cli.workflow.raw_data.raw_data_service import RawDataAnalysisService +from cg.constants.constants import Workflow +from cg.constants.priority import Priority, TrailblazerPriority +from cg.constants.tb import AnalysisType +from cg.store.models import Analysis, Case, Order +from cg.store.store import Store +from tests.typed_mock import TypedMock, create_typed_mock + + +@pytest.mark.freeze_time +def test_store_analysis(): + raw_data_case_id = "raw_data_case_id" + + case: Case = create_autospec( + Case, + id=1, + internal_id=raw_data_case_id, + latest_ticket="ticket_2", + latest_order=create_autospec(Order, id="123"), + priority=Priority.standard, + ) + + new_analysis = create_autospec(Analysis) + + store: TypedMock[Store] = create_typed_mock(Store) + store.as_type.get_case_by_internal_id = Mock(return_value=case) + store.as_type.add_analysis = Mock(return_value=new_analysis) + store.as_type.session = Mock() + + trailblazer_api = create_autospec(TrailblazerAPI) + + raw_data_analysis_service = RawDataAnalysisService( + store=store.as_type, trailblazer_api=trailblazer_api + ) + + raw_data_analysis_service.store_analysis(case_id=raw_data_case_id) + + store.as_mock.add_analysis.assert_called_once_with( + case_id=1, + completed_at=datetime.now(), + primary=True, + started_at=datetime.now(), + workflow=Workflow.RAW_DATA, + ) + store.as_mock.session.add.assert_called_once_with(new_analysis) + store.as_mock.session.commit.assert_called_once() + + trailblazer_api.add_pending_analysis.assert_called_once_with( + analysis_type=AnalysisType.OTHER, + case_id=raw_data_case_id, + config_path="", + order_id="123", + out_dir="", + priority=TrailblazerPriority.NORMAL, + ticket="ticket_2", + workflow=Workflow.RAW_DATA, + ) + + +def test_store_analysis_no_trailblazer_analysis_created(): + raw_data_case_id = "raw_data_case_id" + + case: Case = create_autospec( + Case, + id=1, + internal_id=raw_data_case_id, + latest_ticket="ticket_2", + latest_order=create_autospec(Order, id="123"), + priority=Priority.standard, + ) + + new_analysis = create_autospec(Analysis) + + store: TypedMock[Store] = create_typed_mock(Store) + store.as_type.get_case_by_internal_id = Mock(return_value=case) + store.as_type.add_analysis = Mock(return_value=new_analysis) + store.as_type.session = Mock() + + trailblazer_api = create_autospec(TrailblazerAPI) + trailblazer_api.add_pending_analysis = Mock(side_effect=Exception) + + raw_data_analysis_service = RawDataAnalysisService( + store=store.as_type, trailblazer_api=trailblazer_api + ) + with pytest.raises(Exception): + raw_data_analysis_service.store_analysis(case_id=raw_data_case_id) + + store.as_mock.add_analysis.assert_not_called() + store.as_mock.session.commit.assert_not_called()