From df14125af02c843a867d0e3e81f8dcee418312e4 Mon Sep 17 00:00:00 2001 From: Harel Meir Date: Mon, 25 May 2026 11:28:44 +0300 Subject: [PATCH 1/6] Support multi-arch dedicated tests Currently, only one cpu arch can be passed without failing. for multiarch tests, we need to iterate over cluster archs. Signed-off-by: Harel Meir --- conftest.py | 2 ++ tests/conftest.py | 11 ++++++----- utilities/pytest_utils.py | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/conftest.py b/conftest.py index 0792568486..c65e0aeb03 100644 --- a/conftest.py +++ b/conftest.py @@ -56,6 +56,7 @@ deploy_run_in_progress_config_map, deploy_run_in_progress_namespace, filter_hpp_tests, + filter_multiarch_tests, get_artifactory_server_url, get_base_matrix_name, get_cnv_version_explorer_url, @@ -643,6 +644,7 @@ def pytest_collection_modifyitems(session, config, items): config.hook.pytest_deselected(items=discard) items[:] = filter_deprecated_api_tests(items=items, config=config) items[:] = filter_sno_only_tests(items=items, config=config) + items[:] = filter_multiarch_tests(items=items, config=config) items[:] = filter_hpp_tests(items=items, config=config) items[:] = mark_nmstate_dependent_tests(items=items) diff --git a/tests/conftest.py b/tests/conftest.py index 233fd03adb..f91053db9c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -474,13 +474,12 @@ def nodes(admin_client): @pytest.fixture(scope="session") -def schedulable_nodes(nodes): +def schedulable_nodes(nodes, nodes_cpu_architecture): """Get nodes marked as schedulable by kubevirt. For multi-arch testing - filter nodes by the architecture being tested. """ schedulable_label = "kubevirt.io/schedulable" - cpu_arch = py_config.get("cpu_arch") schedulable = [ node for node in nodes @@ -489,10 +488,12 @@ def schedulable_nodes(nodes): and not node.instance.spec.unschedulable and not kubernetes_taint_exists(node) and node.kubelet_ready - and (not cpu_arch or node.labels.get(KUBERNETES_ARCH_LABEL) == cpu_arch) + and (not nodes_cpu_architecture or node.labels.get(KUBERNETES_ARCH_LABEL) == nodes_cpu_architecture) ] - LOGGER.info(f"Schedulable nodes: {[node.name for node in schedulable]}, node architecture: {cpu_arch or 'all'}") + LOGGER.info( + f"Schedulable nodes: {[node.name for node in schedulable]}, node architecture: {nodes_cpu_architecture or 'all'}" + ) yield schedulable @@ -1513,7 +1514,7 @@ def cluster_info( f"\tOCS version: {ocs_current_version}\n" f"\tCNI type: {get_cluster_cni_type(admin_client=admin_client)}\n" f"\tWorkers type: {workers_type}\n" - f"\tCluster CPU Architecture: {py_config['cluster_arch']}\n" + f"\tCluster CPU Architecture: {nodes_cpu_architecture or ', '.join(py_config['cluster_arch'])}\n" f"\tIPv4 cluster: {ipv4_supported_cluster()}\n" f"\tIPv6 cluster: {ipv6_supported_cluster()}\n" f"\tVirtctl version: \n\t{virtctl_client_version}\n\t{virtctl_server_version}\n" diff --git a/utilities/pytest_utils.py b/utilities/pytest_utils.py index cd958fac6d..5933ad191c 100644 --- a/utilities/pytest_utils.py +++ b/utilities/pytest_utils.py @@ -649,6 +649,26 @@ def update_cpu_arch_related_config(cpu_arch_option: str) -> None: generate_instance_type_matrix_dicts(os_dict=py_config) +def remove_tests_from_list(items: list[pytest.Item], filter_str: str) -> tuple[list[pytest.Item], list[pytest.Item]]: + discard_tests: list[pytest.Item] = [] + items_to_return: list[pytest.Item] = [] + for item in items: + if filter_str in item.keywords: + discard_tests.append(item) + else: + items_to_return.append(item) + return discard_tests, items_to_return + + +def filter_multiarch_tests(items: list[pytest.Item], config: pytest.Config) -> list[pytest.Item]: + if py_config.get("cluster_type") == MULTIARCH: + return items + discard_tests, items_to_return = remove_tests_from_list(items=items, filter_str="multiarch") + if discard_tests: + config.hook.pytest_deselected(items=discard_tests) + return items_to_return + + def assert_incremental_classes_fully_collected(items: list[pytest.Item]) -> None: """Verify that all tests defined in incremental classes were collected. From c590c3a43764db92623a451818481a6b6a329b06 Mon Sep 17 00:00:00 2001 From: Harel Meir Date: Wed, 3 Jun 2026 14:07:28 +0300 Subject: [PATCH 2/6] Fix collection for multiarch tests Collection fails because of re-import. Transitioning to get method Signed-off-by: Harel Meir --- tests/chaos/oadp/test_oadp.py | 4 ++-- .../multiarch/test_multiarch_golden_images_support.py | 4 +++- tests/storage/cdi_upload/test_upload.py | 5 +++-- tests/storage/cdi_upload/test_upload_virtctl.py | 5 +++-- tests/storage/golden_image/test_golden_image.py | 4 ++-- .../test_high_performance_templates.py | 4 ++-- utilities/pytest_utils.py | 11 ----------- 7 files changed, 15 insertions(+), 22 deletions(-) diff --git a/tests/chaos/oadp/test_oadp.py b/tests/chaos/oadp/test_oadp.py index d198c71e43..705287712e 100644 --- a/tests/chaos/oadp/test_oadp.py +++ b/tests/chaos/oadp/test_oadp.py @@ -16,7 +16,7 @@ pytest.param( { "vm_name": "vm-node-reboot-12011", - "rhel_image": RHEL_LATEST["image_name"], + "rhel_image": RHEL_LATEST.get("image_name"), }, marks=pytest.mark.polarion("CNV-12011"), ), @@ -49,7 +49,7 @@ def test_reboot_vm_node_during_backup( pytest.param( { "vm_name": "vm-node-drain-12020", - "rhel_image": RHEL_LATEST["image_name"], + "rhel_image": RHEL_LATEST.get("image_name"), }, marks=pytest.mark.polarion("CNV-12020"), ), diff --git a/tests/install_upgrade_operators/hco_enablement_golden_image_updates/multiarch/test_multiarch_golden_images_support.py b/tests/install_upgrade_operators/hco_enablement_golden_image_updates/multiarch/test_multiarch_golden_images_support.py index a57008b2e7..ed97455659 100644 --- a/tests/install_upgrade_operators/hco_enablement_golden_image_updates/multiarch/test_multiarch_golden_images_support.py +++ b/tests/install_upgrade_operators/hco_enablement_golden_image_updates/multiarch/test_multiarch_golden_images_support.py @@ -16,7 +16,7 @@ import pytest -__test__ = False +pytestmark = [pytest.mark.multiarch] class TestDisabledMultiarchGoldenImagesSupport: @@ -29,6 +29,8 @@ class TestDisabledMultiarchGoldenImagesSupport: - "enableMultiArchBootImageImport" feature gate disabled in HCO CR """ + __test__ = False + @pytest.mark.polarion("CNV-15977") def test_only_architecture_agnostic_golden_image_resources_exist(self): """ diff --git a/tests/storage/cdi_upload/test_upload.py b/tests/storage/cdi_upload/test_upload.py index be7d29b1a2..1d4f45092d 100644 --- a/tests/storage/cdi_upload/test_upload.py +++ b/tests/storage/cdi_upload/test_upload.py @@ -18,6 +18,7 @@ import tests.storage.utils as storage_utils import utilities.storage +from tests.os_params import RHEL_LATEST from utilities.constants import Images from utilities.constants.components import CDI_UPLOADPROXY from utilities.constants.timeouts import TIMEOUT_1MIN, TIMEOUT_3MIN, TIMEOUT_5MIN @@ -322,8 +323,8 @@ def test_successful_concurrent_uploads( [ pytest.param( { - "image_path": py_config["latest_rhel_os_dict"]["image_path"], - "image_file": py_config["latest_rhel_os_dict"]["image_name"], + "image_path": RHEL_LATEST.get("image_path"), + "image_file": RHEL_LATEST.get("image_name"), }, { "dv_name": "cnv-4511", diff --git a/tests/storage/cdi_upload/test_upload_virtctl.py b/tests/storage/cdi_upload/test_upload_virtctl.py index 11ac2ee5f4..c521b0c238 100644 --- a/tests/storage/cdi_upload/test_upload_virtctl.py +++ b/tests/storage/cdi_upload/test_upload_virtctl.py @@ -13,6 +13,7 @@ from pytest_testconfig import config as py_config from libs.net.cluster import is_ipv6_single_stack_cluster +from tests.os_params import RHEL_LATEST from tests.storage.cdi_upload.utils import get_storage_profile_minimum_supported_pvc_size from tests.storage.utils import assert_use_populator, create_windows_vm_validate_guest_agent_info from utilities.constants import Images @@ -495,8 +496,8 @@ def test_successful_vm_from_uploaded_dv_windows( [ pytest.param( { - "image_path": py_config["latest_rhel_os_dict"]["image_path"], - "image_file": py_config["latest_rhel_os_dict"]["image_name"], + "image_path": RHEL_LATEST.get("image_path"), + "image_file": RHEL_LATEST.get("image_name"), }, marks=(pytest.mark.polarion("CNV-4512")), ), diff --git a/tests/storage/golden_image/test_golden_image.py b/tests/storage/golden_image/test_golden_image.py index 2e16a46328..69fba3fb50 100644 --- a/tests/storage/golden_image/test_golden_image.py +++ b/tests/storage/golden_image/test_golden_image.py @@ -15,8 +15,8 @@ LOGGER = logging.getLogger(__name__) -LATEST_RHEL_IMAGE = RHEL_LATEST["image_path"] -RHEL_IMAGE_SIZE = RHEL_LATEST["dv_size"] +LATEST_RHEL_IMAGE = RHEL_LATEST.get("image_path") +RHEL_IMAGE_SIZE = RHEL_LATEST.get("dv_size") DV_PARAM = { diff --git a/tests/virt/node/high_performance_vm/test_high_performance_templates.py b/tests/virt/node/high_performance_vm/test_high_performance_templates.py index b69e154cee..a3affe929a 100644 --- a/tests/virt/node/high_performance_vm/test_high_performance_templates.py +++ b/tests/virt/node/high_performance_vm/test_high_performance_templates.py @@ -96,7 +96,7 @@ def increased_high_performance_vm_core_count_by_one(high_performance_vm): "os": RHEL_LATEST_OS, "workload": Template.Workload.HIGHPERFORMANCE, "flavor": Template.Flavor.SMALL, - "architecture": py_config["cpu_arch"], + "architecture": py_config.get("cpu_arch"), }, }, ], @@ -151,7 +151,7 @@ def test_rhel_change_cpu_core_count( "os": "win2k19", "workload": Template.Workload.HIGHPERFORMANCE, "flavor": Template.Flavor.MEDIUM, - "architecture": py_config["cpu_arch"], + "architecture": py_config.get("cpu_arch"), }, }, ], diff --git a/utilities/pytest_utils.py b/utilities/pytest_utils.py index 5933ad191c..48bfd7a00a 100644 --- a/utilities/pytest_utils.py +++ b/utilities/pytest_utils.py @@ -649,17 +649,6 @@ def update_cpu_arch_related_config(cpu_arch_option: str) -> None: generate_instance_type_matrix_dicts(os_dict=py_config) -def remove_tests_from_list(items: list[pytest.Item], filter_str: str) -> tuple[list[pytest.Item], list[pytest.Item]]: - discard_tests: list[pytest.Item] = [] - items_to_return: list[pytest.Item] = [] - for item in items: - if filter_str in item.keywords: - discard_tests.append(item) - else: - items_to_return.append(item) - return discard_tests, items_to_return - - def filter_multiarch_tests(items: list[pytest.Item], config: pytest.Config) -> list[pytest.Item]: if py_config.get("cluster_type") == MULTIARCH: return items From 15d2a8b5f7ff3d7d1b7a14ced346b67294840999 Mon Sep 17 00:00:00 2001 From: Harel Meir Date: Wed, 24 Jun 2026 08:54:05 +0300 Subject: [PATCH 3/6] docs: update MULTIARCH.md with full heterogeneous cluster guide Signed-off-by: Harel Meir --- docs/MULTIARCH.md | 90 ++++++++++++++++++++++++++++++++++++--- utilities/pytest_utils.py | 13 ++++++ 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/docs/MULTIARCH.md b/docs/MULTIARCH.md index 06bc1f5d33..bf034950ec 100644 --- a/docs/MULTIARCH.md +++ b/docs/MULTIARCH.md @@ -1,13 +1,93 @@ # Multi-Architecture (Heterogeneous) Clusters -Currently supported architectures for multi-arch runs: `amd64` and `arm64`. +A heterogeneous cluster has worker nodes of more than one CPU architecture — for example, amd64 and arm64 workers coexisting on the same cluster. The test framework detects this automatically. -On clusters where nodes have different CPU architectures, you must pass `--cpu-arch` to select the architecture for the run. Use a single value (e.g. `--cpu-arch=amd64`) or, for tests marked with `multiarch`, a comma-separated list (e.g. `--cpu-arch=amd64,arm64`). Use the config file `tests/global_config_multiarch.py` and the `multiarch` marker for tests that run across multiple architectures. Do not pass `--cpu-arch` on homogeneous clusters. +**Supported architectures:** `amd64`, `arm64` + +## Overview + +The `--cpu-arch` option selects which architecture(s) to target. Behavior depends on cluster type and the value passed: + +| Test suite | Cluster | `--cpu-arch` | What runs | +| ---------- | ------- | ------------ | --------- | +| **Standard** | Homogeneous (single arch) | Omit — auto-detected from node labels | Standard regression tests | +| **Multiarch regression** | Heterogeneous (multiarch) | Single value — e.g. `amd64` or `arm64` | Full suite, scoped to nodes of that arch | +| **Multiarch-dedicated** | Heterogeneous (multiarch) | Comma-separated — e.g. `amd64,arm64` | Only tests marked with `multiarch` | + +**On a heterogeneous cluster:** + +- `--cpu-arch` is **required**. Omitting it raises `UnsupportedCPUArchitectureError`. +- Pass `--tc-file=tests/global_config.py` for regression runs (preferred — it auto-imports the multiarch config). `tests/global_config_multiarch.py` also works. +- For multiarch-dedicated tests, `--tc-file=tests/global_config_multiarch.py` is **required**. + +**On a homogeneous cluster:** + +- Run tests normally and do **not** pass `--cpu-arch`. Passing it raises `UnsupportedCPUArchitectureError`. + +## Multiarch regression + +Run the existing test suite against one architecture's nodes at a time. + +```bash +# amd64 regression +uv run pytest --tc-file=tests/global_config.py --cpu-arch=amd64 ... + +# arm64 regression +uv run pytest --tc-file=tests/global_config.py --cpu-arch=arm64 ... +``` + +## Multiarch-dedicated tests + +Run tests that exercise behavior requiring multiple architectures simultaneously (e.g., golden image import across both archs, cross-arch scheduling). ```bash -uv run pytest --tc-file=tests/global_config_multiarch.py --cpu-arch=amd64 ... +uv run pytest --tc-file=tests/global_config_multiarch.py --cpu-arch=amd64,arm64 \ + -m "iuo and multiarch" ... ``` -## Limitations +### Run requirements + +- The cluster must be heterogeneous. +- `--cpu-arch` must list multiple architectures (e.g. `amd64,arm64`) +- Every collected test must have the `multiarch` marker — use `-m multiarch`, or point pytest at a path that contains only multiarch tests (e.g. a `multiarch/` subdirectory). If any non-multiarch test is collected, pytest raises `UnsupportedCPUArchitectureError`. + +### Writing dedicated tests + +Multiarch-dedicated tests must be fully isolated from regular tests. Do **not** reuse or modify existing fixtures and functions — create new ones dedicated to multiarch tests. + +Mark the entire file or specific classes with the `multiarch` marker: + +```python +# Module-level (preferred — marks the whole file) +pytestmark = [pytest.mark.multiarch] + +# Class-level +@pytest.mark.multiarch +class TestMultiarchFeature: + ... +``` + +The `multiarch` marker is **required** on any test that runs in multiarch-dedicated mode. It also prevents the test from being collected on homogeneous clusters. + +Place multiarch tests in a `multiarch/` subdirectory or use `_multiarch` in the filename (repo convention, not enforced by pytest): + +``` +tests/ + install_upgrade_operators/ + hco_enablement_golden_image_updates/ + multiarch/ + test_multiarch_golden_images_support.py + network/ + connectivity/ + test_pod_network_multiarch.py +``` + +### Framework constraints + +Multiarch-dedicated runs (`--cpu-arch=amd64,arm64`) do not set a single target architecture. Tests must not rely on the helpers that regression runs provide: -`*_os_matrix` variables are not created for multi-arch runs (when `--cpu-arch` contains multiple architectures, e.g. `--cpu-arch=amd64,arm64`). +| Helper | Multiarch regression | Multiarch-dedicated | +| ------ | -------------------- | ------------------- | +| `py_config["cpu_arch"]` | Set to selected arch | **Not set** | +| OS matrix keys in `py_config` (e.g. `latest_rhel_os_dict`) | Generated for selected arch | **Not generated** | +| `schedulable_nodes` | Nodes of selected arch only | All schedulable nodes — filter by arch in the test | diff --git a/utilities/pytest_utils.py b/utilities/pytest_utils.py index 48bfd7a00a..97fcd6615c 100644 --- a/utilities/pytest_utils.py +++ b/utilities/pytest_utils.py @@ -650,6 +650,19 @@ def update_cpu_arch_related_config(cpu_arch_option: str) -> None: def filter_multiarch_tests(items: list[pytest.Item], config: pytest.Config) -> list[pytest.Item]: + """Deselect multiarch-marked tests on homogeneous clusters. + + On heterogeneous clusters (cluster_type=MULTIARCH), all tests pass through unchanged. + On homogeneous clusters, tests marked with 'multiarch' are deselected and reported + via pytest_deselected so they appear in the session summary. + + Args: + items: Collected test items. + config: Pytest config object, used to report deselected items. + + Returns: + Filtered list of test items with multiarch tests removed on homogeneous clusters. + """ if py_config.get("cluster_type") == MULTIARCH: return items discard_tests, items_to_return = remove_tests_from_list(items=items, filter_str="multiarch") From cf72b7f291d80d69a5d1141a29c666554e4d55a9 Mon Sep 17 00:00:00 2001 From: Harel Meir Date: Mon, 29 Jun 2026 13:10:15 +0300 Subject: [PATCH 4/6] Add tox check for multiarch Signed-off-by: Harel Meir --- tox.ini | 17 ++++++++++++++++- utilities/architecture.py | 2 +- utilities/unittests/test_architecture.py | 6 ++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 643220a309..0f458440ba 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=pytest-check-x86, pytest-check-arm64, pytest-check-s390x, unused-code, utilities-unittests +envlist=pytest-check-x86, pytest-check-arm64, pytest-check-s390x, pytest-check-multiarch, unused-code, utilities-unittests skipsdist=True [testenv] @@ -59,6 +59,21 @@ deps= commands = uv run pytest --tc-file=tests/global_config.py --collect-only -m s390x +[testenv:pytest-check-multiarch] +basepython = python3.14 +recreate=True +setenv = + PYTHONPATH = {toxinidir} + LC_ALL = en_US.utf8 + LANG = en_US.utf8 + UV_PYTHON = python3.14 + OPENSHIFT_VIRTUALIZATION_TEST_IMAGES_ARCH = amd64,arm64 +deps= + uv +commands = + uv run pytest --tc-file=tests/global_config.py --cpu-arch=amd64 --collect-only + uv run pytest --tc-file=tests/global_config.py --cpu-arch=arm64 --collect-only + uv run pytest --tc-file=tests/global_config_multiarch.py --cpu-arch=amd64,arm64 -m multiarch --collect-only # Polarion # Should run on every commit. diff --git a/utilities/architecture.py b/utilities/architecture.py index 2a2974bf01..bb49f9be6e 100644 --- a/utilities/architecture.py +++ b/utilities/architecture.py @@ -27,7 +27,7 @@ def get_cluster_architecture() -> set[str]: # Needed for CI if arch := os.environ.get("OPENSHIFT_VIRTUALIZATION_TEST_IMAGES_ARCH"): - return {arch} + return set(arch.split(",")) # Skip cluster connection for pytest flags that exit immediately without collecting tests _pytest_exit_flags = {"--help", "-h", "--version"} diff --git a/utilities/unittests/test_architecture.py b/utilities/unittests/test_architecture.py index b15a3f3ee8..270beb343e 100644 --- a/utilities/unittests/test_architecture.py +++ b/utilities/unittests/test_architecture.py @@ -36,6 +36,12 @@ def test_get_cluster_architecture_from_env_amd64(self): result = get_cluster_architecture() assert result == {"amd64"} + def test_get_cluster_architecture_from_env_multiarch(self): + """Test getting architecture from environment variable - comma-separated multiarch""" + with patch.dict(in_dict=os.environ, values={"OPENSHIFT_VIRTUALIZATION_TEST_IMAGES_ARCH": "amd64,arm64"}): + result = get_cluster_architecture() + assert result == {"amd64", "arm64"} + @patch("utilities.architecture.cache_admin_client") @patch("utilities.architecture.Node") def test_get_cluster_architecture_from_nodes_amd64(self, mock_node_class, mock_cache_client): From cfd1845728d958d1a4a8a00fca55d9b0a7b0bce4 Mon Sep 17 00:00:00 2001 From: Harel Meir Date: Tue, 30 Jun 2026 14:05:23 +0300 Subject: [PATCH 5/6] Updated README and cluster_info Signed-off-by: Harel Meir --- docs/MULTIARCH.md | 2 +- tests/conftest.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/MULTIARCH.md b/docs/MULTIARCH.md index bf034950ec..058ab29300 100644 --- a/docs/MULTIARCH.md +++ b/docs/MULTIARCH.md @@ -53,7 +53,7 @@ uv run pytest --tc-file=tests/global_config_multiarch.py --cpu-arch=amd64,arm64 ### Writing dedicated tests -Multiarch-dedicated tests must be fully isolated from regular tests. Do **not** reuse or modify existing fixtures and functions — create new ones dedicated to multiarch tests. +Multiarch-dedicated tests should be isolated from regular tests. Avoid modifying existing fixtures and functions — prefer creating dedicated ones for multiarch tests to reduce the risk of breaking regression suites. Mark the entire file or specific classes with the `multiarch` marker: diff --git a/tests/conftest.py b/tests/conftest.py index f91053db9c..17dd2a35d5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1497,7 +1497,6 @@ def cluster_info( ocs_current_version, kubevirt_resource_scope_session, workers_type, - nodes_cpu_architecture, ): title = "\nCluster info:\n" virtctl_client_version, virtctl_server_version = None, None @@ -1514,7 +1513,7 @@ def cluster_info( f"\tOCS version: {ocs_current_version}\n" f"\tCNI type: {get_cluster_cni_type(admin_client=admin_client)}\n" f"\tWorkers type: {workers_type}\n" - f"\tCluster CPU Architecture: {nodes_cpu_architecture or ', '.join(py_config['cluster_arch'])}\n" + f"\tCluster CPU Architecture: {', '.join(py_config['cluster_arch'])}\n" f"\tIPv4 cluster: {ipv4_supported_cluster()}\n" f"\tIPv6 cluster: {ipv6_supported_cluster()}\n" f"\tVirtctl version: \n\t{virtctl_client_version}\n\t{virtctl_server_version}\n" From 4656d10918008296fe162720ce52a365fa18f6ad Mon Sep 17 00:00:00 2001 From: Harel Meir Date: Wed, 1 Jul 2026 13:04:23 +0300 Subject: [PATCH 6/6] Add multiarch unnitest Signed-off-by: Harel Meir --- utilities/unittests/test_pytest_utils.py | 46 ++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/utilities/unittests/test_pytest_utils.py b/utilities/unittests/test_pytest_utils.py index 4bf8407760..7dba269d62 100644 --- a/utilities/unittests/test_pytest_utils.py +++ b/utilities/unittests/test_pytest_utils.py @@ -28,6 +28,7 @@ deploy_run_in_progress_namespace, exit_pytest_execution, filter_hpp_tests, + filter_multiarch_tests, generate_common_template_matrix_dicts, generate_instance_type_matrix_dicts, get_artifactory_server_url, @@ -2490,3 +2491,48 @@ def test_empty_marker_expression_filters_hpp(self): assert result == [] config.hook.pytest_deselected.assert_called_once_with(items=[item_hpp]) + + +class TestFilterMultiarchTests: + """Test cases for filter_multiarch_tests function.""" + + @patch("utilities.pytest_utils.py_config", {"cluster_type": MULTIARCH}) + def test_returns_all_items_on_multiarch_cluster(self): + """All tests pass through on heterogeneous (multiarch) clusters.""" + item_multiarch = MagicMock() + item_multiarch.keywords = {"multiarch": True} + item_other = MagicMock() + item_other.keywords = {"storage": True} + items = [item_multiarch, item_other] + config = MagicMock() + + result = filter_multiarch_tests(items=items, config=config) + + assert result == items + config.hook.pytest_deselected.assert_not_called() + + @patch("utilities.pytest_utils.py_config", {"cluster_type": AMD_64}) + def test_removes_multiarch_tests_on_homogeneous_cluster(self): + """Multiarch-marked tests are deselected on homogeneous clusters.""" + item_multiarch = MagicMock() + item_multiarch.keywords = {"multiarch": True} + item_other = MagicMock() + item_other.keywords = {"storage": True} + config = MagicMock() + + result = filter_multiarch_tests(items=[item_multiarch, item_other], config=config) + + assert result == [item_other] + config.hook.pytest_deselected.assert_called_once_with(items=[item_multiarch]) + + @patch("utilities.pytest_utils.py_config", {"cluster_type": AMD_64}) + def test_no_deselection_when_no_multiarch_tests(self): + """No deselection occurs when no tests have the multiarch marker.""" + item_other = MagicMock() + item_other.keywords = {"storage": True} + config = MagicMock() + + result = filter_multiarch_tests(items=[item_other], config=config) + + assert result == [item_other] + config.hook.pytest_deselected.assert_not_called()