You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
343 lines
9.1 KiB
343 lines
9.1 KiB
import datetime
|
|
import uuid
|
|
|
|
from kazoo.recipe.lease import NonBlockingLease
|
|
from kazoo.recipe.lease import MultiNonBlockingLease
|
|
|
|
from kazoo.testing import KazooTestCase
|
|
|
|
|
|
class MockClock(object):
|
|
def __init__(self, epoch=0):
|
|
self.epoch = epoch
|
|
|
|
def forward(self, seconds):
|
|
self.epoch += seconds
|
|
|
|
def __call__(self):
|
|
return datetime.datetime.utcfromtimestamp(self.epoch)
|
|
|
|
|
|
class KazooLeaseTests(KazooTestCase):
|
|
def setUp(self):
|
|
super(KazooLeaseTests, self).setUp()
|
|
self.client2 = self._get_client(timeout=0.8)
|
|
self.client2.start()
|
|
self.client3 = self._get_client(timeout=0.8)
|
|
self.client3.start()
|
|
self.path = "/" + uuid.uuid4().hex
|
|
self.clock = MockClock(10)
|
|
|
|
def tearDown(self):
|
|
for cl in [self.client2, self.client3]:
|
|
if cl.connected:
|
|
cl.stop()
|
|
cl.close()
|
|
del self.client2
|
|
del self.client3
|
|
|
|
|
|
class NonBlockingLeaseTests(KazooLeaseTests):
|
|
def test_renew(self):
|
|
# Use client convenience method here to test it at least once. Use
|
|
# class directly in
|
|
# other tests in order to get better IDE support.
|
|
lease = self.client.NonBlockingLease(
|
|
self.path, datetime.timedelta(seconds=3), utcnow=self.clock
|
|
)
|
|
assert lease
|
|
assert lease.obtained is True
|
|
|
|
self.clock.forward(2)
|
|
renewed_lease = self.client.NonBlockingLease(
|
|
self.path, datetime.timedelta(seconds=3), utcnow=self.clock
|
|
)
|
|
assert renewed_lease
|
|
|
|
def test_busy(self):
|
|
lease = NonBlockingLease(
|
|
self.client,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
utcnow=self.clock,
|
|
)
|
|
assert lease
|
|
|
|
self.clock.forward(2)
|
|
foreigner_lease = NonBlockingLease(
|
|
self.client2,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
identifier="some.other.host",
|
|
utcnow=self.clock,
|
|
)
|
|
assert not foreigner_lease
|
|
assert foreigner_lease.obtained is False
|
|
|
|
def test_overtake(self):
|
|
lease = NonBlockingLease(
|
|
self.client,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
utcnow=self.clock,
|
|
)
|
|
assert lease
|
|
|
|
self.clock.forward(4)
|
|
foreigner_lease = NonBlockingLease(
|
|
self.client2,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
identifier="some.other.host",
|
|
utcnow=self.clock,
|
|
)
|
|
assert foreigner_lease
|
|
|
|
def test_renew_no_overtake(self):
|
|
lease = self.client.NonBlockingLease(
|
|
self.path, datetime.timedelta(seconds=3), utcnow=self.clock
|
|
)
|
|
assert lease
|
|
assert lease.obtained is True
|
|
|
|
self.clock.forward(2)
|
|
renewed_lease = self.client.NonBlockingLease(
|
|
self.path, datetime.timedelta(seconds=3), utcnow=self.clock
|
|
)
|
|
assert renewed_lease
|
|
|
|
self.clock.forward(2)
|
|
foreigner_lease = NonBlockingLease(
|
|
self.client2,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
identifier="some.other.host",
|
|
utcnow=self.clock,
|
|
)
|
|
assert not foreigner_lease
|
|
|
|
def test_overtaker_renews(self):
|
|
lease = NonBlockingLease(
|
|
self.client,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
utcnow=self.clock,
|
|
)
|
|
assert lease
|
|
|
|
self.clock.forward(4)
|
|
foreigner_lease = NonBlockingLease(
|
|
self.client2,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
identifier="some.other.host",
|
|
utcnow=self.clock,
|
|
)
|
|
assert foreigner_lease
|
|
|
|
self.clock.forward(2)
|
|
foreigner_renew = NonBlockingLease(
|
|
self.client2,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
identifier="some.other.host",
|
|
utcnow=self.clock,
|
|
)
|
|
assert foreigner_renew
|
|
|
|
def test_overtake_refuse_first(self):
|
|
lease = NonBlockingLease(
|
|
self.client,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
utcnow=self.clock,
|
|
)
|
|
assert lease
|
|
|
|
self.clock.forward(4)
|
|
foreigner_lease = NonBlockingLease(
|
|
self.client2,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
identifier="some.other.host",
|
|
utcnow=self.clock,
|
|
)
|
|
assert foreigner_lease
|
|
|
|
self.clock.forward(2)
|
|
first_again_lease = NonBlockingLease(
|
|
self.client,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
utcnow=self.clock,
|
|
)
|
|
assert not first_again_lease
|
|
|
|
def test_old_version(self):
|
|
# Skip to a future version
|
|
NonBlockingLease._version += 1
|
|
lease = NonBlockingLease(
|
|
self.client,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
utcnow=self.clock,
|
|
)
|
|
assert lease
|
|
|
|
# Then back to today.
|
|
NonBlockingLease._version -= 1
|
|
self.clock.forward(4)
|
|
foreigner_lease = NonBlockingLease(
|
|
self.client2,
|
|
self.path,
|
|
datetime.timedelta(seconds=3),
|
|
identifier="some.other.host",
|
|
utcnow=self.clock,
|
|
)
|
|
# Since a newer version wrote the lease file, the lease is not taken.
|
|
assert not foreigner_lease
|
|
|
|
|
|
class MultiNonBlockingLeaseTest(KazooLeaseTests):
|
|
def test_1_renew(self):
|
|
ls = self.client.MultiNonBlockingLease(
|
|
1, self.path, datetime.timedelta(seconds=4), utcnow=self.clock
|
|
)
|
|
assert ls
|
|
self.clock.forward(2)
|
|
ls2 = MultiNonBlockingLease(
|
|
self.client,
|
|
1,
|
|
self.path,
|
|
datetime.timedelta(seconds=4),
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls2
|
|
|
|
def test_1_reject(self):
|
|
ls = MultiNonBlockingLease(
|
|
self.client,
|
|
1,
|
|
self.path,
|
|
datetime.timedelta(seconds=4),
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls
|
|
self.clock.forward(2)
|
|
ls2 = MultiNonBlockingLease(
|
|
self.client2,
|
|
1,
|
|
self.path,
|
|
datetime.timedelta(seconds=4),
|
|
identifier="some.other.host",
|
|
utcnow=self.clock,
|
|
)
|
|
assert not ls2
|
|
|
|
def test_2_renew(self):
|
|
ls = MultiNonBlockingLease(
|
|
self.client,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=7),
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls
|
|
self.clock.forward(2)
|
|
ls2 = MultiNonBlockingLease(
|
|
self.client2,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=7),
|
|
identifier="host2",
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls2
|
|
self.clock.forward(2)
|
|
ls3 = MultiNonBlockingLease(
|
|
self.client,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=7),
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls3
|
|
self.clock.forward(2)
|
|
ls4 = MultiNonBlockingLease(
|
|
self.client2,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=7),
|
|
identifier="host2",
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls4
|
|
|
|
def test_2_reject(self):
|
|
ls = MultiNonBlockingLease(
|
|
self.client,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=7),
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls
|
|
self.clock.forward(2)
|
|
ls2 = MultiNonBlockingLease(
|
|
self.client2,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=7),
|
|
identifier="host2",
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls2
|
|
self.clock.forward(2)
|
|
ls3 = MultiNonBlockingLease(
|
|
self.client3,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=7),
|
|
identifier="host3",
|
|
utcnow=self.clock,
|
|
)
|
|
assert not ls3
|
|
|
|
def test_2_handover(self):
|
|
ls = MultiNonBlockingLease(
|
|
self.client,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=4),
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls
|
|
self.clock.forward(2)
|
|
ls2 = MultiNonBlockingLease(
|
|
self.client2,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=4),
|
|
identifier="host2",
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls2
|
|
self.clock.forward(3)
|
|
ls3 = MultiNonBlockingLease(
|
|
self.client3,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=4),
|
|
identifier="host3",
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls3
|
|
self.clock.forward(2)
|
|
ls4 = MultiNonBlockingLease(
|
|
self.client,
|
|
2,
|
|
self.path,
|
|
datetime.timedelta(seconds=4),
|
|
utcnow=self.clock,
|
|
)
|
|
assert ls4
|