mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Move lock testing into the main test suite
This commit is contained in:
parent
cf293a6232
commit
666248454b
@ -242,174 +242,4 @@ class DebugRWLockWrapper(RWLockWrapper):
|
|||||||
print ('release done: thread id:', current_thread(), 'is_shared:', self._shlock.is_shared, 'is_exclusive:', self._shlock.is_exclusive, file=sys.stderr)
|
print ('release done: thread id:', current_thread(), 'is_shared:', self._shlock.is_shared, 'is_exclusive:', self._shlock.is_exclusive, file=sys.stderr)
|
||||||
print ('_' * 120, file=sys.stderr)
|
print ('_' * 120, file=sys.stderr)
|
||||||
|
|
||||||
# Tests {{{
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import time, random, unittest
|
|
||||||
from threading import Thread
|
|
||||||
|
|
||||||
class TestLock(unittest.TestCase):
|
|
||||||
"""Testcases for Lock classes."""
|
|
||||||
|
|
||||||
def test_owns_locks(self):
|
|
||||||
lock = SHLock()
|
|
||||||
self.assertFalse(lock.owns_lock())
|
|
||||||
lock.acquire(shared=True)
|
|
||||||
self.assertTrue(lock.owns_lock())
|
|
||||||
lock.release()
|
|
||||||
self.assertFalse(lock.owns_lock())
|
|
||||||
lock.acquire(shared=False)
|
|
||||||
self.assertTrue(lock.owns_lock())
|
|
||||||
lock.release()
|
|
||||||
self.assertFalse(lock.owns_lock())
|
|
||||||
|
|
||||||
done = []
|
|
||||||
def test():
|
|
||||||
if not lock.owns_lock():
|
|
||||||
done.append(True)
|
|
||||||
lock.acquire()
|
|
||||||
t = Thread(target=test)
|
|
||||||
t.daemon = True
|
|
||||||
t.start()
|
|
||||||
t.join(1)
|
|
||||||
self.assertEqual(len(done), 1)
|
|
||||||
lock.release()
|
|
||||||
|
|
||||||
def test_multithread_deadlock(self):
|
|
||||||
lock = SHLock()
|
|
||||||
def two_shared():
|
|
||||||
r = RWLockWrapper(lock)
|
|
||||||
with r:
|
|
||||||
time.sleep(0.2)
|
|
||||||
with r:
|
|
||||||
pass
|
|
||||||
def one_exclusive():
|
|
||||||
time.sleep(0.1)
|
|
||||||
w = RWLockWrapper(lock, is_shared=False)
|
|
||||||
with w:
|
|
||||||
pass
|
|
||||||
threads = [Thread(target=two_shared), Thread(target=one_exclusive)]
|
|
||||||
for t in threads:
|
|
||||||
t.daemon = True
|
|
||||||
t.start()
|
|
||||||
for t in threads:
|
|
||||||
t.join(5)
|
|
||||||
live = [t for t in threads if t.is_alive()]
|
|
||||||
self.assertListEqual(live, [], 'ShLock hung')
|
|
||||||
|
|
||||||
def test_upgrade(self):
|
|
||||||
lock = SHLock()
|
|
||||||
lock.acquire(shared=True)
|
|
||||||
self.assertRaises(LockingError, lock.acquire, shared=False)
|
|
||||||
lock.release()
|
|
||||||
|
|
||||||
def test_downgrade(self):
|
|
||||||
lock = SHLock()
|
|
||||||
lock.acquire(shared=False)
|
|
||||||
self.assertRaises(LockingError, lock.acquire, shared=True)
|
|
||||||
lock.release()
|
|
||||||
|
|
||||||
def test_recursive(self):
|
|
||||||
lock = SHLock()
|
|
||||||
lock.acquire(shared=True)
|
|
||||||
lock.acquire(shared=True)
|
|
||||||
self.assertEqual(lock.is_shared, 2)
|
|
||||||
lock.release()
|
|
||||||
lock.release()
|
|
||||||
self.assertFalse(lock.is_shared)
|
|
||||||
lock.acquire(shared=False)
|
|
||||||
lock.acquire(shared=False)
|
|
||||||
self.assertEqual(lock.is_exclusive, 2)
|
|
||||||
lock.release()
|
|
||||||
lock.release()
|
|
||||||
self.assertFalse(lock.is_exclusive)
|
|
||||||
|
|
||||||
def test_release(self):
|
|
||||||
lock = SHLock()
|
|
||||||
self.assertRaises(LockingError, lock.release)
|
|
||||||
|
|
||||||
def get_lock(shared):
|
|
||||||
lock.acquire(shared=shared)
|
|
||||||
time.sleep(1)
|
|
||||||
lock.release()
|
|
||||||
|
|
||||||
threads = [Thread(target=get_lock, args=(x,)) for x in (True,
|
|
||||||
False)]
|
|
||||||
for t in threads:
|
|
||||||
t.daemon = True
|
|
||||||
t.start()
|
|
||||||
self.assertRaises(LockingError, lock.release)
|
|
||||||
t.join(2)
|
|
||||||
self.assertFalse(t.is_alive())
|
|
||||||
self.assertFalse(lock.is_shared)
|
|
||||||
self.assertFalse(lock.is_exclusive)
|
|
||||||
|
|
||||||
def test_acquire(self):
|
|
||||||
lock = SHLock()
|
|
||||||
|
|
||||||
def get_lock(shared):
|
|
||||||
lock.acquire(shared=shared)
|
|
||||||
time.sleep(1)
|
|
||||||
lock.release()
|
|
||||||
|
|
||||||
shared = Thread(target=get_lock, args=(True,))
|
|
||||||
shared.daemon = True
|
|
||||||
shared.start()
|
|
||||||
time.sleep(0.1)
|
|
||||||
self.assertTrue(lock.acquire(shared=True, blocking=False))
|
|
||||||
lock.release()
|
|
||||||
self.assertFalse(lock.acquire(shared=False, blocking=False))
|
|
||||||
lock.acquire(shared=False)
|
|
||||||
self.assertFalse(shared.is_alive())
|
|
||||||
lock.release()
|
|
||||||
self.assertTrue(lock.acquire(shared=False, blocking=False))
|
|
||||||
lock.release()
|
|
||||||
|
|
||||||
exclusive = Thread(target=get_lock, args=(False,))
|
|
||||||
exclusive.daemon = True
|
|
||||||
exclusive.start()
|
|
||||||
time.sleep(0.1)
|
|
||||||
self.assertFalse(lock.acquire(shared=False, blocking=False))
|
|
||||||
self.assertFalse(lock.acquire(shared=True, blocking=False))
|
|
||||||
lock.acquire(shared=True)
|
|
||||||
self.assertFalse(exclusive.is_alive())
|
|
||||||
lock.release()
|
|
||||||
lock.acquire(shared=False)
|
|
||||||
lock.release()
|
|
||||||
lock.acquire(shared=True)
|
|
||||||
lock.release()
|
|
||||||
self.assertFalse(lock.is_shared)
|
|
||||||
self.assertFalse(lock.is_exclusive)
|
|
||||||
|
|
||||||
def test_contention(self):
|
|
||||||
lock = SHLock()
|
|
||||||
done = []
|
|
||||||
def lots_of_acquires():
|
|
||||||
for _ in xrange(1000):
|
|
||||||
shared = random.choice([True,False])
|
|
||||||
lock.acquire(shared=shared)
|
|
||||||
lock.acquire(shared=shared)
|
|
||||||
time.sleep(random.random() * 0.0001)
|
|
||||||
lock.release()
|
|
||||||
time.sleep(random.random() * 0.0001)
|
|
||||||
lock.acquire(shared=shared)
|
|
||||||
time.sleep(random.random() * 0.0001)
|
|
||||||
lock.release()
|
|
||||||
lock.release()
|
|
||||||
done.append(True)
|
|
||||||
threads = [Thread(target=lots_of_acquires) for _ in xrange(10)]
|
|
||||||
for t in threads:
|
|
||||||
t.daemon = True
|
|
||||||
t.start()
|
|
||||||
for t in threads:
|
|
||||||
t.join(20)
|
|
||||||
live = [t for t in threads if t.is_alive()]
|
|
||||||
self.assertListEqual(live, [], 'ShLock hung')
|
|
||||||
self.assertEqual(len(done), len(threads), 'SHLock locking failed')
|
|
||||||
self.assertFalse(lock.is_shared)
|
|
||||||
self.assertFalse(lock.is_exclusive)
|
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestLock)
|
|
||||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
174
src/calibre/db/tests/locking.py
Normal file
174
src/calibre/db/tests/locking.py
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
|
import time, random
|
||||||
|
from threading import Thread
|
||||||
|
from calibre.db.tests.base import BaseTest
|
||||||
|
from calibre.db.locking import SHLock, RWLockWrapper, LockingError
|
||||||
|
|
||||||
|
class TestLock(BaseTest):
|
||||||
|
"""Tests for db locking """
|
||||||
|
|
||||||
|
def test_owns_locks(self):
|
||||||
|
lock = SHLock()
|
||||||
|
self.assertFalse(lock.owns_lock())
|
||||||
|
lock.acquire(shared=True)
|
||||||
|
self.assertTrue(lock.owns_lock())
|
||||||
|
lock.release()
|
||||||
|
self.assertFalse(lock.owns_lock())
|
||||||
|
lock.acquire(shared=False)
|
||||||
|
self.assertTrue(lock.owns_lock())
|
||||||
|
lock.release()
|
||||||
|
self.assertFalse(lock.owns_lock())
|
||||||
|
|
||||||
|
done = []
|
||||||
|
def test():
|
||||||
|
if not lock.owns_lock():
|
||||||
|
done.append(True)
|
||||||
|
lock.acquire()
|
||||||
|
t = Thread(target=test)
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
t.join(1)
|
||||||
|
self.assertEqual(len(done), 1)
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
def test_multithread_deadlock(self):
|
||||||
|
lock = SHLock()
|
||||||
|
def two_shared():
|
||||||
|
r = RWLockWrapper(lock)
|
||||||
|
with r:
|
||||||
|
time.sleep(0.2)
|
||||||
|
with r:
|
||||||
|
pass
|
||||||
|
def one_exclusive():
|
||||||
|
time.sleep(0.1)
|
||||||
|
w = RWLockWrapper(lock, is_shared=False)
|
||||||
|
with w:
|
||||||
|
pass
|
||||||
|
threads = [Thread(target=two_shared), Thread(target=one_exclusive)]
|
||||||
|
for t in threads:
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
for t in threads:
|
||||||
|
t.join(5)
|
||||||
|
live = [t for t in threads if t.is_alive()]
|
||||||
|
self.assertListEqual(live, [], 'ShLock hung')
|
||||||
|
|
||||||
|
def test_upgrade(self):
|
||||||
|
lock = SHLock()
|
||||||
|
lock.acquire(shared=True)
|
||||||
|
self.assertRaises(LockingError, lock.acquire, shared=False)
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
def test_downgrade(self):
|
||||||
|
lock = SHLock()
|
||||||
|
lock.acquire(shared=False)
|
||||||
|
self.assertRaises(LockingError, lock.acquire, shared=True)
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
def test_recursive(self):
|
||||||
|
lock = SHLock()
|
||||||
|
lock.acquire(shared=True)
|
||||||
|
lock.acquire(shared=True)
|
||||||
|
self.assertEqual(lock.is_shared, 2)
|
||||||
|
lock.release()
|
||||||
|
lock.release()
|
||||||
|
self.assertFalse(lock.is_shared)
|
||||||
|
lock.acquire(shared=False)
|
||||||
|
lock.acquire(shared=False)
|
||||||
|
self.assertEqual(lock.is_exclusive, 2)
|
||||||
|
lock.release()
|
||||||
|
lock.release()
|
||||||
|
self.assertFalse(lock.is_exclusive)
|
||||||
|
|
||||||
|
def test_release(self):
|
||||||
|
lock = SHLock()
|
||||||
|
self.assertRaises(LockingError, lock.release)
|
||||||
|
|
||||||
|
def get_lock(shared):
|
||||||
|
lock.acquire(shared=shared)
|
||||||
|
time.sleep(1)
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
threads = [Thread(target=get_lock, args=(x,)) for x in (True,
|
||||||
|
False)]
|
||||||
|
for t in threads:
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
self.assertRaises(LockingError, lock.release)
|
||||||
|
t.join(2)
|
||||||
|
self.assertFalse(t.is_alive())
|
||||||
|
self.assertFalse(lock.is_shared)
|
||||||
|
self.assertFalse(lock.is_exclusive)
|
||||||
|
|
||||||
|
def test_acquire(self):
|
||||||
|
lock = SHLock()
|
||||||
|
|
||||||
|
def get_lock(shared):
|
||||||
|
lock.acquire(shared=shared)
|
||||||
|
time.sleep(1)
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
shared = Thread(target=get_lock, args=(True,))
|
||||||
|
shared.daemon = True
|
||||||
|
shared.start()
|
||||||
|
time.sleep(0.1)
|
||||||
|
self.assertTrue(lock.acquire(shared=True, blocking=False))
|
||||||
|
lock.release()
|
||||||
|
self.assertFalse(lock.acquire(shared=False, blocking=False))
|
||||||
|
lock.acquire(shared=False)
|
||||||
|
self.assertFalse(shared.is_alive())
|
||||||
|
lock.release()
|
||||||
|
self.assertTrue(lock.acquire(shared=False, blocking=False))
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
exclusive = Thread(target=get_lock, args=(False,))
|
||||||
|
exclusive.daemon = True
|
||||||
|
exclusive.start()
|
||||||
|
time.sleep(0.1)
|
||||||
|
self.assertFalse(lock.acquire(shared=False, blocking=False))
|
||||||
|
self.assertFalse(lock.acquire(shared=True, blocking=False))
|
||||||
|
lock.acquire(shared=True)
|
||||||
|
self.assertFalse(exclusive.is_alive())
|
||||||
|
lock.release()
|
||||||
|
lock.acquire(shared=False)
|
||||||
|
lock.release()
|
||||||
|
lock.acquire(shared=True)
|
||||||
|
lock.release()
|
||||||
|
self.assertFalse(lock.is_shared)
|
||||||
|
self.assertFalse(lock.is_exclusive)
|
||||||
|
|
||||||
|
def test_contention(self):
|
||||||
|
lock = SHLock()
|
||||||
|
done = []
|
||||||
|
def lots_of_acquires():
|
||||||
|
for _ in xrange(1000):
|
||||||
|
shared = random.choice([True,False])
|
||||||
|
lock.acquire(shared=shared)
|
||||||
|
lock.acquire(shared=shared)
|
||||||
|
time.sleep(random.random() * 0.0001)
|
||||||
|
lock.release()
|
||||||
|
time.sleep(random.random() * 0.0001)
|
||||||
|
lock.acquire(shared=shared)
|
||||||
|
time.sleep(random.random() * 0.0001)
|
||||||
|
lock.release()
|
||||||
|
lock.release()
|
||||||
|
done.append(True)
|
||||||
|
threads = [Thread(target=lots_of_acquires) for _ in xrange(10)]
|
||||||
|
for t in threads:
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
for t in threads:
|
||||||
|
t.join(20)
|
||||||
|
live = [t for t in threads if t.is_alive()]
|
||||||
|
self.assertListEqual(live, [], 'ShLock hung')
|
||||||
|
self.assertEqual(len(done), len(threads), 'SHLock locking failed')
|
||||||
|
self.assertFalse(lock.is_shared)
|
||||||
|
self.assertFalse(lock.is_exclusive)
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user