diff --git a/conftest.py b/conftest.py index deffc6e59..01f6f9812 100644 --- a/conftest.py +++ b/conftest.py @@ -170,21 +170,26 @@ def pytest_collection_modifyitems(items: list[pytest.Item], config: pytest.Confi # Automatically mark tests based on fixtures they require. # Check pytest.ini or pytest --markers for marker descriptions. - markable_fixtures = [ - 'uefi_vm', - 'unix_vm', - 'windows_vm', - 'hostA2', - 'hostB1', - 'unused_512B_disks', - 'unused_4k_disks', - ] + # Maps fixture name -> mark name. skip_if_not_* variants map to the same mark as their + # fail counterparts since they still require the same VM type. + markable_fixtures: dict[str, str] = { + 'uefi_vm': 'uefi_vm', + 'skip_if_not_uefi_vm': 'uefi_vm', + 'unix_vm': 'unix_vm', + 'skip_if_not_unix_vm': 'unix_vm', + 'windows_vm': 'windows_vm', + 'skip_if_not_windows_vm': 'windows_vm', + 'hostA2': 'hostA2', + 'hostB1': 'hostB1', + 'unused_512B_disks': 'unused_512B_disks', + 'unused_4k_disks': 'unused_4k_disks', + } for item in items: fixturenames = getattr(item, 'fixturenames', ()) - for fixturename in markable_fixtures: + for fixturename, markname in markable_fixtures.items(): if fixturename in fixturenames: - item.add_marker(fixturename) + item.add_marker(markname) if 'vm_ref' not in fixturenames: item.add_marker('no_vm') @@ -752,7 +757,16 @@ def running_vm(started_vm: VM) -> VM: def unix_vm(imported_vm: VM) -> Generator[VM, None, None]: vm = imported_vm if vm.is_windows: - pytest.skip("This test is only compatible with unix VMs.") + pytest.fail("This test requires a unix VM.") + yield vm + +@pytest.fixture(scope='module') +def skip_if_not_unix_vm(imported_vm: VM) -> Generator[VM, None, None]: + # Skip (not fail) is intentional: used in multi-VM jobs where both unix and Windows VMs + # are present by design. A non-matching VM is expected, not a misconfiguration. + vm = imported_vm + if vm.is_windows: + pytest.skip("Skipping: this test is only compatible with unix VMs.") yield vm @pytest.fixture(scope="module") @@ -764,14 +778,32 @@ def running_unix_vm(unix_vm: VM, running_vm: VM) -> VM: def windows_vm(imported_vm: VM) -> Generator[VM, None, None]: vm = imported_vm if not vm.is_windows: - pytest.skip("This test is only compatible with Windows VMs.") + pytest.fail("This test requires a Windows VM.") + yield vm + +@pytest.fixture(scope='module') +def skip_if_not_windows_vm(imported_vm: VM) -> Generator[VM, None, None]: + # Skip (not fail) is intentional: used in multi-VM jobs where both unix and Windows VMs + # are present by design. A non-matching VM is expected, not a misconfiguration. + vm = imported_vm + if not vm.is_windows: + pytest.skip("Skipping: this test is only compatible with Windows VMs.") yield vm @pytest.fixture(scope='module') def uefi_vm(imported_vm: VM) -> Generator[VM, None, None]: vm = imported_vm if not vm.is_uefi: - pytest.skip('This test requires an UEFI VM') + pytest.fail('This test requires a UEFI VM.') + yield vm + +@pytest.fixture(scope='module') +def skip_if_not_uefi_vm(imported_vm: VM) -> Generator[VM, None, None]: + # Skip (not fail) is intentional: used in multi-VM jobs where both UEFI and non-UEFI VMs + # are present by design. A non-matching VM is expected, not a misconfiguration. + vm = imported_vm + if not vm.is_uefi: + pytest.skip('Skipping: this test requires a UEFI VM.') yield vm @pytest.fixture(scope='session') diff --git a/tests/guest_tools/unix/test_guest_tools_unix.py b/tests/guest_tools/unix/test_guest_tools_unix.py index f2e870702..37ce84d3c 100644 --- a/tests/guest_tools/unix/test_guest_tools_unix.py +++ b/tests/guest_tools/unix/test_guest_tools_unix.py @@ -26,7 +26,7 @@ def __init__(self) -> None: @pytest.mark.multi_vms -@pytest.mark.usefixtures("unix_vm") +@pytest.mark.usefixtures("skip_if_not_unix_vm") class TestGuestToolsUnix: @pytest.fixture(scope='class') def state(self) -> State: diff --git a/tests/guest_tools/win/test_guest_tools_win.py b/tests/guest_tools/win/test_guest_tools_win.py index 969836f24..44057505c 100644 --- a/tests/guest_tools/win/test_guest_tools_win.py +++ b/tests/guest_tools/win/test_guest_tools_win.py @@ -70,7 +70,7 @@ @pytest.mark.multi_vms -@pytest.mark.usefixtures("windows_vm") +@pytest.mark.usefixtures("skip_if_not_windows_vm") class TestGuestToolsWindows: def test_drivers_detected(self, vm_install_test_tools_per_test_class: VM) -> None: pass @@ -144,7 +144,7 @@ def test_xenvbd_ssd(self, vm_install_test_tools_per_test_class: VM) -> None: @pytest.mark.multi_vms -@pytest.mark.usefixtures("windows_vm") +@pytest.mark.usefixtures("skip_if_not_windows_vm") class TestGuestToolsWindowsDestructive: def test_uninstall_tools(self, vm_install_test_tools_no_reboot: VM) -> None: vm = vm_install_test_tools_no_reboot @@ -176,7 +176,7 @@ def test_install_with_other_tools( exitcode = install_guest_tools(vm, guest_tools_iso, PowerAction.Nothing, check=False) assert exitcode == ERROR_INSTALL_FAILURE - @pytest.mark.usefixtures("uefi_vm") + @pytest.mark.usefixtures("skip_if_not_uefi_vm") def test_uefi_vm_suspend_refused_without_tools(self, running_unsealed_windows_vm: VM) -> None: vm = running_unsealed_windows_vm with pytest.raises(SSHCommandFailed, match="lacks the feature"): diff --git a/tests/guest_tools/win/test_xenclean.py b/tests/guest_tools/win/test_xenclean.py index e88f86a6c..bd089e34a 100644 --- a/tests/guest_tools/win/test_xenclean.py +++ b/tests/guest_tools/win/test_xenclean.py @@ -94,7 +94,7 @@ def onboarding_guest_tools_iso(guest_tools_iso: Dict[str, Any]) -> Dict[str, Any @pytest.mark.multi_vms -@pytest.mark.usefixtures("windows_vm") +@pytest.mark.usefixtures("skip_if_not_windows_vm") class TestXenClean: def test_xenclean_without_tools( self, running_unsealed_windows_vm: VM, guest_tools_iso: Dict[str, Any] diff --git a/tests/uefi_sb/test_uefistored_sb.py b/tests/uefi_sb/test_uefistored_sb.py index 43033d749..5d113cf2a 100644 --- a/tests/uefi_sb/test_uefistored_sb.py +++ b/tests/uefi_sb/test_uefistored_sb.py @@ -38,7 +38,7 @@ @pytest.mark.small_vm @pytest.mark.usefixtures("host_less_than_8_3") -@pytest.mark.usefixtures("pool_without_uefi_certs", "unix_vm") +@pytest.mark.usefixtures("pool_without_uefi_certs", "skip_if_not_unix_vm") class TestGuestLinuxUEFISecureBoot: PK: EFIAuth KEK: EFIAuth @@ -135,7 +135,7 @@ def test_sb_off_really_means_off(self, uefi_vm: VM) -> None: @pytest.mark.usefixtures("host_less_than_8_3") -@pytest.mark.usefixtures("pool_without_uefi_certs", "windows_vm") +@pytest.mark.usefixtures("pool_without_uefi_certs", "skip_if_not_windows_vm") class TestGuestWindowsUEFISecureBoot: @pytest.fixture(autouse=True) def setup_and_cleanup(self, uefi_vm_and_snapshot: tuple[VM, Snapshot]) -> Generator[None, None, None]: diff --git a/tests/uefi_sb/test_varstored_sb.py b/tests/uefi_sb/test_varstored_sb.py index 29696e283..a10c47a60 100644 --- a/tests/uefi_sb/test_varstored_sb.py +++ b/tests/uefi_sb/test_varstored_sb.py @@ -37,7 +37,7 @@ @pytest.mark.small_vm @pytest.mark.usefixtures("host_at_least_8_3") -@pytest.mark.usefixtures("unix_vm") +@pytest.mark.usefixtures("skip_if_not_unix_vm") class TestGuestLinuxUEFISecureBoot: PK: EFIAuth KEK: EFIAuth @@ -137,7 +137,7 @@ def test_append_with_poison(self, uefi_vm: VM) -> None: @pytest.mark.usefixtures("host_at_least_8_3") -@pytest.mark.usefixtures("windows_vm") +@pytest.mark.usefixtures("skip_if_not_windows_vm") class TestGuestWindowsUEFISecureBoot: @pytest.fixture(autouse=True) def setup_and_cleanup(self, uefi_vm_and_snapshot: tuple[VM, Snapshot]) -> Generator[None, None, None]: