|
7 | 7 | This module is run automatically by pytest, to define and enable fixtures.
|
8 | 8 | """
|
9 | 9 |
|
| 10 | +import itertools |
10 | 11 | import os
|
11 | 12 | import sys
|
12 | 13 | import warnings
|
@@ -71,16 +72,58 @@ def reset_sys_path():
|
71 | 72 | sys.path[:] = sys_path
|
72 | 73 |
|
73 | 74 |
|
| 75 | +TRACK_TESTS = False |
| 76 | +TEST_TXT = "/tmp/tests.txt" |
| 77 | + |
| 78 | +def pytest_sessionstart(): |
| 79 | + """Run once at the start of the test session.""" |
| 80 | + if TRACK_TESTS: # pragma: debugging |
| 81 | + with open(TEST_TXT, "w") as testtxt: |
| 82 | + print("Starting:", file=testtxt) |
| 83 | + |
| 84 | + |
| 85 | +def write_test_name(prefix): |
| 86 | + """For tracking where and when tests are running.""" |
| 87 | + if TRACK_TESTS: # pragma: debugging |
| 88 | + with open(TEST_TXT, "a") as testtxt: |
| 89 | + worker = os.environ.get('PYTEST_XDIST_WORKER', 'none') |
| 90 | + test = os.environ.get("PYTEST_CURRENT_TEST", "unknown") |
| 91 | + print(f"{prefix} {worker}: {test}", file=testtxt, flush=True) |
| 92 | + |
| 93 | + |
74 | 94 | @pytest.hookimpl(hookwrapper=True)
|
75 | 95 | def pytest_runtest_call(item):
|
76 |
| - """Convert StopEverything into skipped tests.""" |
| 96 | + """Run once for each test.""" |
| 97 | + write_test_name(">") |
| 98 | + |
| 99 | + # Convert StopEverything into skipped tests. |
77 | 100 | outcome = yield
|
78 | 101 | if outcome.excinfo and issubclass(outcome.excinfo[0], StopEverything): # pragma: only jython
|
79 | 102 | pytest.skip(f"Skipping {item.nodeid} for StopEverything: {outcome.excinfo[1]}")
|
80 | 103 |
|
81 |
| - # For diagnosing test running: |
82 |
| - if 0: |
83 |
| - with open("/tmp/tests.txt", "a") as proctxt: |
84 |
| - worker = os.environ.get('PYTEST_XDIST_WORKER', 'none') |
85 |
| - test = os.environ.get("PYTEST_CURRENT_TEST", "unknown") |
86 |
| - print(f"{worker}: {test}", file=proctxt, flush=True) |
| 104 | + write_test_name("<") |
| 105 | + |
| 106 | + |
| 107 | +def interleaved(firsts, rest, n): |
| 108 | + """Interleave the firsts among the rest so that they occur each n items.""" |
| 109 | + num = sum(len(l) for l in firsts) + len(rest) |
| 110 | + lists = firsts + [rest] * (n - len(firsts)) |
| 111 | + listcycle = itertools.cycle(lists) |
| 112 | + |
| 113 | + while num: |
| 114 | + alist = next(listcycle) # pylint: disable=stop-iteration-return |
| 115 | + if alist: |
| 116 | + yield alist.pop() |
| 117 | + num -= 1 |
| 118 | + |
| 119 | +def pytest_collection_modifyitems(items): |
| 120 | + """Re-order the collected tests.""" |
| 121 | + # Trick the xdist scheduler to put all of the VirtualenvTest tests on the |
| 122 | + # same worker by sprinkling them into the collected items every Nth place. |
| 123 | + virt = set(i for i in items if "VirtualenvTest" in i.nodeid) |
| 124 | + rest = [i for i in items if i not in virt] |
| 125 | + nworkers = int(os.environ.get("PYTEST_XDIST_WORKER_COUNT", 4)) |
| 126 | + items[:] = interleaved([virt], rest, nworkers) |
| 127 | + if TRACK_TESTS: # pragma: debugging |
| 128 | + with open("/tmp/items.txt", "w") as f: |
| 129 | + print("\n".join(i.nodeid for i in items), file=f) |
0 commit comments