diff options
author | Andy McCurdy <andy@andymccurdy.com> | 2014-06-01 08:12:47 -0700 |
---|---|---|
committer | Andy McCurdy <andy@andymccurdy.com> | 2014-06-01 08:14:27 -0700 |
commit | b36ab87d22dc9b4f0109d17f6f3c7740bb48a7fe (patch) | |
tree | 1f53a914aa23a569da2b39f93e7bdf40f02ed2a2 /tests/test_lock.py | |
parent | be6e501d046c9fb7ef86a47ec3b276a22997e900 (diff) | |
download | redis-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.py | 124 |
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) |