From b7f0213565ab82c955f16aea5454293d7f151a74 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Mon, 16 Dec 2019 15:10:39 -0500 Subject: [PATCH] [wip] steps towards testing the node traversal behavior --- src/_zkapauthorizer/lease_maintenance.py | 7 +++ src/_zkapauthorizer/tests/strategies.py | 54 +++++++++++++++++++ .../tests/test_lease_maintenance.py | 43 +++++++++++++-- 3 files changed, 101 insertions(+), 3 deletions(-) diff --git a/src/_zkapauthorizer/lease_maintenance.py b/src/_zkapauthorizer/lease_maintenance.py index dfb251d..cf81a15 100644 --- a/src/_zkapauthorizer/lease_maintenance.py +++ b/src/_zkapauthorizer/lease_maintenance.py @@ -327,6 +327,10 @@ def lease_maintenance_service( def maintain_leases_from_root(root_node, storage_broker, secret_holder, min_lease_remaining, get_now): """ + An operation for ``lease_maintenance_service`` which visits ``root_node`` + and all its children and renews their leases if they have + ``min_lease_remaining`` or less on them. + :param IFilesystemNode root_node: A Tahoe-LAFS filesystem node to use as the root of a node hierarchy to be maintained. @@ -338,6 +342,9 @@ def maintain_leases_from_root(root_node, storage_broker, secret_holder, min_leas holder which can give us the lease renewal secrets needed to renew leases. + :param timedelta min_lease_remaining: The minimum amount of time remaining + to allow on a lease without renewing it. + :param get_now: A no-argument callable that returns the current time as a ``datetime`` instance. """ diff --git a/src/_zkapauthorizer/tests/strategies.py b/src/_zkapauthorizer/tests/strategies.py index f4d1ce5..4011e8c 100644 --- a/src/_zkapauthorizer/tests/strategies.py +++ b/src/_zkapauthorizer/tests/strategies.py @@ -583,3 +583,57 @@ def clocks(now=posix_safe_datetimes()): c.advance((when - _POSIX_EPOCH).total_seconds()) return c return now.map(clock_at_time) + + + + +@implementer(IFilesystemNode) +@attr.ib +class _LeafNode(object): + _storage_index = attr.ib() + + def get_storage_index(self): + return self._storage_index + + +def leaf_nodes(): + return storage_indexes().map(_LeafNode) + + +@implementer(IDirectoryNode) +@attr.s +class _DirectoryNode(object): + _storage_index = attr.ib() + _children = attr.ib() + + def list(self): + return succeed(self._children) + + +def directory_nodes(child_strategy): + """ + Build directory nodes with children drawn from the given strategy. + """ + children = dictionaries( + text(), + tuples( + child_strategy, + just({}), + ), + ) + return builds( + _DirectoryNode, + storage_indexes(), + children, + ) + + +def node_hierarchies(): + """ + Build hierarchies of ``IDirectoryNode`` and other ``IFilesystemNode`` + (incomplete) providers. + """ + return recursive( + leaf_nodes(), + directory_nodes, + ) diff --git a/src/_zkapauthorizer/tests/test_lease_maintenance.py b/src/_zkapauthorizer/tests/test_lease_maintenance.py index 670fd47..23f736b 100644 --- a/src/_zkapauthorizer/tests/test_lease_maintenance.py +++ b/src/_zkapauthorizer/tests/test_lease_maintenance.py @@ -34,6 +34,9 @@ from testtools import ( from testtools.matchers import ( Equals, ) +from testtools.twistedsupport import ( + succeeds, +) from hypothesis import ( given, note, @@ -61,9 +64,9 @@ from twisted.application.service import ( from allmydata.util.hashutil import ( CRYPTO_VAL_SIZE, ) -# from allmydata.client import ( -# SecretHolder, -# ) +from allmydata.client import ( + SecretHolder, +) from ..foolscap import ( ShareStat, @@ -76,10 +79,12 @@ from .matchers import ( from .strategies import ( storage_indexes, clocks, + node_hierarchies, ) from ..lease_maintenance import ( lease_maintenance_service, + maintain_leases_from_root, ) @@ -305,3 +310,35 @@ class LeaseMaintenanceServiceTests(TestCase): leases_maintained_at, Equals([datetime.utcfromtimestamp(clock.seconds())]), ) + + +class MaintainLeasesFromRootTests(TestCase): + """ + Tests for ``maintain_leases_from_root``. + """ + @given(node_hierarchies(), clocks()) + def test_visits_all_nodes(self, root_node, clock): + """ + The operation calls the specified visitor with every node from the root to + its deepest children. + """ + visited = [] + def visitor(node): + visited.append(node) + + storage_broker = DummyStorageBroker(clock, []) + secret_holder = SecretHolder(lease_secret, convergence_secret) + + operation = maintain_leases_from_root( + visitor, + root_node, + storage_broker, + secret_holder, + timedelta(days=3), + lambda: datetime.utcfromtimestamp(clock.seconds()), + ) + + self.assertThat( + operation(root_node), + succeeds(Always()), + ) -- GitLab