11from __future__ import annotations
22
3+ import pprint
34import os
45import re
56import shutil
@@ -1199,6 +1200,73 @@ def pytest_collection_modifyitems():
11991200
12001201
12011202class TestIsoScope :
1203+ def test_distributed_setup_teardown_coordination (
1204+ self , pytester : pytest .Pytester
1205+ ) -> None :
1206+ """
1207+ The isoscope scheduler provides a distributed coordination mechanism
1208+ for Scope-level Resource Setup/Teardown with the following guarantees:
1209+ 1. Resource Setup is performed exactly once per test Scope.
1210+ 2. Resource Teardown is performed exactly once per test Scope.
1211+ 3. Resource Setup of the executing test Scope completes BEFORE
1212+ execution of the Scope's tests.
1213+ 4. Resource Teardown phase of the executing test Scope begins after
1214+ completion of all tests of the Scope.
1215+ 5. Resource Setup of the next test Scope begins after completion of
1216+ the previous test Scope's Resource Teardown.
1217+ """
1218+ test_file = """
1219+ import pathlib
1220+ from uuid import uuid1
1221+ import pytest
1222+ class TestScopeA:
1223+ @classmethod
1224+ @pytest.fixture(scope='class', autouse=True)
1225+ def distributed_setup_and_teardown(
1226+ cls,
1227+ iso_scheduling:
1228+ request: pytest.FixtureRequest):
1229+ with iso_scheduling.coordinate_setup_teardown(
1230+ setup_request=request) as coordinator:
1231+ # Distributed Setup
1232+ coordinator.maybe_call_setup(cls.patch_system_under_test)
1233+ try:
1234+ # Yield control back to the XDist Worker to allow the
1235+ # test cases to run
1236+ yield
1237+ finally:
1238+ # Distributed Teardown
1239+ coordinator.maybe_call_teardown(cls.revert_system_under_test)
1240+ @classmethod
1241+ def patch_system_under_test(
1242+ cls,
1243+ setup_context: DistributedSetupContext) -> None:
1244+ # Initialize the System Under Test for all the test cases in
1245+ # this test class and store state in `setup_context.client_dir`.
1246+
1247+ @classmethod
1248+ def revert_system_under_test(
1249+ cls,
1250+ teardown_context: DistributedTeardownContext)
1251+ # Fetch state from `teardown_context.client_dir` and revert
1252+ # changes made by `patch_system_under_test()`.
1253+
1254+ @pytest.mark.parametrize('i', range(5))
1255+ def test(self, i):
1256+ pass
1257+
1258+ class TestScopeB(TestScopeA):
1259+ pass
1260+ """
1261+ pytester .makepyfile (test_a = test_file , test_b = test_file )
1262+ result = pytester .runpytest ("-n2" , "--dist=isoscope" , "-v" )
1263+
1264+ print ("ZZZ outlines" )
1265+ print (pprint .pprint (result .outlines , indent = 4 ))
1266+ print ("ZZZ errlines" )
1267+ print (pprint .pprint (result .errlines , indent = 4 ))
1268+ assert False
1269+
12021270 def test_by_module (self , pytester : pytest .Pytester ) -> None :
12031271 test_file = """
12041272 import pytest
@@ -1367,8 +1435,8 @@ def test2(self):
13671435 assert len (counts_by_worker_fence_b ) == 1
13681436 assert next (iter (counts_by_worker_fence_b .values ())) == 2
13691437
1370- @pytest .mark .parametrize (" num_tests" , [1 , 2 , 3 , 4 , 5 , 7 ])
1371- def test_two_tests_min_per_worker_rule_with_two_workers (
1438+ @pytest .mark .parametrize (' num_tests' , [1 , 2 , 3 , 4 , 5 , 7 ])
1439+ def test_two_tests_min_per_worker_rule (
13721440 self , num_tests : int , pytester : pytest .Pytester
13731441 ) -> None :
13741442 """
@@ -1377,8 +1445,6 @@ def test_two_tests_min_per_worker_rule_with_two_workers(
13771445 """
13781446 test_file1 = f"""
13791447 import pytest
1380- # 6 tests should distribute 2 per worker for 3 workers due to the
1381- # min-2 scope tests per worker rule.
13821448 @pytest.mark.parametrize('i', range({ num_tests } ))
13831449 def test(i):
13841450 pass
0 commit comments