coveragepy icon indicating copy to clipboard operation
coveragepy copied to clipboard

Missing coverage when using the "redis" library

Open krieghan opened this issue 1 year ago • 7 comments

Describe the bug When using asyncio with redis.asyncio (redispy), some lines that are definitely hit remain mysteriously uncovered, even when using a combination of different concurrency settings

To Reproduce

  1. Python version 3.11.4, with coverage 7.3.0 and redis 5.0.0 (OS is Ubuntu 22.04)
  2. My .coveragerc file:
[run]
source = .
parallel = True
concurrency = 
    thread
    gevent
    multiprocessing

(I've tried various combinations of concurrency, but I most often leave it blank. I suspect it's not even appropriate for my application, though I'm not certain)

My minimal example (coverage_test.py):

import asyncio

import redis.asyncio as redis


async def main():
    client = redis.Redis()
    result = await client.get('key')
    print('running main')

if __name__ == '__main__':
    asyncio.run(main())
    print('finished main')

I issue the coverage command with a bash script (coverage.sh) as follows:

coverage erase
coverage run coverage_test.py
coverage combine
coverage html
xdg-open htmlcov/index.html

The output of the script is:

running main
finished main

And the coverage of the file looks like this:

image

I would expect the last print statement (which is executed, according to the output) to be marked green. I see there are some similar issues (most notably https://github.com/nedbat/coveragepy/issues/1082 and https://github.com/nedbat/coveragepy/issues/1598), but as I mentioned I haven't found a concurrency setting that mitigates this.

krieghan avatar Aug 16 '23 15:08 krieghan

Is there a way to reproduce this without running a Redis instance? I get a ConnectionError.

nedbat avatar Aug 23 '23 10:08 nedbat

Oh wow, that's a solid point. I don't know of a way around it at the moment, but I can look into it. Thanks for the response!

krieghan avatar Aug 23 '23 12:08 krieghan

I've tried for a bit to reproduce this issue with asyncio streams (which, drilling down, seems to be where the issue comes up). I haven't been able to do it with just the naive echo client/server that python's documentation lays out. There's something here happening that seems specific to redis-py, and I don't know how to reproduce the issue without a redis instance running :/. I've left an inquiry on their project (basically the same information as here, but with a longer example included, as well) - I'm hoping they have some insights: https://github.com/redis/redis-py/issues/2912

krieghan avatar Aug 24 '23 14:08 krieghan

I saw that python released a new version for python 3.11.5. I've tried everything again with this new version. I still see the same behavior in coverage, but I am now seeing an additional traceback from redis as the script closes. I thought it might be related to this line of missing coverage. I'm including it here:

Exception ignored in: <function StreamWriter.del at 0x7fcd228adb20> Traceback (most recent call last): File "/usr/local/lib/python3.11/asyncio/streams.py", line 396, in del self.close() File "/usr/local/lib/python3.11/asyncio/streams.py", line 344, in close return self._transport.close() ^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/asyncio/selector_events.py", line 860, in close self._loop.call_soon(self._call_connection_lost, None) File "/usr/local/lib/python3.11/asyncio/base_events.py", line 761, in call_soon self._check_closed() File "/usr/local/lib/python3.11/asyncio/base_events.py", line 519, in _check_closed raise RuntimeError('Event loop is closed') RuntimeError: Event loop is closed

krieghan avatar Aug 25 '23 15:08 krieghan

Is there a way to reproduce this without running a Redis instance? I get a ConnectionError.

I'm seeing it using fakeredis, which is what I use to test redis code.

aw-was-here avatar Dec 08 '23 01:12 aw-was-here

I'm seeing it using fakeredis, which is what I use to test redis code.

Any chance you can give us a way to reproduce it?

nedbat avatar Dec 08 '23 01:12 nedbat

I'm seeing it using fakeredis, which is what I use to test redis code.

Any chance you can give us a way to reproduce it?

This repo was setup in a hurry so things in pyproject.toml aren't correct, but it should be good enough to demonstrate:

https://github.com/aw-was-here/redis-cov-test

Screen Shot 2023-12-07 at 11 05 02 PM

aw-was-here avatar Dec 08 '23 07:12 aw-was-here