1
1
from __future__ import annotations
2
2
3
+ import pprint
3
4
import os
4
5
import re
5
6
import shutil
@@ -1199,6 +1200,73 @@ def pytest_collection_modifyitems():
1199
1200
1200
1201
1201
1202
class 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
+
1202
1270
def test_by_module (self , pytester : pytest .Pytester ) -> None :
1203
1271
test_file = """
1204
1272
import pytest
@@ -1367,8 +1435,8 @@ def test2(self):
1367
1435
assert len (counts_by_worker_fence_b ) == 1
1368
1436
assert next (iter (counts_by_worker_fence_b .values ())) == 2
1369
1437
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 (
1372
1440
self , num_tests : int , pytester : pytest .Pytester
1373
1441
) -> None :
1374
1442
"""
@@ -1377,8 +1445,6 @@ def test_two_tests_min_per_worker_rule_with_two_workers(
1377
1445
"""
1378
1446
test_file1 = f"""
1379
1447
import pytest
1380
- # 6 tests should distribute 2 per worker for 3 workers due to the
1381
- # min-2 scope tests per worker rule.
1382
1448
@pytest.mark.parametrize('i', range({ num_tests } ))
1383
1449
def test(i):
1384
1450
pass
0 commit comments