5353SOURCE = Path (__file__ ).resolve ().parent .parent / "src" / "babelqueue" / "redis_transport.py"
5454
5555
56+ def _reject_constant (name : str ) -> None :
57+ raise ValueError (f"{ name } is not JSON (RFC 8259)" )
58+
59+
5660def assert_poison_record (case : unittest .TestCase , record : str , body : str , queue : str ) -> None :
5761 """``record`` is the ADR-0035 poison DLQ record for ``body`` read from ``queue``."""
5862 parsed = json .loads (record )
@@ -66,7 +70,9 @@ def assert_poison_record(case: unittest.TestCase, record: str, body: str, queue:
6670 members = None
6771 if decoded is not None :
6872 try :
69- members = json .loads (decoded )
73+ # ADR-0035 section 1: a strict RFC 8259 object is spliced; NaN / Infinity / -Infinity
74+ # (which Python's json.loads accepts by default) make the body a wrapper case.
75+ members = json .loads (decoded , parse_constant = _reject_constant )
7076 except ValueError :
7177 members = None
7278 if decoded is None :
@@ -255,7 +261,7 @@ class PopScriptWithoutRedisTest(unittest.TestCase):
255261 def _lua (self ):
256262 try :
257263 from lupa import LuaRuntime
258- except ImportError : # pragma: no cover - lupa ships with the test extras
264+ except ImportError : # pragma: no cover - lupa is optional (it comes with fakeredis[lua])
259265 self .skipTest ("lupa is not installed" )
260266 return LuaRuntime (unpack_returned_tuples = True )
261267
@@ -294,6 +300,7 @@ def test_the_stub_models_the_bug_an_unguarded_encode_raises(self):
294300 "reserved = cjson.encode(decoded)" ,
295301 )
296302 self .assertNotEqual (unguarded , _POP )
303+ self ._lua () # skips when lupa is not installed (the matrix jobs install no Redis extras)
297304 from lupa import LuaError
298305
299306 with self .assertRaises (LuaError ):
@@ -1101,7 +1108,8 @@ def test_undecodable_body_is_dead_lettered_raw_on_first_delivery(self):
11011108 app = self .app (max_attempts = 3 , dead_letter = True )
11021109 app .register (URN , lambda data , meta : None )
11031110 self .assertEqual (app .consume (self .queue , max_messages = 1 , timeout = 0 ), 1 )
1104- self .assertEqual (self .client .lrange (f"{ self .queue } .dlq" , 0 , - 1 ), [garbage ])
1111+ (record ,) = self .client .lrange (f"{ self .queue } .dlq" , 0 , - 1 )
1112+ assert_poison_record (self , record , garbage , self .queue ) # ADR-0035 wrapper, not the raw body
11051113 self .assertEqual (self .client .llen (self .processing ), 0 )
11061114 self .assertEqual (self .client .zcard (self .deadlines ), 0 )
11071115 self .assertEqual (self .client .llen (self .queue ), 0 ) # never re-queued for a retry
@@ -1111,7 +1119,8 @@ def test_undecodable_body_is_dead_lettered_with_the_dlq_off_too(self):
11111119 app = self .app (max_attempts = 3 , dead_letter = False )
11121120 app .register (URN , lambda data , meta : None )
11131121 self .assertEqual (app .consume (self .queue , max_messages = 1 , timeout = 0 ), 1 )
1114- self .assertEqual (self .client .lrange (f"{ self .queue } .dlq" , 0 , - 1 ), ["[1]" ])
1122+ (record ,) = self .client .lrange (f"{ self .queue } .dlq" , 0 , - 1 )
1123+ assert_poison_record (self , record , "[1]" , self .queue )
11151124 self .assertEqual (self .client .llen (self .processing ), 0 )
11161125
11171126 def test_publish_with_headers_stores_a_frame_and_pop_unframes (self ):
0 commit comments