Compare commits

..

9 Commits

Author SHA1 Message Date
Aleksandr Mezin
b591be4868 Release 3.2.1
Some checks failed
deploy / deploy (push) Failing after 1s
2023-03-12 14:42:09 +02:00
Aleksandr Mezin
b6c195a56c Merge pull request #885 from amezin/steal-hang-fix
Fix hang caused by `steal` command with empty test queue
2023-03-10 13:12:30 +02:00
Aleksandr Mezin
6abcdfc22e Fix hang caused by steal command with empty test queue
Fixes #884
2023-03-09 16:44:34 +02:00
pre-commit-ci[bot]
58fd7ccc05 [pre-commit.ci] pre-commit autoupdate (#881)
updates:
- [github.com/pre-commit/mirrors-mypy: v1.0.0 → v1.0.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.0.0...v1.0.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-02-27 08:53:38 -03:00
Bruno Oliveira
ba526fad5a Merge pull request #879 from pytest-dev/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2023-02-14 07:29:00 -03:00
pre-commit-ci[bot]
efe674b265 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/mirrors-mypy: v0.991 → v1.0.0](https://github.com/pre-commit/mirrors-mypy/compare/v0.991...v1.0.0)
2023-02-14 03:23:39 +00:00
Bruno Oliveira
5d692a7d63 Merge pull request #878 from akx/patch-1
docs: Remove unused statement in one-log-per-worker example
2023-02-13 11:01:58 -03:00
Aarni Koskela
5e795d88e7 docs: Remove unused statement in one-log-per-worker example 2023-02-13 15:38:59 +02:00
Aleksandr Mezin
2329d3454f Merge pull request #875 from pytest-dev/release-3.2.0
Release 3.2.0
2023-02-07 17:08:32 +02:00
5 changed files with 59 additions and 4 deletions

View File

@@ -39,7 +39,7 @@ repos:
language: python language: python
additional_dependencies: [pygments, restructuredtext_lint] additional_dependencies: [pygments, restructuredtext_lint]
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.991 rev: v1.0.1
hooks: hooks:
- id: mypy - id: mypy
files: ^(src/|testing/) files: ^(src/|testing/)

View File

@@ -1,3 +1,12 @@
pytest-xdist 3.2.1 (2023-03-12)
===============================
Bug Fixes
---------
- `#884 <https://github.com/pytest-dev/pytest-xdist/issues/884>`_: Fixed hang in ``worksteal`` scheduler.
pytest-xdist 3.2.0 (2023-02-07) pytest-xdist 3.2.0 (2023-02-07)
=============================== ===============================

View File

@@ -221,7 +221,6 @@ Example:
def pytest_configure(config): def pytest_configure(config):
worker_id = os.environ.get("PYTEST_XDIST_WORKER") worker_id = os.environ.get("PYTEST_XDIST_WORKER")
if worker_id is not None: if worker_id is not None:
log_file = config.getini("worker_log_file")
logging.basicConfig( logging.basicConfig(
format=config.getini("log_file_format"), format=config.getini("log_file_format"),
filename=f"tests_{worker_id}.log", filename=f"tests_{worker_id}.log",

View File

@@ -58,6 +58,7 @@ def worker_title(title):
class WorkerInteractor: class WorkerInteractor:
SHUTDOWN_MARK = object() SHUTDOWN_MARK = object()
QUEUE_REPLACED_MARK = object()
def __init__(self, config, channel): def __init__(self, config, channel):
self.config = config self.config = config
@@ -72,6 +73,15 @@ class WorkerInteractor:
def _make_queue(self): def _make_queue(self):
return self.channel.gateway.execmodel.queue.Queue() return self.channel.gateway.execmodel.queue.Queue()
def _get_next_item_index(self):
"""Gets the next item from test queue. Handles the case when the queue
is replaced concurrently in another thread.
"""
result = self.torun.get()
while result is self.QUEUE_REPLACED_MARK:
result = self.torun.get()
return result
def sendevent(self, name, **kwargs): def sendevent(self, name, **kwargs):
self.log("sending", name, kwargs) self.log("sending", name, kwargs)
self.channel.send((name, kwargs)) self.channel.send((name, kwargs))
@@ -136,19 +146,22 @@ class WorkerInteractor:
self.torun.put(i) self.torun.put(i)
self.sendevent("unscheduled", indices=stolen) self.sendevent("unscheduled", indices=stolen)
old_queue.put(self.QUEUE_REPLACED_MARK)
@pytest.hookimpl @pytest.hookimpl
def pytest_runtestloop(self, session): def pytest_runtestloop(self, session):
self.log("entering main loop") self.log("entering main loop")
self.channel.setcallback(self.handle_command, endmarker=self.SHUTDOWN_MARK) self.channel.setcallback(self.handle_command, endmarker=self.SHUTDOWN_MARK)
self.nextitem_index = self.torun.get() self.nextitem_index = self._get_next_item_index()
while self.nextitem_index is not self.SHUTDOWN_MARK: while self.nextitem_index is not self.SHUTDOWN_MARK:
self.run_one_test() self.run_one_test()
return True return True
def run_one_test(self): def run_one_test(self):
self.item_index = self.nextitem_index
self.nextitem_index = self._get_next_item_index()
items = self.session.items items = self.session.items
self.item_index, self.nextitem_index = self.nextitem_index, self.torun.get()
item = items[self.item_index] item = items[self.item_index]
if self.nextitem_index is self.SHUTDOWN_MARK: if self.nextitem_index is self.SHUTDOWN_MARK:
nextitem = None nextitem = None

View File

@@ -271,6 +271,40 @@ class TestWorkerInteractor:
ev = worker.popevent("workerfinished") ev = worker.popevent("workerfinished")
assert "workeroutput" in ev.kwargs assert "workeroutput" in ev.kwargs
def test_steal_empty_queue(self, worker: WorkerSetup, unserialize_report) -> None:
worker.pytester.makepyfile(
"""
def test_func(): pass
def test_func2(): pass
"""
)
worker.setup()
ev = worker.popevent("collectionfinish")
ids = ev.kwargs["ids"]
assert len(ids) == 2
worker.sendcommand("runtests_all")
for when in ["setup", "call", "teardown"]:
ev = worker.popevent("testreport")
rep = unserialize_report(ev.kwargs["data"])
assert rep.nodeid.endswith("::test_func")
assert rep.when == when
worker.sendcommand("steal", indices=[0, 1])
ev = worker.popevent("unscheduled")
assert ev.kwargs["indices"] == []
worker.sendcommand("shutdown")
for when in ["setup", "call", "teardown"]:
ev = worker.popevent("testreport")
rep = unserialize_report(ev.kwargs["data"])
assert rep.nodeid.endswith("::test_func2")
assert rep.when == when
ev = worker.popevent("workerfinished")
assert "workeroutput" in ev.kwargs
def test_remote_env_vars(pytester: pytest.Pytester) -> None: def test_remote_env_vars(pytester: pytest.Pytester) -> None:
pytester.makepyfile( pytester.makepyfile(