locking.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import time
  2. import pytest
  3. from ..locking import get_id, TimeoutTimer, ExclusiveLock, UpgradableLock, LockRoster, \
  4. ADD, REMOVE, SHARED, EXCLUSIVE, LockTimeout
  5. ID1 = "foo", 1, 1
  6. ID2 = "bar", 2, 2
  7. def test_id():
  8. hostname, pid, tid = get_id()
  9. assert isinstance(hostname, str)
  10. assert isinstance(pid, int)
  11. assert isinstance(tid, int)
  12. assert len(hostname) > 0
  13. assert pid > 0
  14. class TestTimeoutTimer:
  15. def test_timeout(self):
  16. timeout = 0.5
  17. t = TimeoutTimer(timeout).start()
  18. assert not t.timed_out()
  19. time.sleep(timeout * 1.5)
  20. assert t.timed_out()
  21. def test_notimeout_sleep(self):
  22. timeout, sleep = None, 0.5
  23. t = TimeoutTimer(timeout, sleep).start()
  24. assert not t.timed_out_or_sleep()
  25. assert time.time() >= t.start_time + 1 * sleep
  26. assert not t.timed_out_or_sleep()
  27. assert time.time() >= t.start_time + 2 * sleep
  28. @pytest.fixture()
  29. def lockpath(tmpdir):
  30. return str(tmpdir.join('lock'))
  31. class TestExclusiveLock:
  32. def test_checks(self, lockpath):
  33. with ExclusiveLock(lockpath, timeout=1) as lock:
  34. assert lock.is_locked() and lock.by_me()
  35. def test_acquire_break_reacquire(self, lockpath):
  36. lock = ExclusiveLock(lockpath, id=ID1).acquire()
  37. lock.break_lock()
  38. with ExclusiveLock(lockpath, id=ID2):
  39. pass
  40. def test_timeout(self, lockpath):
  41. with ExclusiveLock(lockpath, id=ID1):
  42. with pytest.raises(LockTimeout):
  43. ExclusiveLock(lockpath, id=ID2, timeout=0.1).acquire()
  44. class TestUpgradableLock:
  45. def test_shared(self, lockpath):
  46. lock1 = UpgradableLock(lockpath, exclusive=False, id=ID1).acquire()
  47. lock2 = UpgradableLock(lockpath, exclusive=False, id=ID2).acquire()
  48. assert len(lock1._roster.get(SHARED)) == 2
  49. assert len(lock1._roster.get(EXCLUSIVE)) == 0
  50. lock1.release()
  51. lock2.release()
  52. def test_exclusive(self, lockpath):
  53. with UpgradableLock(lockpath, exclusive=True, id=ID1) as lock:
  54. assert len(lock._roster.get(SHARED)) == 0
  55. assert len(lock._roster.get(EXCLUSIVE)) == 1
  56. def test_upgrade(self, lockpath):
  57. with UpgradableLock(lockpath, exclusive=False) as lock:
  58. lock.upgrade()
  59. lock.upgrade() # NOP
  60. assert len(lock._roster.get(SHARED)) == 0
  61. assert len(lock._roster.get(EXCLUSIVE)) == 1
  62. def test_downgrade(self, lockpath):
  63. with UpgradableLock(lockpath, exclusive=True) as lock:
  64. lock.downgrade()
  65. lock.downgrade() # NOP
  66. assert len(lock._roster.get(SHARED)) == 1
  67. assert len(lock._roster.get(EXCLUSIVE)) == 0
  68. def test_break(self, lockpath):
  69. lock = UpgradableLock(lockpath, exclusive=True, id=ID1).acquire()
  70. lock.break_lock()
  71. assert len(lock._roster.get(SHARED)) == 0
  72. assert len(lock._roster.get(EXCLUSIVE)) == 0
  73. with UpgradableLock(lockpath, exclusive=True, id=ID2):
  74. pass
  75. def test_timeout(self, lockpath):
  76. with UpgradableLock(lockpath, exclusive=False, id=ID1):
  77. with pytest.raises(LockTimeout):
  78. UpgradableLock(lockpath, exclusive=True, id=ID2, timeout=0.1).acquire()
  79. with UpgradableLock(lockpath, exclusive=True, id=ID1):
  80. with pytest.raises(LockTimeout):
  81. UpgradableLock(lockpath, exclusive=False, id=ID2, timeout=0.1).acquire()
  82. with UpgradableLock(lockpath, exclusive=True, id=ID1):
  83. with pytest.raises(LockTimeout):
  84. UpgradableLock(lockpath, exclusive=True, id=ID2, timeout=0.1).acquire()
  85. @pytest.fixture()
  86. def rosterpath(tmpdir):
  87. return str(tmpdir.join('roster'))
  88. class TestLockRoster:
  89. def test_empty(self, rosterpath):
  90. roster = LockRoster(rosterpath)
  91. empty = roster.load()
  92. roster.save(empty)
  93. assert empty == {}
  94. def test_modify_get(self, rosterpath):
  95. roster1 = LockRoster(rosterpath, id=ID1)
  96. assert roster1.get(SHARED) == set()
  97. roster1.modify(SHARED, ADD)
  98. assert roster1.get(SHARED) == {ID1, }
  99. roster2 = LockRoster(rosterpath, id=ID2)
  100. roster2.modify(SHARED, ADD)
  101. assert roster2.get(SHARED) == {ID1, ID2, }
  102. roster1 = LockRoster(rosterpath, id=ID1)
  103. roster1.modify(SHARED, REMOVE)
  104. assert roster1.get(SHARED) == {ID2, }
  105. roster2 = LockRoster(rosterpath, id=ID2)
  106. roster2.modify(SHARED, REMOVE)
  107. assert roster2.get(SHARED) == set()