From 17d66c052bfd08f8d00301cc431a83c70f05db0f Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Tue, 15 Sep 2020 11:33:28 -0400 Subject: [PATCH] Thread a reactor through PaymentController so tests don't use the real one --- src/_zkapauthorizer/_plugin.py | 6 ++++-- src/_zkapauthorizer/controller.py | 10 +++++++--- src/_zkapauthorizer/resource.py | 19 +++++++++++++++++-- src/_zkapauthorizer/tests/fixtures.py | 5 ++++- .../tests/test_client_resource.py | 2 ++ src/_zkapauthorizer/tests/test_controller.py | 13 +++++++++++++ src/_zkapauthorizer/tests/test_plugin.py | 10 +++++++++- 7 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/_zkapauthorizer/_plugin.py b/src/_zkapauthorizer/_plugin.py index 98eb8da..1b8874e 100644 --- a/src/_zkapauthorizer/_plugin.py +++ b/src/_zkapauthorizer/_plugin.py @@ -185,7 +185,7 @@ class ZKAPAuthorizer(object): ) - def get_client_resource(self, node_config, default_token_count=None): + def get_client_resource(self, node_config, default_token_count=None, reactor=None): """ Get an ``IZKAPRoot`` for the given node configuration. @@ -197,12 +197,14 @@ class ZKAPAuthorizer(object): This is only used if a number of tokens isn't specified at the point of redemption. """ - from twisted.internet import reactor + if reactor is None: + from twisted.internet import reactor return resource_from_configuration( node_config, store=self._get_store(node_config), redeemer=self._get_redeemer(node_config, None, reactor), default_token_count=default_token_count, + clock=reactor, ) diff --git a/src/_zkapauthorizer/controller.py b/src/_zkapauthorizer/controller.py index 96d7074..15d8395 100644 --- a/src/_zkapauthorizer/controller.py +++ b/src/_zkapauthorizer/controller.py @@ -712,6 +712,9 @@ class PaymentController(object): TODO: Retrieve this value from the PaymentServer or from the ZKAPAuthorizer configuration instead of just hard-coding a duplicate value in this implementation. + + :ivar IReactorTime _clock: The reactor to use for scheduling redemption + retries. """ _log = Logger() @@ -721,9 +724,7 @@ class PaymentController(object): num_redemption_groups = attr.ib(default=16) - _clock = attr.ib( - default=attr.Factory(partial(namedAny, "twisted.internet.reactor")), - ) + _clock = attr.ib(default=None) _error = attr.ib(default=attr.Factory(dict)) _unpaid = attr.ib(default=attr.Factory(dict)) @@ -735,6 +736,9 @@ class PaymentController(object): This is an initialization-time hook called by attrs. """ + if self._clock is None: + self._clock = namedAny("twisted.internet.reactor") + self._check_pending_vouchers() # Also start a time-based polling loop to retry redemption of vouchers # in retryable error states. diff --git a/src/_zkapauthorizer/resource.py b/src/_zkapauthorizer/resource.py index 96dc29d..f8fa7a9 100644 --- a/src/_zkapauthorizer/resource.py +++ b/src/_zkapauthorizer/resource.py @@ -91,7 +91,13 @@ class IZKAPRoot(IResource): controller = Attribute("The ``PaymentController`` used by this resource tree.") -def from_configuration(node_config, store, redeemer=None, default_token_count=None): +def from_configuration( + node_config, + store, + redeemer=None, + default_token_count=None, + clock=None, +): """ Instantiate the plugin root resource using data from its configuration section, **storageclient.plugins.privatestorageio-zkapauthz-v1**, in the @@ -108,6 +114,10 @@ def from_configuration(node_config, store, redeemer=None, default_token_count=No :param IRedeemer redeemer: The voucher redeemer to use. If ``None`` a sensible one is constructed. + :param default_token_count: See ``PaymentController.default_token_count``. + + :param clock: See ``PaymentController._clock``. + :return IZKAPRoot: The root of the resource hierarchy presented by the client side of the plugin. """ @@ -120,7 +130,12 @@ def from_configuration(node_config, store, redeemer=None, default_token_count=No ) if default_token_count is None: default_token_count = NUM_TOKENS - controller = PaymentController(store, redeemer, default_token_count) + controller = PaymentController( + store, + redeemer, + default_token_count, + clock=clock, + ) calculator = PriceCalculator( get_configured_shares_needed(node_config), diff --git a/src/_zkapauthorizer/tests/fixtures.py b/src/_zkapauthorizer/tests/fixtures.py index 00be5b2..35aadae 100644 --- a/src/_zkapauthorizer/tests/fixtures.py +++ b/src/_zkapauthorizer/tests/fixtures.py @@ -30,7 +30,9 @@ from fixtures import ( from twisted.python.filepath import ( FilePath, ) - +from twisted.internet.task import ( + Clock, +) from allmydata.storage.server import ( StorageServer, ) @@ -125,6 +127,7 @@ class ConfiglessMemoryVoucherStore(Fixture): # minimum token count requirement (can't have fewer tokens # than groups). num_redemption_groups=1, + clock=Clock(), ).redeem( voucher, ) diff --git a/src/_zkapauthorizer/tests/test_client_resource.py b/src/_zkapauthorizer/tests/test_client_resource.py index e13d474..6b38da7 100644 --- a/src/_zkapauthorizer/tests/test_client_resource.py +++ b/src/_zkapauthorizer/tests/test_client_resource.py @@ -103,6 +103,7 @@ from twisted.internet.defer import ( ) from twisted.internet.task import ( Cooperator, + Clock, ) from twisted.web.http import ( OK, @@ -278,6 +279,7 @@ def root_from_config(config, now): memory_connect, ), default_token_count=NUM_TOKENS, + clock=Clock(), ) diff --git a/src/_zkapauthorizer/tests/test_controller.py b/src/_zkapauthorizer/tests/test_controller.py index bec922b..25568d0 100644 --- a/src/_zkapauthorizer/tests/test_controller.py +++ b/src/_zkapauthorizer/tests/test_controller.py @@ -73,6 +73,9 @@ from twisted.python.url import ( from twisted.internet.defer import ( fail, ) +from twisted.internet.task import ( + Clock, +) from twisted.web.iweb import ( IAgent, ) @@ -228,6 +231,7 @@ class PaymentControllerTests(TestCase): store, DummyRedeemer(), default_token_count=100, + clock=Clock(), ) self.assertThat( @@ -263,6 +267,7 @@ class PaymentControllerTests(TestCase): store, NonRedeemer(), default_token_count=100, + clock=Clock(), ) self.assertThat( controller.redeem(voucher), @@ -299,6 +304,7 @@ class PaymentControllerTests(TestCase): # Require more success than we're going to get so it doesn't # finish. num_redemption_groups=counter, + clock=Clock(), ) self.assertThat( @@ -353,6 +359,7 @@ class PaymentControllerTests(TestCase): ), default_token_count=num_tokens, num_redemption_groups=num_redemption_groups, + clock=Clock(), ) self.assertThat( controller.redeem(voucher), @@ -378,6 +385,7 @@ class PaymentControllerTests(TestCase): # The number of redemption groups must not change for # redemption of a particular voucher. num_redemption_groups=num_redemption_groups, + clock=Clock(), ) first_try() @@ -412,6 +420,7 @@ class PaymentControllerTests(TestCase): redeemer, default_token_count=num_tokens, num_redemption_groups=num_redemption_groups, + clock=Clock(), ) self.assertThat( controller.redeem(voucher), @@ -435,6 +444,7 @@ class PaymentControllerTests(TestCase): store, DummyRedeemer(public_key), default_token_count=100, + clock=Clock(), ) self.assertThat( controller.redeem(voucher), @@ -462,6 +472,7 @@ class PaymentControllerTests(TestCase): store, DoubleSpendRedeemer(), default_token_count=100, + clock=Clock(), ) self.assertThat( controller.redeem(voucher), @@ -491,6 +502,7 @@ class PaymentControllerTests(TestCase): store, UnpaidRedeemer(), default_token_count=100, + clock=Clock(), ) self.assertThat( unpaid_controller.redeem(voucher), @@ -510,6 +522,7 @@ class PaymentControllerTests(TestCase): store, DummyRedeemer(), default_token_count=100, + clock=Clock(), ) self.assertThat( diff --git a/src/_zkapauthorizer/tests/test_plugin.py b/src/_zkapauthorizer/tests/test_plugin.py index 44c79af..e28f06b 100644 --- a/src/_zkapauthorizer/tests/test_plugin.py +++ b/src/_zkapauthorizer/tests/test_plugin.py @@ -99,6 +99,9 @@ from twisted.plugin import ( from twisted.test.proto_helpers import ( StringTransport, ) +from twisted.internet.task import ( + Clock, +) from twisted.web.resource import ( IResource, ) @@ -483,6 +486,7 @@ class ClientPluginTests(TestCase): DummyRedeemer(), default_token_count=num_passes, num_redemption_groups=1, + clock=Clock(), ) # Get a token inserted into the store. redeeming = controller.redeem(voucher) @@ -543,7 +547,11 @@ class ClientResourceTests(TestCase): nodedir = tempdir.join(b"node") config = get_config(nodedir, b"tub.port") self.assertThat( - storage_server.get_client_resource(config, default_token_count=10), + storage_server.get_client_resource( + config, + default_token_count=10, + reactor=Clock(), + ), Provides([IResource]), ) -- GitLab