summaryrefslogtreecommitdiff
path: root/tests/test_lock.py
diff options
context:
space:
mode:
authorAndy McCurdy <andy@andymccurdy.com>2014-06-01 08:12:47 -0700
committerAndy McCurdy <andy@andymccurdy.com>2014-06-01 08:14:27 -0700
commitb36ab87d22dc9b4f0109d17f6f3c7740bb48a7fe (patch)
tree1f53a914aa23a569da2b39f93e7bdf40f02ed2a2 /tests/test_lock.py
parentbe6e501d046c9fb7ef86a47ec3b276a22997e900 (diff)
downloadredis-py-b36ab87d22dc9b4f0109d17f6f3c7740bb48a7fe.tar.gz
updated Lock class:
* now uses unique string tokens to claim lock ownership * added extend() method to extend the timeout on an already acquired lock
Diffstat (limited to 'tests/test_lock.py')
-rw-r--r--tests/test_lock.py124
1 files changed, 85 insertions, 39 deletions
diff --git a/tests/test_lock.py b/tests/test_lock.py
index a31f5f1..304dbe1 100644
--- a/tests/test_lock.py
+++ b/tests/test_lock.py
@@ -2,60 +2,106 @@ from __future__ import with_statement
import pytest
import time
-from redis.lock import Lock, LockError
+from redis.lock import LockError
class TestLock(object):
- def test_lock(self, r):
- lock = r.lock('foo')
- assert lock.acquire()
- assert r['foo'] == str(Lock.LOCK_FOREVER).encode()
+ def test_lock(self, sr):
+ lock = sr.lock('foo')
+ assert lock.acquire(blocking=False)
+ assert sr.get('foo') == lock.token
+ assert sr.ttl('foo') == -1
lock.release()
- assert r.get('foo') is None
+ assert sr.get('foo') is None
- def test_competing_locks(self, r):
- lock1 = r.lock('foo')
- lock2 = r.lock('foo')
- assert lock1.acquire()
+ def test_competing_locks(self, sr):
+ lock1 = sr.lock('foo')
+ lock2 = sr.lock('foo')
+ assert lock1.acquire(blocking=False)
assert not lock2.acquire(blocking=False)
lock1.release()
- assert lock2.acquire()
+ assert lock2.acquire(blocking=False)
assert not lock1.acquire(blocking=False)
lock2.release()
- def test_timeouts(self, r):
- lock1 = r.lock('foo', timeout=1)
- lock2 = r.lock('foo')
- assert lock1.acquire()
- now = time.time()
- assert now < lock1.acquired_until < now + 1
- assert lock1.acquired_until == float(r['foo'])
- assert not lock2.acquire(blocking=False)
- time.sleep(2) # need to wait up to 2 seconds for lock to timeout
- assert lock2.acquire(blocking=False)
- lock2.release()
+ def test_timeout(self, sr):
+ lock = sr.lock('foo', timeout=10)
+ assert lock.acquire(blocking=False)
+ assert 0 < sr.ttl('foo') <= 10
+ lock.release()
- def test_non_blocking(self, r):
- lock1 = r.lock('foo')
+ def test_float_timeout(self, sr):
+ lock = sr.lock('foo', timeout=9.5)
+ assert lock.acquire(blocking=False)
+ assert 0 < sr.pttl('foo') <= 9500
+ lock.release()
+
+ def test_blocking_timeout(self, sr):
+ lock1 = sr.lock('foo')
assert lock1.acquire(blocking=False)
- assert lock1.acquired_until
+ lock2 = sr.lock('foo', blocking_timeout=0.2)
+ start = time.time()
+ assert not lock2.acquire()
+ assert (time.time() - start) > 0.2
lock1.release()
- assert lock1.acquired_until is None
-
- def test_context_manager(self, r):
- with r.lock('foo'):
- assert r['foo'] == str(Lock.LOCK_FOREVER).encode()
- assert r.get('foo') is None
- def test_float_timeout(self, r):
- lock1 = r.lock('foo', timeout=1.5)
- lock2 = r.lock('foo', timeout=1.5)
- assert lock1.acquire()
- assert not lock2.acquire(blocking=False)
- lock1.release()
+ def test_context_manager(self, sr):
+ with sr.lock('foo') as lock:
+ assert sr.get('foo') == lock.token
+ assert sr.get('foo') is None
- def test_high_sleep_raises_error(self, r):
+ def test_high_sleep_raises_error(self, sr):
"If sleep is higher than timeout, it should raise an error"
with pytest.raises(LockError):
- r.lock('foo', timeout=1, sleep=2)
+ sr.lock('foo', timeout=1, sleep=2)
+
+ def test_releasing_unlocked_lock_raises_error(self, sr):
+ lock = sr.lock('foo')
+ with pytest.raises(LockError):
+ lock.release()
+
+ def test_releasing_lock_no_longer_owned_raises_error(self, sr):
+ lock = sr.lock('foo')
+ lock.acquire(blocking=False)
+ # manually change the token
+ sr.set('foo', 'a')
+ with pytest.raises(LockError):
+ lock.release()
+ # even though we errored, the token is still cleared
+ assert lock.token is None
+
+ def test_extend_lock(self, sr):
+ lock = sr.lock('foo', timeout=10)
+ assert lock.acquire(blocking=True)
+ assert 0 < sr.pttl('foo') <= 10000
+ assert lock.extend(10)
+ assert 10000 < sr.pttl('foo') < 20000
+ lock.release()
+
+ def test_extend_lock_float(self, sr):
+ lock = sr.lock('foo', timeout=10.0)
+ assert lock.acquire(blocking=True)
+ assert 0 < sr.pttl('foo') <= 10000
+ assert lock.extend(10.0)
+ assert 10000 < sr.pttl('foo') < 20000
+ lock.release()
+
+ def test_extending_unlocked_lock_raises_error(self, sr):
+ lock = sr.lock('foo', timeout=10)
+ with pytest.raises(LockError):
+ lock.extend(10)
+
+ def test_extending_lock_with_no_timeout_raises_error(self, sr):
+ lock = sr.lock('foo')
+ assert lock.acquire(blocking=False)
+ with pytest.raises(LockError):
+ lock.extend(10)
+ lock.release()
+
+ def test_extending_lock_no_longer_owned_raises_error(self, sr):
+ lock = sr.lock('foo')
+ assert lock.acquire(blocking=False)
+ sr.set('foo', 'a')
+ with pytest.raises(LockError):
+ lock.extend(10)