coveragepy icon indicating copy to clipboard operation
coveragepy copied to clipboard

coverage run in parallel with multiprocessing doesn't measure test coverage for coroutines.

Open felixxm opened this issue 1 year ago • 3 comments

Describe the bug

Test coverage is not measured for coroutines when coverage is run in parallel with concurrency = multiprocessing. The following commit introduced this regression in Django: https://github.com/django/django/commit/69352d85fa8412865db9e0c7f177b333c0eac3e2. Running coverage without concurrency = multiprocessing works

$ coverage run runtests.py --settings=test_sqlite3 --parallel=1
$ coverage html

image

when run in parallel with concurrency = multiprocessing, coroutines are not marked as covered:

$ coverage run runtests.py --settings=test_sqlite
$ coverage combine
$ coverage html

image

To Reproduce How can we reproduce the problem? Please be specific. Don't link to a failing CI job. Answer the questions below:

  1. What version of Python are you using?

    3.10.9 and 3.11.1

  2. What version of coverage.py shows the problem?

    7.2.1

  3. What versions of what packages do you have installed?

    MarkupSafe-2.1.2 Pillow-9.4.0 PySocks-1.7.1 PyYAML-6.0 aiohttp-3.8.4 aiosignal-1.3.1 aiosmtpd-1.4.4.post2 argon2-cffi-21.3.0 argon2-cffi-bindings-21.2.0 asgiref-3.6.0 async-generator-1.10 async-timeout-4.0.2 atpublic-3.1.1 attrs-22.2.0 bcrypt-4.0.1 black-23.1.0 certifi-2022.12.7 cffi-1.15.1 charset-normalizer-3.1.0 click-8.1.3 docutils-0.19 exceptiongroup-1.1.1 frozenlist-1.3.3 geoip2-4.6.0 h11-0.14.0 idna-3.4 jinja2-3.1.2 maxminddb-2.2.0 multidict-6.0.4 mypy-extensions-1.0.0 numpy-1.24.2 outcome-1.2.0 packaging-23.0 pathspec-0.11.1 platformdirs-3.1.1 pycparser-2.21 pylibmc-1.6.3 pymemcache-4.0.0 pywatchman-1.4.1 redis-4.5.1 requests-2.28.2 selenium-4.8.2 sniffio-1.3.0 sortedcontainers-2.4.0 sqlparse-0.4.3 tblib-1.7.0 trio-0.22.0 trio-websocket-0.10.0 tzdata-2022.7 urllib3-1.26.15 wsproto-1.2.0 yarl-1.8.2

  4. What code shows the problem?

    coroutines

  5. What commands did you run?

    $ coverage run runtests.py --settings=test_sqlite $ coverage combine $ coverage html

Expected behavior Test coverage is measured for coroutines.

felixxm avatar Mar 15 '23 11:03 felixxm

It's hard for me to see how multiprocessing could interfere with in-process measurement of coroutines. Can you provide use with a reproducible demonstration of the problem.

nedbat avatar Mar 15 '23 13:03 nedbat

The minimal reproducer with the Django test suite is for auser() coroutine.

It is marked as covered when running:

coverage run runtests.py auth_tests.test_middleware --settings=test_sqlite --parallel=1
coverage html

but not when running:

coverage run --concurrency=multiprocessing runtests.py auth_tests.test_middleware --settings=test_sqlite
coverage combine
coverage html

felixxm avatar Mar 15 '23 15:03 felixxm

@felixxm Taking a look at this issue at PyCon sprints. I was able to reproduce your scenario both in the Django project and in an isolated scenario.

Determined that threads (spun by asgiref.sync.AsyncToSync in the Django test cases) are being ignored when --concurrency=multiprocessing is set.

Setting --concurrency=multiprocessing,thread solves the immediate issue and auser() is reported in coverage.

Investigating making this the default behaviour when using multiprocessing.

marcgibbons avatar Apr 24 '23 22:04 marcgibbons