Skip to content

chore: Bump app version in tests to 1.1.0 in prod#464

Open
blanca-pablos wants to merge 1 commit intomainfrom
chore/he-tme-bump-to-1.1.0-prod
Open

chore: Bump app version in tests to 1.1.0 in prod#464
blanca-pablos wants to merge 1 commit intomainfrom
chore/he-tme-bump-to-1.1.0-prod

Conversation

@blanca-pablos
Copy link
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings March 5, 2026 16:16
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the HETA_APPLICATION_VERSION constant used in integration/end-to-end tests against the production environment, bumping it from 1.0.0 to 1.1.0 to reflect that version 1.1.0 of the he-tme application is now available in production. The staging environment constant was already set to 1.1.0, so this change brings production in sync.

Changes:

  • Bumps HETA_APPLICATION_VERSION in the production branch of the environment match block from "1.0.0" to "1.1.0"

@codecov
Copy link

codecov bot commented Mar 5, 2026

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
712 2 710 15
View the top 2 failed test(s) by shortest run time
tests.aignostics.application.gui_test::test_gui_run_download
Stack Traces | 54.7s run time
user = <nicegui.testing.user.User object at 0x7f2a5ba60180>
runner = <typer.testing.CliRunner object at 0x7f2a0b053e10>
tmp_path = PosixPath('.../pytest-of-runner/pytest-21/test_gui_run_download1')
silent_logging = None
record_property = <function record_property.<locals>.append_property at 0x7f2a456f68d0>

    @pytest.mark.e2e
    @pytest.mark.long_running
    @pytest.mark.flaky(retries=1, delay=5)
    @pytest.mark.timeout(timeout=60 * 10)
    @pytest.mark.sequential  # Helps on Linux with image analysis step otherwise timing out
    async def test_gui_run_download(  # noqa: PLR0915
        user: User, runner: CliRunner, tmp_path: Path, silent_logging: None, record_property
    ) -> None:
        """Test that the user can download a run result via the GUI."""
        record_property("tested-item-id", "SPEC-APPLICATION-SERVICE, SPEC-GUI-SERVICE")
        with patch(
            "aignostics.application._gui._page_application_run_describe.get_user_data_directory",
            return_value=tmp_path,
        ):
            # Find run
            runs = Service().application_runs(
                application_id=HETA_APPLICATION_ID,
                application_version=HETA_APPLICATION_VERSION,
                external_id=SPOT_0_GS_URL,
                tags=["scheduled"],
                has_output=True,
                limit=1,
            )
            if not runs:
                message = f"No matching runs found for application {HETA_APPLICATION_ID} ({HETA_APPLICATION_VERSION}). "
                message += "This test requires the scheduled test test_application_runs_heta_version passing first."
                pytest.skip(message)
    
            run_id = runs[0].run_id
    
            # Explore run
            run = Service().application_run(run_id).details()
            print(
                f"Found existing run: {run.run_id}\n"
                f"application: {run.application_id} ({run.version_number})\n"
                f"status: {run.state}, output: {run.output}\n"
                f"submitted at: {run.submitted_at}, terminated at: {run.terminated_at}\n"
                f"statistics: {run.statistics!r}\n",
                f"custom_metadata: {run.custom_metadata!r}\n",
            )
            # Step 1: Go to latest completed run
            await user.open(f"/application/run/{run.run_id}")
            await user.should_see(f"Run {run.run_id}", retries=100)
            await user.should_see(
                f"Run of {run.application_id} ({run.version_number})",
                retries=100,
            )
    
            # Step 2: Open Result Download dialog
            await user.should_see(marker="BUTTON_DOWNLOAD_RUN", retries=100)
            user.find(marker="BUTTON_DOWNLOAD_RUN").click()
    
            # Step 3: Check download button is initially disabled, then select Data folder
            download_run_button: ui.button = user.find(marker="DIALOG_BUTTON_DOWNLOAD_RUN").elements.pop()
            assert not download_run_button.enabled, "Download button should be disabled before selecting target"
            await user.should_see(marker="BUTTON_DOWNLOAD_DESTINATION_DATA", retries=100)
            user.find(marker="BUTTON_DOWNLOAD_DESTINATION_DATA").click()
            await assert_notified(user, "Using Launchpad results directory")
    
            # Step 4: Trigger Download - wait for button to be enabled
            download_run_button = user.find(marker="DIALOG_BUTTON_DOWNLOAD_RUN").elements.pop()
            assert download_run_button.enabled, "Download button should be enabled after selecting target"
            user.find(marker="DIALOG_BUTTON_DOWNLOAD_RUN").click()
            await assert_notified(user, "Downloading ...")
    
            # Check: Download completed
            await assert_notified(user, "Download completed.", 60 * 4)
            print_directory_structure(tmp_path, "downloaded_run")
    
            # Check for directory layout as expected
            run_dir = tmp_path / run.run_id
            assert run_dir.is_dir(), f"Expected run directory {run_dir} not found"
    
            subdirs = [d for d in run_dir.iterdir() if d.is_dir()]
            assert len(subdirs) == 2, f"Expected two subdirectories in {run_dir}, but found {len(subdirs)}"
    
            input_dir = run_dir / "input"
            assert input_dir.is_dir(), f"Expected input directory {input_dir} not found"
    
            results_dir = run_dir / SPOT_0_FILENAME.replace(".tiff", "")
            assert results_dir.is_dir(), f"Expected run results directory {results_dir} not found"
    
            # Check for input file having been downloaded
            input_file = input_dir / SPOT_0_FILENAME
            assert input_file.exists(), f"Expected input file {input_file} not found"
            assert input_file.stat().st_size == SPOT_0_FILESIZE, (
                f"Expected input file size {SPOT_0_FILESIZE}, but got {input_file.stat().st_size}"
            )
    
            # Check for files in the results directory
            files_in_results_dir = list(results_dir.glob("*"))
            assert len(files_in_results_dir) == 9, (
                f"Expected 9 files in {results_dir}, but found {len(files_in_results_dir)}: "
                f"{[f.name for f in files_in_results_dir]}"
            )
    
            print(f"Found files in {results_dir}:")
            for filename, expected_size, tolerance_percent in SPOT_0_EXPECTED_RESULT_FILES:
                file_path = results_dir / filename
                if file_path.exists():
                    actual_size = file_path.stat().st_size
                    print(f"  {filename}: {actual_size} bytes (expected: {expected_size} ±{tolerance_percent}%)")
                else:
                    print(f"  {filename}: NOT FOUND")
            for filename, expected_size, tolerance_percent in SPOT_0_EXPECTED_RESULT_FILES:
                file_path = results_dir / filename
                assert file_path.exists(), f"Expected file {filename} not found"
                actual_size = file_path.stat().st_size
                min_size = expected_size * (100 - tolerance_percent) // 100
                max_size = expected_size * (100 + tolerance_percent) // 100
>               assert min_size <= actual_size <= max_size, (
                    f"File size for {filename} ({actual_size} bytes) is outside allowed range "
                    f"({min_size} to {max_size} bytes, ±{tolerance_percent}% of {expected_size})"
                )
E               AssertionError: File size for tissue_qc_geojson_polygons.json (259955 bytes) is outside allowed range (144601 to 176734 bytes, ±10% of 160668)
E               assert 259955 <= 176734

.../aignostics/application/gui_test.py:455: AssertionError
tests.aignostics.qupath.gui_test::test_gui_run_qupath_install_to_inspect
Stack Traces | 66.5s run time
user = <nicegui.testing.user.User object at 0x7f2a441678a0>
runner = <typer.testing.CliRunner object at 0x7f2a1919faf0>
tmp_path = PosixPath('.../pytest-of-runner/pytest-21/test_gui_run_qupath_install_to0')
silent_logging = None, qupath_teardown = None, qupath_save_restore = None
record_property = <function record_property.<locals>.append_property at 0x7f2a19129850>

    @pytest.mark.e2e
    @pytest.mark.long_running
    @pytest.mark.skipif(
        (platform.system() == "Linux" and platform.machine() in {"aarch64", "arm64"}),
        reason="QuPath is not supported on ARM64 Linux",
    )
    @pytest.mark.timeout(timeout=60 * 15)
    @pytest.mark.sequential
    async def test_gui_run_qupath_install_to_inspect(  # noqa: C901, PLR0912, PLR0913, PLR0914, PLR0915, PLR0917
        user: User,
        runner: CliRunner,
        tmp_path: Path,
        silent_logging: None,
        qupath_teardown: None,
        qupath_save_restore: None,
        record_property,
    ) -> None:
        """Test installing QuPath, downloading run results, creating QuPath project from it, and inspecting results."""
        record_property("tested-item-id", "TC-QUPATH-01, SPEC-GUI-SERVICE")
    
        # Find run
        runs = Service().application_runs(
            application_id=HETA_APPLICATION_ID,
            application_version=HETA_APPLICATION_VERSION,
            external_id=SPOT_0_GS_URL,
            tags=["scheduled"],
            has_output=True,
            limit=1,
        )
        if not runs:
            message = f"No matching runs found for application {HETA_APPLICATION_ID} ({HETA_APPLICATION_VERSION}). "
            message += "This test requires the scheduled test test_application_runs_heta_version passing first."
            pytest.skip(message)
    
        run_id = runs[0].run_id
    
        # Explore run
        run = Service().application_run(run_id).details()
        print(
            f"Found existing run: {run.run_id}\n"
            f"application: {run.application_id} ({run.version_number})\n"
            f"status: {run.state}, output: {run.output}\n"
            f"submitted at: {run.submitted_at}, terminated at: {run.terminated_at}\n"
            f"statistics: {run.statistics!r}\n",
            f"custom_metadata: {run.custom_metadata!r}\n",
        )
    
        # Explore results
        results = list(Service().application_run(run_id).results())
        assert results, f"No results found for run {run_id}"
        for item in results:
            print(
                f"Found item: {item.item_id}, status: {item.state}, output: {item.output}, "
                f"external_id: {item.external_id}\n"
                f"custom_metadata: {item.custom_metadata!r}\n",
            )
    
        with patch(
            "aignostics.application._gui._page_application_run_describe.get_user_data_directory", return_value=tmp_path
        ):
            # Step 1: (Re)Install QuPath
            result = runner.invoke(cli, ["qupath", "install"])
            output = normalize_output(result.output, strip_ansi=True)
            assert f"QuPath v{QUPATH_VERSION} installed successfully" in output, (
                f"Expected 'QuPath v{QUPATH_VERSION} installed successfully' in output.\nOutput: {output}"
            )
            assert result.exit_code == 0
    
            # Step 2: Go to latest completed run via GUI
            await user.open(f"/application/run/{run.run_id}")
            await user.should_see(f"Run {run.run_id}")
            await user.should_see(f"Run of {HETA_APPLICATION_ID} ({HETA_APPLICATION_VERSION})")
    
            # Step 3: Open Result Download dialog
            await user.should_see(marker="BUTTON_OPEN_QUPATH", retries=100)
            user.find(marker="BUTTON_OPEN_QUPATH").click()
    
            # Step 4: Select Data destination
            await user.should_see(marker="BUTTON_DOWNLOAD_DESTINATION_DATA")
            download_destination_data_button: ui.button = user.find(
                marker="BUTTON_DOWNLOAD_DESTINATION_DATA"
            ).elements.pop()
            assert download_destination_data_button.enabled, "Download destination button should be enabled"
            user.find(marker="BUTTON_DOWNLOAD_DESTINATION_DATA").click()
            await assert_notified(user, "Using Launchpad results directory", 30)
    
            # Step 5: Trigger Download
            await user.should_see(marker="DIALOG_BUTTON_DOWNLOAD_RUN")
            download_run_button: ui.button = user.find(marker="DIALOG_BUTTON_DOWNLOAD_RUN").elements.pop()
            assert download_run_button.enabled, "Download button should be enabled before downloading"
            user.find(marker="DIALOG_BUTTON_DOWNLOAD_RUN").click()
            await assert_notified(user, "Downloading ...", 30)
    
            # Step 6: Check download completes, QuPath project created, and QuPath launched
            await assert_notified(user, "Download and QuPath project creation completed.", 60 * 5)
            print_directory_structure(tmp_path, "execute")
    
            # Check for directory layout as expected
            run_dir = tmp_path / run.run_id
            assert run_dir.is_dir(), f"Expected run directory {run_dir} not found"
    
            subdirs = [d for d in run_dir.iterdir() if d.is_dir()]
            assert len(subdirs) == 3, f"Expected three subdirectories in {run_dir}, but found {len(subdirs)}"
    
            input_dir = run_dir / "input"
            assert input_dir.is_dir(), f"Expected input directory {input_dir} not found"
    
            results_dir = run_dir / SPOT_0_FILENAME.replace(".tiff", "")
            assert results_dir.is_dir(), f"Expected run results directory {results_dir} not found"
    
            qupath_dir = run_dir / "qupath"
            assert qupath_dir.is_dir(), f"Expected QuPath directory {qupath_dir} not found"
    
            # Check for input file having been downloaded
            input_file = input_dir / SPOT_0_FILENAME
            assert input_file.exists(), f"Expected input file {input_file} not found"
            assert input_file.stat().st_size == SPOT_0_FILESIZE, (
                f"Expected input file size {SPOT_0_FILESIZE}, but got {input_file.stat().st_size}"
            )
    
            # Check for files in the results directory
            files_in_results_dir = list(results_dir.glob("*"))
            assert len(files_in_results_dir) == 9, (
                f"Expected 9 files in {results_dir}, but found {len(files_in_results_dir)}: "
                f"{[f.name for f in files_in_results_dir]}"
            )
    
            print(f"Found files in {results_dir}:")
            for filename, expected_size, tolerance_percent in SPOT_0_EXPECTED_RESULT_FILES:
                file_path = results_dir / filename
                if file_path.exists():
                    actual_size = file_path.stat().st_size
                    print(f"  {filename}: {actual_size} bytes (expected: {expected_size} ±{tolerance_percent}%)")
                else:
                    print(f"  {filename}: NOT FOUND")
            for filename, expected_size, tolerance_percent in SPOT_0_EXPECTED_RESULT_FILES:
                file_path = results_dir / filename
                assert file_path.exists(), f"Expected file {filename} not found"
                actual_size = file_path.stat().st_size
                min_size = expected_size * (100 - tolerance_percent) // 100
                max_size = expected_size * (100 + tolerance_percent) // 100
>               assert min_size <= actual_size <= max_size, (
                    f"File size for {filename} ({actual_size} bytes) is outside allowed range "
                    f"({min_size} to {max_size} bytes, ±{tolerance_percent}% of {expected_size})"
                )
E               AssertionError: File size for tissue_qc_geojson_polygons.json (259955 bytes) is outside allowed range (144601 to 176734 bytes, ±10% of 160668)
E               assert 259955 <= 176734

.../aignostics/qupath/gui_test.py:279: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 5, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants