From 3f374bbfcf683d4bf262d48728db18e6fd3172b4 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Fri, 19 Nov 2021 10:13:51 -0500 Subject: [PATCH] Metrics: Add test for metric file writing scaffolding --- setup.cfg | 1 + src/_zkapauthorizer/_plugin.py | 13 ++++++++- src/_zkapauthorizer/_storage_server.py | 1 + src/_zkapauthorizer/tests/test_plugin.py | 35 +++++++++++++++++++++++- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index ebbd1ac..343668b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -48,6 +48,7 @@ install_requires = tahoe-lafs @ https://github.com/tahoe-lafs/tahoe-lafs/archive/d3c6f58a8ded7db3324ef97c47f5c1921c3d58b7.zip treq pyutil + prometheus-client [options.extras_require] test = coverage; fixtures; testtools; hypothesis diff --git a/src/_zkapauthorizer/_plugin.py b/src/_zkapauthorizer/_plugin.py index cf331c6..88998b0 100644 --- a/src/_zkapauthorizer/_plugin.py +++ b/src/_zkapauthorizer/_plugin.py @@ -27,6 +27,7 @@ from allmydata.client import _Client from allmydata.interfaces import IAnnounceableStorageServer, IFoolscapStoragePlugin from allmydata.node import MissingConfigEntry from challenge_bypass_ristretto import SigningKey +from prometheus_client import CollectorRegistry from twisted.internet.defer import succeed from twisted.logger import Logger from twisted.python.filepath import FilePath @@ -94,8 +95,17 @@ class ZKAPAuthorizer(object): """ return get_redeemer(self.name, node_config, announcement, reactor) - def get_storage_server(self, configuration, get_anonymous_storage_server): + def get_storage_server( + self, configuration, get_anonymous_storage_server, reactor=None + ): + if reactor is None: + from twisted.internet import reactor + registry = CollectorRegistry() + # schedule_writing(registry) kwargs = configuration.copy() + + kwargs.pop(u"prometheus-metrics-path", None) + kwargs.pop(u"prometheus-metrics-interval", None) root_url = kwargs.pop(u"ristretto-issuer-root-url") pass_value = int(kwargs.pop(u"pass-value", BYTES_PER_PASS)) signing_key = load_signing_key( @@ -110,6 +120,7 @@ class ZKAPAuthorizer(object): get_anonymous_storage_server(), pass_value=pass_value, signing_key=signing_key, + registry=registry, **kwargs ) return succeed( diff --git a/src/_zkapauthorizer/_storage_server.py b/src/_zkapauthorizer/_storage_server.py index e379989..4d47ad1 100644 --- a/src/_zkapauthorizer/_storage_server.py +++ b/src/_zkapauthorizer/_storage_server.py @@ -171,6 +171,7 @@ class ZKAPAuthorizerStorageServer(Referenceable): _original = attr.ib(validator=provides(RIStorageServer)) _pass_value = pass_value_attribute() _signing_key = attr.ib(validator=instance_of(SigningKey)) + _registry = attr.ib() _clock = attr.ib( validator=provides(IReactorTime), default=attr.Factory(partial(namedAny, "twisted.internet.reactor")), diff --git a/src/_zkapauthorizer/tests/test_plugin.py b/src/_zkapauthorizer/tests/test_plugin.py index 78959a5..3060075 100644 --- a/src/_zkapauthorizer/tests/test_plugin.py +++ b/src/_zkapauthorizer/tests/test_plugin.py @@ -19,6 +19,7 @@ Tests for the Tahoe-LAFS plugin. from __future__ import absolute_import import tempfile +from datetime import timedelta from functools import partial from os import makedirs @@ -36,7 +37,9 @@ from foolscap.broker import Broker from foolscap.ipb import IReferenceable, IRemotelyCallable from foolscap.referenceable import LocalReferenceable from hypothesis import given, settings -from hypothesis.strategies import datetimes, just, sampled_from +from hypothesis.strategies import datetimes, just, sampled_from, timedeltas +from isodate import duration_isoformat +from prometheus_client import CollectorRegistry, Gauge from StringIO import StringIO from testtools import TestCase from testtools.content import text_content @@ -47,12 +50,14 @@ from testtools.matchers import ( Contains, ContainsDict, Equals, + FileContains, HasLength, IsInstance, MatchesAll, MatchesStructure, ) from testtools.twistedsupport import succeeded +from testtools.twistedsupport._deferred import extract_result from twisted.internet.task import Clock from twisted.plugin import getPlugins from twisted.python.filepath import FilePath @@ -74,6 +79,7 @@ from .matchers import Provides, raises from .strategies import ( announcements, client_dummyredeemer_configurations, + clocks, dummy_ristretto_keys, lease_cancel_secrets, lease_renew_secrets, @@ -262,6 +268,33 @@ class ServerPluginTests(TestCase): ), ) + @given(timedeltas(min_value=timedelta(seconds=1)), clocks()) + def test_metrics_written(self, metrics_interval, clock): + """ + When the configuration tells us where to put a metrics .prom file + and an interval how often to do so, test that metrics are actually + written there after the configured interval. + """ + metrics_path = self.useFixture(TempDir()).join(u"metrics") + configuration = { + u"prometheus-metrics-path": metrics_path, + u"prometheus-metrics-interval": duration_isoformat(metrics_interval), + u"ristretto-issuer-root-url": "foo", + u"ristretto-signing-key-path": SIGNING_KEY_PATH.path, + } + announceable = extract_result( + storage_server.get_storage_server( + configuration, + get_anonymous_storage_server, + reactor=clock, + ) + ) + registry = announceable.storage_server._registry + Gauge("foo", "bar", registry=registry).set(1) + + clock.advance(metrics_interval.total_seconds()) + self.assertThat(metrics_path, FileContains("foo 1")) + tahoe_configs_with_dummy_redeemer = tahoe_configs(client_dummyredeemer_configurations()) -- GitLab