From 1275c63e2a84e450f6b93727cea672ab0219bf3c Mon Sep 17 00:00:00 2001 From: Mathieu Leplatre Date: Wed, 9 Oct 2024 16:26:50 +0200 Subject: [PATCH] Move tests and assertions where they belong --- tests/core/test_initialization.py | 84 +++++++++++++++--- tests/core/test_metrics.py | 49 +++++++++++ tests/plugins/test_history.py | 2 +- tests/plugins/test_quotas.py | 2 +- tests/plugins/test_statsd.py | 139 +----------------------------- 5 files changed, 126 insertions(+), 150 deletions(-) create mode 100644 tests/core/test_metrics.py diff --git a/tests/core/test_initialization.py b/tests/core/test_initialization.py index ca1dd8c16..6d52d75a7 100644 --- a/tests/core/test_initialization.py +++ b/tests/core/test_initialization.py @@ -8,7 +8,7 @@ import kinto.core from kinto.core import initialization -from kinto.core.testing import skip_if_no_statsd, unittest +from kinto.core.testing import get_user_headers, skip_if_no_statsd, unittest class InitializationTest(unittest.TestCase): @@ -293,7 +293,7 @@ def unexpected_exceptions_are_reported(self): @skip_if_no_statsd -class StatsDConfigurationTest(unittest.TestCase): +class MetricsConfigurationTest(unittest.TestCase): settings = { **kinto.core.DEFAULT_SETTINGS, "statsd_url": "udp://host:8080", @@ -305,6 +305,10 @@ def setUp(self): self.mocked = patch.start() self.addCleanup(patch.stop) + patch_watch = mock.patch("kinto.core.metrics.watch_execution_time") + self.mocked_watch = patch_watch.start() + self.addCleanup(patch_watch.stop) + self.config = Configurator(settings=self.settings) self.config.registry.storage = {} self.config.registry.cache = {} @@ -330,19 +334,75 @@ def test_statsd_isnt_included_if_statsd_url_is_not_set(self): self.mocked.assert_not_called() + # + # Backends. + # -class MetricsRegistryConfigurationTest(unittest.TestCase): - settings = kinto.core.DEFAULT_SETTINGS + def test_statsd_is_set_on_cache(self): + kinto.core.initialize(self.config, "0.0.1", "settings_prefix") + _app = webtest.TestApp(self.config.make_wsgi_app()) - def setUp(self): - self.config = Configurator(settings=self.settings) - self.config.registry.storage = {} - self.config.registry.cache = {} - self.config.registry.permission = {} + self.mocked_watch.assert_any_call(self.mocked(), {}, prefix="backend") - patch = mock.patch("kinto.plugins.statsd.StatsDService") - self.mocked = patch.start() - self.addCleanup(patch.stop) + def test_statsd_is_set_on_storage(self): + kinto.core.initialize(self.config, "0.0.1", "settings_prefix") + _app = webtest.TestApp(self.config.make_wsgi_app()) + + self.mocked_watch.assert_any_call(self.mocked(), {}, prefix="backend") + + def test_statsd_is_set_on_permission(self): + kinto.core.initialize(self.config, "0.0.1", "settings_prefix") + _app = webtest.TestApp(self.config.make_wsgi_app()) + + self.mocked_watch.assert_any_call(self.mocked(), {}, prefix="backend") + + # + # Authentication. + # + + def test_statsd_is_set_on_authentication(self): + kinto.core.initialize(self.config, "0.0.1", "settings_prefix") + _app = webtest.TestApp(self.config.make_wsgi_app()) + + self.mocked_watch.assert_any_call( + self.mocked(), mock.ANY, prefix="authentication", classname="basicauth" + ) + + @mock.patch("kinto.core.utils.hmac_digest") + def test_statsd_counts_unique_users(self, digest_mocked): + digest_mocked.return_value = "mat" + kinto.core.initialize(self.config, "0.0.1", "settings_prefix") + app = webtest.TestApp(self.config.make_wsgi_app()) + app.get("/v0/", headers=get_user_headers("bob")) + self.mocked().count.assert_any_call("users", unique="basicauth.mat") + + def test_statsd_counts_authentication_types(self): + kinto.core.initialize(self.config, "0.0.1", "settings_prefix") + app = webtest.TestApp(self.config.make_wsgi_app()) + app.get("/v0/", headers=get_user_headers("bob")) + self.mocked().count.assert_any_call("authn_type.basicauth") + + # + # Endpoints. + # + + def test_statsd_counts_nothing_on_anonymous_requests(self): + kinto.core.initialize(self.config, "0.0.1", "settings_prefix") + app = webtest.TestApp(self.config.make_wsgi_app()) + app.get("/") + self.assertFalse(self.mocked.count.called) + + def test_statsd_counts_views_and_methods(self): + kinto.core.initialize(self.config, "0.0.1", "settings_prefix") + app = webtest.TestApp(self.config.make_wsgi_app()) + app.get("/v0/__heartbeat__") + self.mocked().count.assert_any_call("view.heartbeat.GET") + + def test_statsd_counts_unknown_urls(self): + kinto.core.initialize(self.config, "0.0.1", "settings_prefix") + app = webtest.TestApp(self.config.make_wsgi_app()) + app.get("/v0/coucou", status=404) + self.assertFalse(self.mocked.count.called) def test_metrics_and_statsd_are_none_if_statsd_url_not_set(self): self.config.add_settings({"statsd_url": None}) diff --git a/tests/core/test_metrics.py b/tests/core/test_metrics.py new file mode 100644 index 000000000..c6ff06a22 --- /dev/null +++ b/tests/core/test_metrics.py @@ -0,0 +1,49 @@ +import unittest +from unittest import mock + +from pyramid.config import Configurator + +from kinto.core import metrics + + +class TestedClass: + attribute = 3.14 + + def test_method(self): + pass + + def _private_method(self): + pass + + +class WatchExecutionTimeTest(unittest.TestCase): + def setUp(self): + self.test_object = TestedClass() + self.mocked = mock.MagicMock() + metrics.watch_execution_time(self.mocked, self.test_object, prefix="test") + + def test_public_methods_generates_statsd_calls(self): + self.test_object.test_method() + self.mocked.timer.assert_called_with("test.testedclass.test_method") + + def test_private_methods_does_not_generates_statsd_calls(self): + self.test_object._private_method() + self.assertFalse(self.mocked().timer.called) + + +class ListenerWithTimerTest(unittest.TestCase): + def setUp(self): + self.config = Configurator() + self.func = lambda x: x # noqa: E731 + + def test_without_metrics_service(self): + wrapped = metrics.listener_with_timer(self.config, "key", self.func) + + self.assertEqual(wrapped(42), 42) # does not raise + + def test_with_metrics_service(self): + self.config.registry.registerUtility(mock.MagicMock(), metrics.IMetricsService) + wrapped = metrics.listener_with_timer(self.config, "key", self.func) + + self.assertEqual(wrapped(42), 42) + self.config.registry.metrics.timer.assert_called_with("key") diff --git a/tests/plugins/test_history.py b/tests/plugins/test_history.py index f21b34106..36088fc25 100644 --- a/tests/plugins/test_history.py +++ b/tests/plugins/test_history.py @@ -26,6 +26,7 @@ def test_history_capability_if_enabled(self): self.assertIn("history", capabilities) +@skip_if_no_statsd class MetricsTest(HistoryWebTest): @classmethod def get_app_settings(cls, extras=None): @@ -37,7 +38,6 @@ def get_app_settings(cls, extras=None): ) return settings - @skip_if_no_statsd def test_a_statsd_timer_is_used_for_history_if_configured(self): with mock.patch("kinto.plugins.statsd.StatsDService.timer") as mocked: self.app.put("/buckets/test", headers=self.headers) diff --git a/tests/plugins/test_quotas.py b/tests/plugins/test_quotas.py index e4f2865ab..27ec5c736 100644 --- a/tests/plugins/test_quotas.py +++ b/tests/plugins/test_quotas.py @@ -76,6 +76,7 @@ def test_quota_capability_if_enabled(self): self.assertIn("quotas", capabilities) +@skip_if_no_statsd class MetricsTest(QuotaWebTest): @classmethod def get_app_settings(cls, extras=None): @@ -87,7 +88,6 @@ def get_app_settings(cls, extras=None): ) return settings - @skip_if_no_statsd def test_a_statsd_timer_is_used_for_quotas_if_configured(self): with mock.patch("kinto.plugins.statsd.StatsDService.timer") as mocked: self.app.put("/buckets/test", headers=self.headers) diff --git a/tests/plugins/test_statsd.py b/tests/plugins/test_statsd.py index e6065c4bf..975941f2a 100644 --- a/tests/plugins/test_statsd.py +++ b/tests/plugins/test_statsd.py @@ -1,108 +1,11 @@ from unittest import mock -import webtest from pyramid import testing -from pyramid.config import Configurator from pyramid.exceptions import ConfigurationError -import kinto from kinto.core.testing import skip_if_no_statsd, unittest from kinto.plugins import statsd -from ..support import BaseWebTest - - -@skip_if_no_statsd -class StatsDIncludeTest(unittest.TestCase): - def setUp(self): - settings = { - **kinto.core.DEFAULT_SETTINGS, - "statsd_url": "udp://host:8080", - "multiauth.policies": "basicauth", - } - self.config = Configurator(settings=settings) - self.config.registry.storage = {} - self.config.registry.cache = {} - self.config.registry.permission = {} - - patch = mock.patch("kinto.plugins.statsd.StatsDService") - self.mocked = patch.start() - self.addCleanup(patch.stop) - - patch_watch = mock.patch("kinto.core.metrics.watch_execution_time") - self.mocked_watch = patch_watch.start() - self.addCleanup(patch_watch.stop) - - def test_statsd_is_set_on_cache(self): - kinto.core.initialize(self.config, "0.0.1", "settings_prefix") - _app = webtest.TestApp(self.config.make_wsgi_app()) - - self.mocked_watch.assert_any_call(self.mocked(), {}, prefix="backend") - - def test_statsd_is_set_on_storage(self): - kinto.core.initialize(self.config, "0.0.1", "settings_prefix") - _app = webtest.TestApp(self.config.make_wsgi_app()) - - self.mocked_watch.assert_any_call(self.mocked(), {}, prefix="backend") - - def test_statsd_is_set_on_permission(self): - kinto.core.initialize(self.config, "0.0.1", "settings_prefix") - _app = webtest.TestApp(self.config.make_wsgi_app()) - - self.mocked_watch.assert_any_call(self.mocked(), {}, prefix="backend") - - def test_statsd_is_set_on_authentication(self): - kinto.core.initialize(self.config, "0.0.1", "settings_prefix") - _app = webtest.TestApp(self.config.make_wsgi_app()) - - self.mocked_watch.assert_any_call( - self.mocked(), mock.ANY, prefix="authentication", classname="basicauth" - ) - - def test_statsd_counts_nothing_on_anonymous_requests(self): - kinto.core.initialize(self.config, "0.0.1", "settings_prefix") - app = webtest.TestApp(self.config.make_wsgi_app()) - app.get("/") - self.assertFalse(self.mocked.count.called) - - def test_statsd_counts_views_and_methods(self): - kinto.core.initialize(self.config, "0.0.1", "settings_prefix") - app = webtest.TestApp(self.config.make_wsgi_app()) - app.get("/v0/__heartbeat__") - self.mocked().count.assert_any_call("view.heartbeat.GET") - - def test_statsd_counts_unknown_urls(self): - kinto.core.initialize(self.config, "0.0.1", "settings_prefix") - app = webtest.TestApp(self.config.make_wsgi_app()) - app.get("/v0/coucou", status=404) - self.assertFalse(self.mocked.count.called) - - @mock.patch("kinto.core.utils.hmac_digest") - def test_statsd_counts_unique_users(self, digest_mocked): - digest_mocked.return_value = "mat" - kinto.core.initialize(self.config, "0.0.1", "settings_prefix") - app = webtest.TestApp(self.config.make_wsgi_app()) - headers = {"Authorization": "Basic bWF0Og=="} - app.get("/v0/", headers=headers) - self.mocked().count.assert_any_call("users", unique="basicauth.mat") - - def test_statsd_counts_authentication_types(self): - kinto.core.initialize(self.config, "0.0.1", "settings_prefix") - app = webtest.TestApp(self.config.make_wsgi_app()) - headers = {"Authorization": "Basic bWF0Og=="} - app.get("/v0/", headers=headers) - self.mocked().count.assert_any_call("authn_type.basicauth") - - -class TestedClass: - attribute = 3.14 - - def test_method(self): - pass - - def _private_method(self): - pass - class StatsDMissing(unittest.TestCase): def setUp(self): @@ -123,21 +26,10 @@ class StatsdClientTest(unittest.TestCase): def setUp(self): self.client = statsd.StatsDService("localhost", 1234, "prefix") - self.test_object = TestedClass() - - with mock.patch.object(self.client, "_client") as mocked_client: - kinto.core.metrics.watch_execution_time(self.client, self.test_object, prefix="test") - self.mocked_client = mocked_client - def test_public_methods_generates_statsd_calls(self): - self.test_object.test_method() - - self.mocked_client.timer.assert_called_with("test.testedclass.test_method") - - def test_private_methods_does_not_generates_statsd_calls(self): - self.mocked_client.reset_mock() - self.test_object._private_method() - self.assertFalse(self.mocked_client.timer.called) + patch = mock.patch.object(self.client, "_client") + self.mocked_client = patch.start() + self.addCleanup(patch.stop) def test_count_increments_the_counter_for_key(self): with mock.patch.object(self.client, "_client") as mocked_client: @@ -167,28 +59,3 @@ def test_load_from_config_uses_project_name_if_defined(self, module_mock): config.registry.settings = {**self.settings, "project_name": "projectname"} statsd.load_from_config(config) module_mock.StatsClient.assert_called_with("foo", 1234, prefix="projectname") - - -@skip_if_no_statsd -class TimingTest(BaseWebTest, unittest.TestCase): - @classmethod - def get_app_settings(cls, *args, **kwargs): - settings = super().get_app_settings(*args, **kwargs) - if not statsd.statsd_module: - return settings - - settings["statsd_url"] = "udp://localhost:8125" - return settings - - def test_statds_tracks_listeners_execution_duration(self): - statsd_client = self.app.app.registry.metrics._client - with mock.patch.object(statsd_client, "timing") as mocked: - self.app.get("/", headers=self.headers) - self.assertTrue(mocked.called) - - def test_statds_tracks_authentication_policies(self): - statsd_client = self.app.app.registry.metrics._client - with mock.patch.object(statsd_client, "timing") as mocked: - self.app.get("/", headers=self.headers) - timers = set(c[0][0] for c in mocked.call_args_list) - self.assertIn("authentication.basicauth.unauthenticated_userid", timers)