33# pylint:disable=redefined-outer-name
44
55import asyncio
6+ import datetime
67
78import pytest
89import redis
910import redis .asyncio as aioredis
11+ from faker import Faker
12+ from redis .asyncio .lock import Lock
13+ from servicelib .background_task import periodic_task
1014
1115
12- async def test_aioredis (redis_client : aioredis .Redis ):
13- await redis_client .set ("my-key" , "value" )
14- val = await redis_client .get ("my-key" )
15- assert val == "value"
16+ async def test_aioredis (redis_client : aioredis .Redis , faker : Faker ):
17+ key = faker .pystr ()
18+ value = faker .pystr ()
19+ await redis_client .set (key , value )
20+ val = await redis_client .get (key )
21+ assert val == value
1622
1723
18- async def test_redlocks_features (redis_client : aioredis .Redis ):
19- # Check wether a resourece acquired by any other redlock instance:
20- lock = redis_client .lock ("resource_name" )
24+ async def test_lock_acquisition (redis_client : aioredis .Redis , faker : Faker ):
25+ lock_name = faker . pystr ()
26+ lock = redis_client .lock (lock_name )
2127 assert not await lock .locked ()
2228
2329 # Try to acquire the lock:
2430 lock_acquired = await lock .acquire (blocking = False )
25- assert lock_acquired , "Lock not acquired"
31+ assert lock_acquired is True
32+ assert await lock .locked () is True
33+ assert await lock .owned () is True
34+ with pytest .raises (redis .exceptions .LockError ):
35+ # a lock with no timeout cannot be reacquired
36+ await lock .reacquire ()
37+ with pytest .raises (redis .exceptions .LockError ):
38+ # a lock with no timeout cannot be extended
39+ await lock .extend (2 )
40+
41+ # try to acquire the lock a second time
42+ same_lock = redis_client .lock (lock_name )
43+ assert await same_lock .locked () is True
44+ assert await same_lock .owned () is False
45+ assert await same_lock .acquire (blocking = False ) is False
46+
47+ # now release the lock
2648 await lock .release ()
2749 assert not await lock .locked ()
2850 assert not await lock .owned ()
2951
30- # use as context manager
52+
53+ async def test_lock_context_manager (redis_client : aioredis .Redis , faker : Faker ):
54+ lock_name = faker .pystr ()
55+ lock = redis_client .lock (lock_name )
56+ assert not await lock .locked ()
57+
3158 async with lock :
3259 assert await lock .locked ()
3360 assert await lock .owned ()
34- # a lock with no timeout cannot be extended
3561 with pytest .raises (redis .exceptions .LockError ):
62+ # a lock with no timeout cannot be reacquired
63+ await lock .reacquire ()
64+
65+ with pytest .raises (redis .exceptions .LockError ):
66+ # a lock with no timeout cannot be extended
3667 await lock .extend (2 )
68+
3769 # try to acquire the lock a second time
38- same_lock = redis_client .lock ("resource_name" , blocking_timeout = 1 )
70+ same_lock = redis_client .lock (lock_name , blocking_timeout = 1 )
3971 assert await same_lock .locked ()
4072 assert not await same_lock .owned ()
4173 assert await same_lock .acquire () == False
@@ -44,13 +76,46 @@ async def test_redlocks_features(redis_client: aioredis.Redis):
4476 ...
4577 assert not await lock .locked ()
4678
47- # now create a lock with a ttl
48- ttl_lock = redis_client .lock ("ttl_resource" , timeout = 2 , blocking_timeout = 1 )
79+
80+ @pytest .fixture
81+ def lock_timeout () -> datetime .timedelta :
82+ return datetime .timedelta (seconds = 2 )
83+
84+
85+ async def test_lock_with_ttl (
86+ redis_client : aioredis .Redis , faker : Faker , lock_timeout : datetime .timedelta
87+ ):
88+ ttl_lock = redis_client .lock (faker .pystr (), timeout = lock_timeout .total_seconds ())
4989 assert not await ttl_lock .locked ()
90+
5091 with pytest .raises (redis .exceptions .LockNotOwnedError ):
5192 # this raises as the lock is lost
5293 async with ttl_lock :
5394 assert await ttl_lock .locked ()
5495 assert await ttl_lock .owned ()
55- await asyncio .sleep (3 )
96+ await asyncio .sleep (2 * lock_timeout . total_seconds () )
5697 assert not await ttl_lock .locked ()
98+
99+
100+ async def test_lock_with_auto_extent (
101+ redis_client : aioredis .Redis , faker : Faker , lock_timeout : datetime .timedelta
102+ ):
103+ ttl_lock = redis_client .lock (faker .pystr (), timeout = lock_timeout .total_seconds ())
104+ assert not await ttl_lock .locked ()
105+
106+ async def _auto_extend_lock (lock : Lock ) -> None :
107+ assert await lock .reacquire () is True
108+
109+ async with ttl_lock , periodic_task (
110+ _auto_extend_lock ,
111+ interval = 0.6 * lock_timeout ,
112+ task_name = f"{ ttl_lock .name } _auto_extend" ,
113+ lock = ttl_lock ,
114+ ):
115+ assert await ttl_lock .locked () is True
116+ assert await ttl_lock .owned () is True
117+ await asyncio .sleep (5 * lock_timeout .total_seconds ())
118+ assert await ttl_lock .locked () is True
119+ assert await ttl_lock .owned () is True
120+ assert await ttl_lock .locked () is False
121+ assert await ttl_lock .owned () is False
0 commit comments