11from __future__ import annotations
22
33import os
4+ import pathlib
45import pprint
56import re
67import shutil
78from typing import cast
9+ from uuid import uuid1
810
911import pytest
1012
@@ -1199,9 +1201,23 @@ def pytest_collection_modifyitems():
11991201 result .stdout .fnmatch_lines (["*RuntimeError: Some runtime error*" ])
12001202
12011203
1204+ @pytest .fixture (scope = "session" )
1205+ def shared_scope_setup_status_path (
1206+ tmp_path_factory : pytest .TempPathFactory , testrun_uid : str
1207+ ) -> pathlib .Path :
1208+ return (
1209+ tmp_path_factory .getbasetemp ().parent
1210+ / "test_distributed_setup_teardown_coordination"
1211+ / testrun_uid
1212+ / uuid1 ().hex
1213+ / "scope_setup_status.txt"
1214+ )
1215+
1216+
12021217class TestIsoScope :
12031218 def test_distributed_setup_teardown_coordination (
1204- self , pytester : pytest .Pytester
1219+ self , pytester : pytest .Pytester ,
1220+ shared_scope_setup_status_path : pathlib .Path
12051221 ) -> None :
12061222 """
12071223 The isoscope scheduler provides a distributed coordination mechanism
@@ -1215,58 +1231,63 @@ def test_distributed_setup_teardown_coordination(
12151231 5. Resource Setup of the next test Scope begins after completion of
12161232 the previous test Scope's Resource Teardown.
12171233 """
1218- test_file = """
1219- from __future__ import annotations
1220- import pathlib
1221- from uuid import uuid1
1222- from typing import TYPE_CHECKING
1223- import pytest
1224- if TYPE_CHECKING:
1225- from xdist.iso_scheduling_utils import (
1226- IsoSchedulingFixture,
1227- DistributedSetupContext,
1228- DistributedTeardownContext
1229- )
1230- class TestScopeA:
1231- @classmethod
1232- @pytest.fixture(scope='class', autouse=True)
1233- def distributed_setup_and_teardown(
1234- cls,
1235- iso_scheduling: IsoSchedulingFixture,
1236- request: pytest.FixtureRequest):
1237- with iso_scheduling.coordinate_setup_teardown(
1238- setup_request=request) as coordinator:
1239- # Distributed Setup
1240- coordinator.maybe_call_setup(cls.patch_system_under_test)
1241- try:
1242- # Yield control back to the XDist Worker to allow the
1243- # test cases to run
1244- yield
1245- finally:
1246- # Distributed Teardown
1247- coordinator.maybe_call_teardown(cls.revert_system_under_test)
1248- @classmethod
1249- def patch_system_under_test(
1250- cls,
1251- setup_context: DistributedSetupContext) -> None:
1252- # Initialize the System Under Test for all the test cases in
1253- # this test class and store state in `setup_context.client_dir`.
1254- pass
1255-
1256- @classmethod
1257- def revert_system_under_test(
1258- cls,
1259- teardown_context: DistributedTeardownContext):
1260- # Fetch state from `teardown_context.client_dir` and revert
1261- # changes made by `patch_system_under_test()`.
1262- pass
1263-
1264- @pytest.mark.parametrize('i', range(5))
1265- def test(self, i):
1266- pass
1234+ test_file = f"""
1235+ from __future__ import annotations
1236+ import pathlib
1237+ from typing import TYPE_CHECKING
1238+ import pytest
1239+ if TYPE_CHECKING:
1240+ from xdist.iso_scheduling_utils import (
1241+ IsoSchedulingFixture,
1242+ DistributedSetupContext,
1243+ DistributedTeardownContext
1244+ )
12671245
1268- class TestScopeB(TestScopeA):
1269- pass
1246+ _SHARED_SCOPE_SETUP_STATUS_PATH = pathlib.Path(
1247+ { str (shared_scope_setup_status_path )} )
1248+
1249+ class TestScopeA:
1250+ @classmethod
1251+ @pytest.fixture(scope='class', autouse=True)
1252+ def distributed_setup_and_teardown(
1253+ cls,
1254+ iso_scheduling: IsoSchedulingFixture,
1255+ request: pytest.FixtureRequest):
1256+ with iso_scheduling.coordinate_setup_teardown(
1257+ setup_request=request) as coordinator:
1258+ # Distributed Setup
1259+ coordinator.maybe_call_setup(cls.patch_system_under_test)
1260+ try:
1261+ # Yield control back to the XDist Worker to allow the
1262+ # test cases to run
1263+ yield
1264+ finally:
1265+ # Distributed Teardown
1266+ coordinator.maybe_call_teardown(cls.revert_system_under_test)
1267+ @classmethod
1268+ def patch_system_under_test(
1269+ cls,
1270+ setup_context: DistributedSetupContext) -> None:
1271+ # Initialize the System Under Test for all the test cases in
1272+ # this test class and store state in `setup_context.client_dir`.
1273+ assert _SHARED_SCOPE_SETUP_STATUS_PATH.read_text() == "TEARDOWN_COMPLETE"
1274+ _SHARED_SCOPE_SETUP_STATUS_PATH.write_text("SETUP_COMPLETE")
1275+
1276+ @classmethod
1277+ def revert_system_under_test(
1278+ cls,
1279+ teardown_context: DistributedTeardownContext):
1280+ # Fetch state from `teardown_context.client_dir` and revert
1281+ # changes made by `patch_system_under_test()`.
1282+ assert _SHARED_SCOPE_SETUP_STATUS_PATH.read_text() == "SETUP_COMPLETE"
1283+ _SHARED_SCOPE_SETUP_STATUS_PATH.write_text("TEARDOWN_COMPLETE")
1284+
1285+ @pytest.mark.parametrize('i', range(5))
1286+ def test(self, i):
1287+ assert _SHARED_SCOPE_SETUP_STATUS_PATH.read_text() == "SETUP_COMPLETE"
1288+
1289+ class TestScopeB(TestScopeA):
1290+ pass
12701291 """
12711292 pytester .makepyfile (test_a = test_file , test_b = test_file )
12721293 result = pytester .runpytest ("-n2" , "--dist=isoscope" , "-v" )
0 commit comments