67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
"""
|
|
Tests for the Redis-backed stall dedup claim (replaces the old in-memory set).
|
|
|
|
- The first claim for a booking wins; a second within the window is refused.
|
|
- The consumer-side handled-claim behaves the same (redelivery guard).
|
|
- A Redis error fails OPEN (returns True) so a genuine stall is never muted.
|
|
|
|
Run:
|
|
python -m unittest discover -s tests
|
|
"""
|
|
import unittest
|
|
|
|
from agents.exception_agent import ExceptionAgent
|
|
|
|
|
|
class FakeRedisNX:
|
|
"""Minimal Redis with SET NX + TTL semantics."""
|
|
def __init__(self, raise_on_set=False):
|
|
self.store = {}
|
|
self.raise_on_set = raise_on_set
|
|
self.set_calls = []
|
|
|
|
async def set(self, key, val, ex=None, nx=False):
|
|
if self.raise_on_set:
|
|
raise RuntimeError("redis down")
|
|
self.set_calls.append((key, ex, nx))
|
|
if nx and key in self.store:
|
|
return None # already claimed
|
|
self.store[key] = val
|
|
return True
|
|
|
|
|
|
def make_agent(redis):
|
|
agent = ExceptionAgent.__new__(ExceptionAgent) # skip heavy __init__
|
|
agent._redis = redis
|
|
return agent
|
|
|
|
|
|
class TestStallDedup(unittest.IsolatedAsyncioTestCase):
|
|
async def test_first_alert_claim_wins_second_refused(self):
|
|
agent = make_agent(FakeRedisNX())
|
|
self.assertTrue(await agent._claim_stall("b1")) # first wins
|
|
self.assertFalse(await agent._claim_stall("b1")) # duplicate refused
|
|
self.assertTrue(await agent._claim_stall("b2")) # different booking ok
|
|
|
|
async def test_claim_sets_ttl_and_nx(self):
|
|
redis = FakeRedisNX()
|
|
await make_agent(redis)._claim_stall("b9")
|
|
key, ex, nx = redis.set_calls[0]
|
|
self.assertEqual(key, "stall_notified:b9")
|
|
self.assertTrue(nx)
|
|
self.assertEqual(ex, 21600)
|
|
|
|
async def test_handled_claim_guards_redelivery(self):
|
|
agent = make_agent(FakeRedisNX())
|
|
self.assertTrue(await agent._claim_stall_handled("b1"))
|
|
self.assertFalse(await agent._claim_stall_handled("b1"))
|
|
|
|
async def test_redis_error_fails_open(self):
|
|
agent = make_agent(FakeRedisNX(raise_on_set=True))
|
|
self.assertTrue(await agent._claim_stall("b1")) # must not mute a real stall
|
|
self.assertTrue(await agent._claim_stall_handled("b1"))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|