1818from .errors import TeardownExceptionGroup
1919from .fixtures import MultihostFixture
2020from .logging import MultihostLogger
21- from .marks import TopologyMark
21+ from .marks import KnownTopologyBase , TopologyMark
2222from .multihost import (
2323 MultihostArtifactsMode ,
2424 MultihostConfig ,
@@ -63,6 +63,7 @@ def __init__(self, pytest_config: pytest.Config) -> None:
6363 self .mh_collect_artifacts : MultihostArtifactsMode = pytest_config .getoption ("mh_collect_artifacts" )
6464 self .mh_artifacts_dir : Path = Path (pytest_config .getoption ("mh_artifacts_dir" ))
6565 self .mh_compress_artifacts : bool = pytest_config .getoption ("mh_compress_artifacts" )
66+ self .mh_ignore_preferred_topology : bool = pytest_config .getoption ("mh_ignore_preferred_topology" )
6667
6768 # Read --mh-collect-logs, default to --mh-collect-artifacts
6869 self .mh_collect_logs : MultihostArtifactsMode = pytest_config .getoption ("mh_collect_logs" )
@@ -200,6 +201,7 @@ def pytest_sessionstart(self, session: pytest.Session) -> None:
200201 self .logger .info (f" collect artifacts: { self .mh_collect_artifacts } " )
201202 self .logger .info (f" artifacts directory: { self .mh_artifacts_dir } " )
202203 self .logger .info (f" collect logs: { self .mh_collect_logs } " )
204+ self .logger .info (f" ignore-preferred-topology: { self .mh_ignore_preferred_topology } " )
203205 self .logger .info ("" )
204206
205207 signal (SIGINT , self .sigint_handler )
@@ -521,6 +523,32 @@ def _create_logger(self, verbose) -> logging.Logger:
521523 def _is_multihost_required (self , item : pytest .Item ) -> bool :
522524 return item .get_closest_marker (name = "topology" ) is not None
523525
526+ def _can_run_preferred_topology (self , mark : pytest .Mark , current_topology : str , item : pytest .Item ) -> bool :
527+ if len (mark .args ) != 1 :
528+ raise ValueError (
529+ f"{ item .nodeid } : Unexpected number of arguments to pytest.mark.preferred_topology: "
530+ f"got { len (mark .args )} , expected 1"
531+ )
532+
533+ arg = mark .args [0 ]
534+
535+ if isinstance (arg , KnownTopologyBase ):
536+ name = arg .value .name
537+ elif isinstance (arg , TopologyMark ):
538+ name = arg .name
539+ elif isinstance (arg , str ):
540+ name = arg
541+ else :
542+ raise ValueError (
543+ f"{ item .nodeid } : Unexpected type of pytest.mark.preferred_topology: "
544+ f"got { type (arg )} , expected KnownTopologyBase | TopologyMark | str"
545+ )
546+
547+ if name == current_topology :
548+ return True
549+
550+ return False
551+
524552 def _can_run_test (self , item : pytest .Item , data : MultihostItemData | None ) -> bool :
525553 if data is None :
526554 return not self ._is_multihost_required (item )
@@ -547,6 +575,12 @@ def _can_run_test(self, item: pytest.Item, data: MultihostItemData | None) -> bo
547575 if data .topology_mark .name not in self .mh_topology :
548576 return False
549577
578+ # Run only for preferred topology unless specific topology is requested or the marker is ignored
579+ if not self .mh_topology and not self .mh_ignore_preferred_topology :
580+ preferred_topology = item .get_closest_marker (name = "preferred_topology" )
581+ if preferred_topology is not None and data .topology_mark is not None :
582+ return self ._can_run_preferred_topology (preferred_topology , data .topology_mark .name , item )
583+
550584 return True
551585
552586 def _clone_function (self , name : str , f : pytest .Function ) -> pytest .Function :
@@ -792,6 +826,12 @@ def pytest_addoption(parser):
792826
793827 parser .addoption ("--mh-lazy-ssh" , action = "store_true" , help = "Postpone connecting to host SSH until it is required" )
794828
829+ parser .addoption (
830+ "--mh-ignore-preferred-topology" ,
831+ action = "store_true" ,
832+ help = "All topologies will run, ignore the preferred_topology marker" ,
833+ )
834+
795835 parser .addoption (
796836 "--mh-topology" ,
797837 action = "append" ,
@@ -862,6 +902,13 @@ def pytest_configure(config: pytest.Config):
862902 "the test is skipped if condition is not met" ,
863903 )
864904
905+ config .addinivalue_line (
906+ "markers" ,
907+ "preferred_topology(topology: KnownTopologyBase | TopologyMark | str): "
908+ "mark test with a preferred topology."
909+ "Test will execute once, skipping additional topologies" ,
910+ )
911+
865912 config .pluginmanager .register (MultihostPlugin (config ), "MultihostPlugin" )
866913
867914
0 commit comments