diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py index 68d201fb59..cb877e67be 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-server/tests/test_aiohttp_server_integration.py @@ -20,8 +20,6 @@ import pytest_asyncio from multidict import CIMultiDict -from opentelemetry import metrics as metrics_api -from opentelemetry import trace as trace_api from opentelemetry.instrumentation._semconv import ( HTTP_DURATION_HISTOGRAM_BUCKETS_NEW, OTEL_SEMCONV_STABILITY_OPT_IN, @@ -73,10 +71,6 @@ from opentelemetry.semconv.attributes.user_agent_attributes import ( USER_AGENT_ORIGINAL, ) -from opentelemetry.test.globals_test import ( - reset_metrics_globals, - reset_trace_globals, -) from opentelemetry.test.test_base import TestBase from opentelemetry.util._importlib_metadata import entry_points from opentelemetry.util.http import ( @@ -103,33 +97,24 @@ def __repr__(self): TRACE = "TRACE" -@pytest.fixture(name="tracer", scope="function") -def fixture_tracer(): +@pytest.fixture(name="test_base", scope="function") +def fixture_test_base(): test_base = TestBase() + test_base.setUp() + try: + yield test_base + finally: + test_base.tearDown() - tracer_provider, memory_exporter = test_base.create_tracer_provider() - - reset_trace_globals() - trace_api.set_tracer_provider(tracer_provider) - - yield tracer_provider, memory_exporter - reset_trace_globals() - memory_exporter.clear() +@pytest.fixture(name="tracer", scope="function") +def fixture_tracer(test_base: TestBase): + return test_base.tracer_provider, test_base.memory_exporter @pytest.fixture(name="meter", scope="function") -def fixture_meter(): - test_base = TestBase() - - meter_provider, memory_reader = test_base.create_meter_provider() - - reset_metrics_globals() - metrics_api.set_meter_provider(meter_provider) - - yield meter_provider, memory_reader - - reset_metrics_globals() +def fixture_meter(test_base: TestBase): + return test_base.meter_provider, test_base.memory_metrics_reader async def default_handler(request, status=200): @@ -143,7 +128,7 @@ def fixture_suppress(): @pytest_asyncio.fixture(name="server_fixture") async def fixture_server_fixture(tracer, aiohttp_server, suppress): - tracer_provider, memory_exporter = tracer + tracer_provider, _ = tracer AioHttpServerInstrumentor().instrument(tracer_provider=tracer_provider) @@ -157,8 +142,6 @@ async def fixture_server_fixture(tracer, aiohttp_server, suppress): yield server, app - memory_exporter.clear() - AioHttpServerInstrumentor().uninstrument() @@ -179,31 +162,27 @@ def test_checking_instrumentor_pkg_installed(): ], ) async def test_status_code_instrumentation( - tracer, - meter, + test_base: TestBase, server_fixture, aiohttp_client, url, expected_method, expected_status_code, ): - _, memory_exporter = tracer - _, metrics_reader = meter server, _ = server_fixture - assert len(memory_exporter.get_finished_spans()) == 0 - metrics = _get_sorted_metrics(metrics_reader.get_metrics_data()) + assert len(test_base.get_finished_spans()) == 0 + metrics = test_base.get_sorted_metrics() assert len(metrics) == 0 client = await aiohttp_client(server) await client.get(url) - assert len(memory_exporter.get_finished_spans()) == 1 - metrics = _get_sorted_metrics(metrics_reader.get_metrics_data()) + assert len(test_base.get_finished_spans()) == 1 + metrics = test_base.get_sorted_metrics() assert len(metrics) == 2 - [span] = memory_exporter.get_finished_spans() - + [span] = test_base.get_finished_spans() assert expected_method.value == span.attributes[HTTP_METHOD] assert expected_status_code == span.attributes[HTTP_STATUS_CODE] assert url == span.attributes[HTTP_TARGET] @@ -212,23 +191,22 @@ async def test_status_code_instrumentation( @pytest.mark.asyncio @pytest.mark.parametrize("suppress", [True]) async def test_suppress_instrumentation( - tracer, server_fixture, aiohttp_client + test_base: TestBase, server_fixture, aiohttp_client ): - _, memory_exporter = tracer server, _ = server_fixture - assert len(memory_exporter.get_finished_spans()) == 0 + assert len(test_base.get_finished_spans()) == 0 client = await aiohttp_client(server) await client.get("/test-path") - assert len(memory_exporter.get_finished_spans()) == 0 + assert len(test_base.get_finished_spans()) == 0 @pytest.mark.asyncio -async def test_remove_sensitive_params(tracer, aiohttp_server, monkeypatch): +async def test_remove_sensitive_params( + test_base: TestBase, aiohttp_server, monkeypatch +): """Test that sensitive information in URLs is properly redacted.""" - _, memory_exporter = tracer - # Use old semconv to test HTTP_URL redaction monkeypatch.setenv( OTEL_SEMCONV_STABILITY_OPT_IN, _StabilityMode.DEFAULT.value @@ -257,7 +235,7 @@ async def handler(request): assert await response.text() == "hello" # Verify redaction in span attributes - spans = memory_exporter.get_finished_spans() + spans = test_base.get_finished_spans() assert len(spans) == 1 span = spans[0] @@ -270,16 +248,13 @@ async def handler(request): # Clean up AioHttpServerInstrumentor().uninstrument() - memory_exporter.clear() @pytest.mark.asyncio async def test_remove_sensitive_params_new( - tracer, aiohttp_server, monkeypatch + test_base: TestBase, aiohttp_server, monkeypatch ): """Test URL handling with new semantic conventions (no redaction for URL_PATH/URL_QUERY).""" - _, memory_exporter = tracer - # Use new semconv monkeypatch.setenv( OTEL_SEMCONV_STABILITY_OPT_IN, _StabilityMode.HTTP.value @@ -308,7 +283,7 @@ async def handler(request): assert await response.text() == "hello" # Verify span attributes with new semconv - spans = memory_exporter.get_finished_spans() + spans = test_base.get_finished_spans() assert len(spans) == 1 span = spans[0] @@ -320,21 +295,6 @@ async def handler(request): # Clean up AioHttpServerInstrumentor().uninstrument() - memory_exporter.clear() - - -def _get_sorted_metrics(metrics_data): - resource_metrics = metrics_data.resource_metrics if metrics_data else [] - - all_metrics = [] - for metrics in resource_metrics: - for scope_metrics in metrics.scope_metrics: - all_metrics.extend(scope_metrics.metrics) - - return sorted( - all_metrics, - key=lambda m: m.name, - ) @pytest.mark.asyncio @@ -343,12 +303,9 @@ def _get_sorted_metrics(metrics_data): ["OTEL_PYTHON_AIOHTTP_SERVER_EXCLUDED_URLS", "OTEL_PYTHON_EXCLUDED_URLS"], ) async def test_excluded_urls( - tracer, meter, aiohttp_server, monkeypatch, env_var + test_base: TestBase, aiohttp_server, monkeypatch, env_var ): """Test that excluded env vars are taken into account.""" - _, memory_exporter = tracer - _, metrics_reader = meter - monkeypatch.setenv(env_var, "/status/200") AioHttpServerInstrumentor().instrument() @@ -367,10 +324,10 @@ async def handler(request): assert response.status == 200 assert await response.text() == "hello" - spans = memory_exporter.get_finished_spans() + spans = test_base.get_finished_spans() assert len(spans) == 0 - metrics = _get_sorted_metrics(metrics_reader.get_metrics_data()) + metrics = test_base.get_sorted_metrics() assert len(metrics) == 0 AioHttpServerInstrumentor().uninstrument() @@ -415,25 +372,11 @@ async def test_non_global_tracer_provider( ) -def _get_sorted_metrics(metrics_data): - resource_metrics = metrics_data.resource_metrics if metrics_data else [] - - all_metrics = [] - for metrics in resource_metrics: - for scope_metrics in metrics.scope_metrics: - all_metrics.extend(scope_metrics.metrics) - - return sorted( - all_metrics, - key=lambda m: m.name, - ) - - @pytest.mark.asyncio -async def test_custom_request_headers(tracer, aiohttp_server, monkeypatch): +async def test_custom_request_headers( + test_base: TestBase, aiohttp_server, monkeypatch +): # pylint: disable=too-many-locals - _, memory_exporter = tracer - monkeypatch.setenv( OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS, ".*my-secret.*", @@ -466,7 +409,7 @@ async def handler(request): assert response.status == 200 assert await response.text() == "hello" - spans = memory_exporter.get_finished_spans() + spans = test_base.get_finished_spans() assert len(spans) == 1 span = spans[0] @@ -489,9 +432,9 @@ async def handler(request): @pytest.mark.asyncio -async def test_custom_response_headers(tracer, aiohttp_server, monkeypatch): - _, memory_exporter = tracer - +async def test_custom_response_headers( + test_base: TestBase, aiohttp_server, monkeypatch +): monkeypatch.setenv( OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS, ".*my-secret.*", @@ -526,7 +469,7 @@ async def handler(request): assert response.status == 200 assert await response.text() == "hello" - spans = memory_exporter.get_finished_spans() + spans = test_base.get_finished_spans() assert len(spans) == 1 span = spans[0] @@ -553,10 +496,8 @@ async def handler(request): # pylint: disable=too-many-locals @pytest.mark.asyncio async def test_semantic_conventions_metrics_old_default( - tracer, meter, aiohttp_server, monkeypatch + test_base: TestBase, aiohttp_server, monkeypatch ): - _, memory_exporter = tracer - _, metrics_reader = meter monkeypatch.setenv( OTEL_SEMCONV_STABILITY_OPT_IN, _StabilityMode.DEFAULT.value ) @@ -573,7 +514,7 @@ async def test_semantic_conventions_metrics_old_default( url, headers={"User-Agent": "test-agent"} ) as response: assert response.status == 200 - spans = memory_exporter.get_finished_spans() + spans = test_base.get_finished_spans() assert len(spans) == 1 span = spans[0] @@ -604,7 +545,7 @@ async def test_semantic_conventions_metrics_old_default( assert NETWORK_PROTOCOL_VERSION not in span.attributes assert HTTP_RESPONSE_STATUS_CODE not in span.attributes - metrics = _get_sorted_metrics(metrics_reader.get_metrics_data()) + metrics = test_base.get_sorted_metrics() expected_metric_names = [ "http.server.active_requests", "http.server.duration", @@ -629,10 +570,8 @@ async def test_semantic_conventions_metrics_old_default( # pylint: disable=too-many-locals @pytest.mark.asyncio async def test_semantic_conventions_metrics_new( - tracer, meter, aiohttp_server, monkeypatch + test_base: TestBase, meter, aiohttp_server, monkeypatch ): - _, memory_exporter = tracer - _, metrics_reader = meter monkeypatch.setenv( OTEL_SEMCONV_STABILITY_OPT_IN, _StabilityMode.HTTP.value ) @@ -649,7 +588,7 @@ async def test_semantic_conventions_metrics_new( url, headers={"User-Agent": "test-agent"} ) as response: assert response.status == 200 - spans = memory_exporter.get_finished_spans() + spans = test_base.get_finished_spans() assert len(spans) == 1 span = spans[0] @@ -680,7 +619,7 @@ async def test_semantic_conventions_metrics_new( assert HTTP_FLAVOR not in span.attributes assert HTTP_STATUS_CODE not in span.attributes - metrics = _get_sorted_metrics(metrics_reader.get_metrics_data()) + metrics = test_base.get_sorted_metrics() expected_metric_names = [ "http.server.active_requests", "http.server.request.duration", @@ -714,10 +653,8 @@ async def test_semantic_conventions_metrics_new( # pylint: disable=too-many-statements @pytest.mark.asyncio async def test_semantic_conventions_metrics_both( - tracer, meter, aiohttp_server, monkeypatch + test_base: TestBase, meter, aiohttp_server, monkeypatch ): - _, memory_exporter = tracer - _, metrics_reader = meter monkeypatch.setenv( OTEL_SEMCONV_STABILITY_OPT_IN, _StabilityMode.HTTP_DUP.value ) @@ -734,7 +671,7 @@ async def test_semantic_conventions_metrics_both( url, headers={"User-Agent": "test-agent"} ) as response: assert response.status == 200 - spans = memory_exporter.get_finished_spans() + spans = test_base.get_finished_spans() assert len(spans) == 1 span = spans[0] @@ -764,7 +701,7 @@ async def test_semantic_conventions_metrics_both( assert span.attributes.get(HTTP_RESPONSE_STATUS_CODE) == 200 assert span.attributes.get(HTTP_ROUTE) == "default_handler" - metrics = _get_sorted_metrics(metrics_reader.get_metrics_data()) + metrics = test_base.get_sorted_metrics() assert len(metrics) == 3 # Both duration metrics + active requests server_active_requests_count_attrs_both = list( _server_active_requests_count_attrs_old