Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
  • Loading branch information
pre-commit-ci[bot] committed Mar 3, 2025
commit 458c8c4a649027b56dac4ac27289b6e37584b285
4 changes: 3 additions & 1 deletion src/xdist/scheduler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
from xdist.scheduler.loadgroup import LoadGroupScheduling as LoadGroupScheduling
from xdist.scheduler.loadscope import LoadScopeScheduling as LoadScopeScheduling
from xdist.scheduler.protocol import Scheduling as Scheduling
from xdist.scheduler.singlecollect import SingleCollectScheduling as SingleCollectScheduling
from xdist.scheduler.singlecollect import (
SingleCollectScheduling as SingleCollectScheduling,
)
from xdist.scheduler.worksteal import WorkStealingScheduling as WorkStealingScheduling
6 changes: 4 additions & 2 deletions src/xdist/scheduler/singlecollect.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ def mark_test_complete(
self, node: WorkerController, item_index: int | str, duration: float = 0
) -> None:
"""Mark test item as completed by node."""
self.node2pending[node].remove(int(item_index) if isinstance(item_index, str) else item_index)
self.node2pending[node].remove(
int(item_index) if isinstance(item_index, str) else item_index
)
self.check_schedule(node, duration=duration)

def mark_test_pending(self, item: str) -> None:
Expand Down Expand Up @@ -208,4 +210,4 @@ def _send_tests(self, node: WorkerController, num: int) -> None:
if tests_per_node:
del self.pending[:num]
self.node2pending[node].extend(tests_per_node)
node.send_runtest_some(tests_per_node)
node.send_runtest_some(tests_per_node)
6 changes: 3 additions & 3 deletions testing/acceptance_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_ok():
result.stdout.fnmatch_lines(["*1 passed*"])
# Make sure the tests are correctly distributed
result.stdout.fnmatch_lines(["*scheduling tests via SingleCollectScheduling*"])

def test_singlecollect_many_tests(self, pytester: pytest.Pytester) -> None:
"""Test that the singlecollect mode correctly distributes many tests."""
# Create test file with multiple tests
Expand All @@ -42,7 +42,7 @@ def test_ok(x):
result.stdout.fnmatch_lines(["*passed*"])
# Make sure the tests are correctly distributed
result.stdout.fnmatch_lines(["*scheduling tests via SingleCollectScheduling*"])

def test_singlecollect_failure(self, pytester: pytest.Pytester) -> None:
"""Test that failures are correctly reported with singlecollect mode."""
p1 = pytester.makepyfile(
Expand All @@ -54,7 +54,7 @@ def test_fail():
result = pytester.runpytest(p1, "-n2", "--dist=singlecollect", "-v")
assert result.ret == 1
result.stdout.fnmatch_lines(["*1 failed*"])

def test_singlecollect_handles_fixtures(self, pytester: pytest.Pytester) -> None:
"""Test that fixtures work correctly with singlecollect mode."""
pytester.makepyfile(
Expand Down
48 changes: 24 additions & 24 deletions testing/test_dsession.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,22 +482,22 @@ def test_add_node_and_collection(self, pytester: pytest.Pytester) -> None:
config = pytester.parseconfig("--tx=2*popen")
sched = SingleCollectScheduling(config)
node1, node2 = MockNode(), MockNode()

# First node should be set as collector
sched.add_node(node1)
assert sched.first_node == node1

# Second node should not become the collector
sched.add_node(node2)
assert sched.first_node == node1

# Collection from first node should be used
collection = ["a.py::test_1", "a.py::test_2", "a.py::test_3"]
sched.add_node_collection(node1, collection)
assert sched.collection == collection
assert sched.collection_done
assert sched.collection_is_completed

# Collection from second node should be ignored
different_collection = ["a.py::test_1", "a.py::test_4"]
sched.add_node_collection(node2, different_collection)
Expand All @@ -510,21 +510,21 @@ def test_schedule_tests(self, pytester: pytest.Pytester) -> None:
node1, node2 = MockNode(), MockNode()
sched.add_node(node1)
sched.add_node(node2)

collection = ["a.py::test_1", "a.py::test_2", "a.py::test_3", "a.py::test_4"]
sched.add_node_collection(node1, collection)

# Should use collection from node1 and distribute tests
sched.schedule()

# Check that tests were distributed across both nodes
assert len(node1.sent) > 0
assert len(node2.sent) > 0

# Tests should be distributed completely
all_tests = node1.sent + node2.sent
assert sorted(all_tests) == list(range(len(collection)))

# The pending list should be empty after distribution
assert not sched.pending

Expand All @@ -534,37 +534,37 @@ def test_handle_node_failure(self, pytester: pytest.Pytester) -> None:
node1, node2 = MockNode(), MockNode()
sched.add_node(node1)
sched.add_node(node2)

collection = ["a.py::test_1", "a.py::test_2", "a.py::test_3", "a.py::test_4"]
sched.add_node_collection(node1, collection)
sched.schedule()

# Simulate node1 completing a test
test_idx = node1.sent[0]
sched.mark_test_complete(node1, test_idx)

# Now remove node2 (simulating failure)
sched.remove_node(node2)

# Tests assigned to node2 should go back to pending
assert len(sched.pending) > 0

# Add a new node
node3 = MockNode()
sched.add_node(node3)

# Since collection is already completed, schedule should assign pending tests to node3
sched.schedule()
assert len(node3.sent) > 0

# Complete all tests
for idx in node1.sent:
if idx != test_idx: # Skip the one we already completed
sched.mark_test_complete(node1, idx)

for idx in node3.sent:
sched.mark_test_complete(node3, idx)

# All tests should be completed
assert sched.tests_finished

Expand All @@ -573,26 +573,26 @@ def test_first_node_failure(self, pytester: pytest.Pytester) -> None:
config = pytester.parseconfig("--tx=2*popen")
sched = SingleCollectScheduling(config)
node1, node2 = MockNode(), MockNode()

# First node should be collector
sched.add_node(node1)
assert sched.first_node == node1

# Add second node
sched.add_node(node2)

# First node fails before collection
sched.remove_node(node1)

# Now second node should become the collector
assert sched.first_node is None # first_node is reset after removal

# Add a new node, it should become the collector
node3 = MockNode()
sched.add_node(node3)
# Verify the new node became the collector
assert sched.first_node == node3

# Complete collection with node3
collection = ["a.py::test_1", "a.py::test_2"]
sched.add_node_collection(node3, collection)
Expand Down
Loading