redis 3.3.0 returns different values than expected causing failing tests in test_fakeredis.py
isms opened this issue · 3 comments
Excluding health check failures covered by #240, there are still this unexpected results:
======================================================================
FAIL: test_ping (__main__.TestFakeStrictRedis)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fakeredis.py", line 2963, in test_ping
self.assertEqual(self.redis.execute_command('ping', 'test'), b'test')
AssertionError: False != b'test'
======================================================================
FAIL: test_zadd_minus_zero (__main__.TestFakeStrictRedis)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fakeredis.py", line 1786, in test_zadd_minus_zero
self.assertEqual(self.redis.execute_command('zscore', 'foo', 'a'), b'-0')
AssertionError: -0.0 != b'-0'
======================================================================
FAIL: test_ping (__main__.TestFakeStrictRedisDecodeResponses)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fakeredis.py", line 2963, in test_ping
self.assertEqual(self.redis.execute_command('ping', 'test'), b'test')
File "test_fakeredis.py", line 4271, in assertEqual
super(DecodeMixin, self).assertEqual(a, self._decode(b), msg)
AssertionError: False != 'test'
======================================================================
FAIL: test_zadd_minus_zero (__main__.TestFakeStrictRedisDecodeResponses)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fakeredis.py", line 1786, in test_zadd_minus_zero
self.assertEqual(self.redis.execute_command('zscore', 'foo', 'a'), b'-0')
File "test_fakeredis.py", line 4271, in assertEqual
super(DecodeMixin, self).assertEqual(a, self._decode(b), msg)
AssertionError: -0.0 != '-0'
======================================================================
FAIL: test_ping (__main__.TestRealStrictRedis)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fakeredis.py", line 2963, in test_ping
self.assertEqual(self.redis.execute_command('ping', 'test'), b'test')
AssertionError: False != b'test'
======================================================================
FAIL: test_zadd_minus_zero (__main__.TestRealStrictRedis)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fakeredis.py", line 1786, in test_zadd_minus_zero
self.assertEqual(self.redis.execute_command('zscore', 'foo', 'a'), b'-0')
AssertionError: -0.0 != b'-0'
======================================================================
FAIL: test_ping (__main__.TestRealStrictRedisDecodeResponses)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fakeredis.py", line 2963, in test_ping
self.assertEqual(self.redis.execute_command('ping', 'test'), b'test')
File "test_fakeredis.py", line 4271, in assertEqual
super(DecodeMixin, self).assertEqual(a, self._decode(b), msg)
AssertionError: False != 'test'
======================================================================
FAIL: test_zadd_minus_zero (__main__.TestRealStrictRedisDecodeResponses)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_fakeredis.py", line 1786, in test_zadd_minus_zero
self.assertEqual(self.redis.execute_command('zscore', 'foo', 'a'), b'-0')
File "test_fakeredis.py", line 4271, in assertEqual
super(DecodeMixin, self).assertEqual(a, self._decode(b), msg)
AssertionError: -0.0 != '-0'
----------------------------------------------------------------------
I think this is really two failures and I can confirm that these are both legitimate (albeit possibly not purposeful) redis-py API changes:
Running redis==3.3.2
>>> from redis import StrictRedis
>>> rc = StrictRedis()
>>> rc.execute_command('ping', 'test')
False
>>> rc.zadd('foo', {'a': -0.0})
1
>>> rc.zadd('foo', {'a': 0.0})
0
>>> rc.execute_command('zscore', 'foo', 'a')
-0.0
Running redis==3.2.1
>>> from redis import StrictRedis
>>> rc = StrictRedis()
>>> rc.execute_command('ping', 'test')
b'test'
>>> rc.zadd('foobarbaz', {'a': -0.0})
1
>>> rc.zadd('foobarbaz', {'a': 0.0})
0
>>> rc.execute_command('zscore', 'foobarbaz', 'a')
b'-0'
Neither of which is called out in the changelog: https://github.com/andymccurdy/redis-py/blob/master/CHANGES
Should we open issues in redis-py?
I think it is most likely this issue from the changelog:
Response callbacks are now case insensitive. This allows users that
call Redis.execute_command() directly to pass lower-case command
names and still get reasonable responses. #1168
So I think the short-term fix is to change the fakeredis tests to pass the command name in uppercase and to expect the redis 3.3+ behaviour (which should also be the 3.2- behaviour for uppercase command names).
Unfortunately this will probably weaken some of the tests because they're ensuring that the raw value (prior to the conversions done by redis-py) exactly matches real redis e.g. the sign of zero returned by zscore. That may prove important if anyone ever extends fakeredis to support other redis frontends like aioredis.
@bmerry I was thinking that would be the issue as well but it seems not. The changelog does indicate a change in support for lowercase commands but it reads as though it is expanding support for lowercase commands. I can confirm that the case doesn't matter using redis==3.3.2
:
>>> from redis import StrictRedis
>>> rc = StrictRedis()
>>> rc.execute_command("PING", "test")
False
>>> rc.ping()
True
>>> rc.execute_command("PING")
True
It certainly seems like they may have inadvertently removed support for the ping message functionality. Nothing really stands out in the diff as breaking this. I do see them using the message functionality here though: redis/redis-py@3.2.1...3.3.0#diff-085cbe85ef9bc2ad832d79163eb39172R3187
However the zadd
issue appears to be related to how responses are being parsed here Since we were using a lowercase command execution it wasn't being picked up for parsing but now it is:
using redis==3.3.2
>>> rc.zadd('foo', {'a': -0.0})
1
>>> rc.zadd('foo', {'a': 0.0})
0
>>> rc.execute_command('zscore', 'foo', 'a')
-0.0
>>> rc.execute_command('ZSCORE', 'foo', 'a')
-0.0
Using redis==3.2.1
>>> rc.zadd('foo', {'a': -0.0})
1
>>> rc.zadd('foo', {'a': 0.0})
0
>>> rc.execute_command('zscore', 'foo', 'a')
b'-0'
>>> rc.execute_command('ZSCORE', 'foo', 'a')
-0.0
So if we switch that test to using the uppercase command we can expect -0.0
for all versions above 3.0