From b5b297c7606fdf851c32f413968d842aa7e23b60 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Tue, 5 May 2020 13:50:55 -0600 Subject: [PATCH] api: Add reset for configuration testing (#636) It is a common occurrence in tests that the global Configuration object needs to be "reset" between tests. This means that its attributes need to be set back to their original values. Since the Configuration object is immutable by design, some additional, non-production available mechanism is needed to perform this action. The need for this feature was mentioned in a conversation in #630. --- .../tests/base_test.py | 5 ++++ .../tests/test_automatic.py | 3 -- .../tests/test_programmatic.py | 3 -- .../opentelemetry/configuration/__init__.py | 17 +++++++++++ .../tests/configuration/test_configuration.py | 30 ++++++++++++++----- 5 files changed, 45 insertions(+), 13 deletions(-) diff --git a/ext/opentelemetry-ext-flask/tests/base_test.py b/ext/opentelemetry-ext-flask/tests/base_test.py index 7147afd719..42341826df 100644 --- a/ext/opentelemetry-ext-flask/tests/base_test.py +++ b/ext/opentelemetry-ext-flask/tests/base_test.py @@ -19,6 +19,7 @@ from werkzeug.wrappers import BaseResponse from opentelemetry import trace +from opentelemetry.configuration import Configuration def expected_attributes(override_attributes): @@ -40,6 +41,10 @@ def expected_attributes(override_attributes): class InstrumentationTest: + def setUp(self): # pylint: disable=invalid-name + super().setUp() # pylint: disable=no-member + Configuration._reset() # pylint: disable=protected-access + @staticmethod def _hello_endpoint(helloid): if helloid == 500: diff --git a/ext/opentelemetry-ext-flask/tests/test_automatic.py b/ext/opentelemetry-ext-flask/tests/test_automatic.py index 04f43d6e64..b94c7b33d6 100644 --- a/ext/opentelemetry-ext-flask/tests/test_automatic.py +++ b/ext/opentelemetry-ext-flask/tests/test_automatic.py @@ -16,7 +16,6 @@ from werkzeug.test import Client from werkzeug.wrappers import BaseResponse -from opentelemetry.configuration import Configuration from opentelemetry.ext.flask import FlaskInstrumentor from opentelemetry.test.test_base import TestBase from opentelemetry.test.wsgitestutil import WsgiTestBase @@ -29,8 +28,6 @@ class TestAutomatic(InstrumentationTest, TestBase, WsgiTestBase): def setUp(self): super().setUp() - Configuration._instance = None # pylint: disable=protected-access - Configuration.__slots__ = [] # pylint: disable=protected-access FlaskInstrumentor().instrument() self.app = flask.Flask(__name__) diff --git a/ext/opentelemetry-ext-flask/tests/test_programmatic.py b/ext/opentelemetry-ext-flask/tests/test_programmatic.py index 1075f808cb..4e17f25fdc 100644 --- a/ext/opentelemetry-ext-flask/tests/test_programmatic.py +++ b/ext/opentelemetry-ext-flask/tests/test_programmatic.py @@ -14,7 +14,6 @@ from flask import Flask -from opentelemetry.configuration import Configuration from opentelemetry.ext.flask import FlaskInstrumentor from opentelemetry.test.test_base import TestBase from opentelemetry.test.wsgitestutil import WsgiTestBase @@ -27,8 +26,6 @@ class TestProgrammatic(InstrumentationTest, TestBase, WsgiTestBase): def setUp(self): super().setUp() - Configuration._instance = None # pylint: disable=protected-access - Configuration.__slots__ = [] # pylint: disable=protected-access self.app = Flask(__name__) FlaskInstrumentor().instrument_app(self.app) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index 57b1c324c6..ad546b0b86 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -122,3 +122,20 @@ def __new__(cls) -> "Configuration": def __getattr__(self, name): return None + + @classmethod + def _reset(cls): + """ + This method "resets" the global configuration attributes + + It is not intended to be used by production code but by testing code + only. + """ + + for slot in cls.__slots__: + if slot in cls.__dict__.keys(): + delattr(cls, slot) + delattr(cls, "_{}".format(slot)) + + cls.__slots__ = [] + cls._instance = None diff --git a/opentelemetry-api/tests/configuration/test_configuration.py b/opentelemetry-api/tests/configuration/test_configuration.py index 9688ec28b6..c736c97262 100644 --- a/opentelemetry-api/tests/configuration/test_configuration.py +++ b/opentelemetry-api/tests/configuration/test_configuration.py @@ -20,14 +20,10 @@ class TestConfiguration(TestCase): - def setUp(self): - # This is added here to force a reload of the whole Configuration - # class, resetting its internal attributes so that each tests starts - # with a clean class. - from opentelemetry.configuration import Configuration # type: ignore - def tearDown(self): - from opentelemetry.configuration import Configuration # type: ignore + # This call resets the attributes of the Configuration class so that + # each test is executed in the same conditions. + Configuration._reset() def test_singleton(self): self.assertIsInstance(Configuration(), Configuration) @@ -72,3 +68,23 @@ def test_slots(self): def test_getattr(self): self.assertIsNone(Configuration().XYZ) + + def test_reset(self): + environ_patcher = patch.dict( + "os.environ", # type: ignore + {"OPENTELEMETRY_PYTHON_TRACER_PROVIDER": "tracer_provider"}, + ) + + environ_patcher.start() + + self.assertEqual( + Configuration().TRACER_PROVIDER, "tracer_provider" + ) # pylint: disable=no-member + + environ_patcher.stop() + + Configuration._reset() + + self.assertIsNone( + Configuration().TRACER_PROVIDER + ) # pylint: disable=no-member