From 660ff5360689d66d83bb96e165d7cd8040633290 Mon Sep 17 00:00:00 2001 From: dataflow-solutions-sk Date: Sun, 9 Aug 2026 17:45:21 +0200 Subject: [PATCH] Fix OTLP gRPC exporter tests connecting via ambiguous 'localhost' hostname The mock gRPC server used by test_otlp_exporter_mixin.py binds only to the IPv4 loopback address (127.0.0.1), but the tests that actually exercise real connections to that server relied on the exporter's default endpoint, which resolves the ambiguous hostname 'localhost'. On environments where 'localhost' resolves to the IPv6 loopback address (::1) first, the exporter would try to connect to whatever (if anything) is listening on ::1:4317 instead of the mock server, causing confusing, environment-dependent test failures/hangs. Give OTLPSpanExporterForTesting an explicit default endpoint of http://127.0.0.1:4317 (only applied when the test doesn't already pass its own endpoint, e.g. test_otlp_exporter_endpoint), matching the address the mock server actually binds to. Update the couple of assertions that hard-coded the old 'localhost:4317' string for exporters that now connect via 127.0.0.1. Tests in test_otlp_trace_exporter.py and test_otlp_metrics_exporter.py only assert against mocked channels (never make a real connection) and still validate the production default endpoint value, so they are left untouched. Assisted-by: Claude Sonnet 5 --- .../tests/test_otlp_exporter_mixin.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_exporter_mixin.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_exporter_mixin.py index b874a4c777..e2be41fb05 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_exporter_mixin.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_exporter_mixin.py @@ -75,6 +75,14 @@ class OTLPSpanExporterForTesting( ], ): def __init__(self, **kwargs): + # Default to the explicit IPv4 loopback address rather than + # "localhost", which can resolve to the IPv6 loopback address + # ("::1") first depending on the OS/environment. The mock server + # used by these tests only binds to 127.0.0.1, so resolving + # "localhost" to ::1 would cause tests to try to connect to an + # unrelated service (if any) listening on ::1:4317 instead of the + # mock server, producing confusing, environment-dependent failures. + kwargs.setdefault("endpoint", "http://127.0.0.1:4317") super().__init__( TraceServiceStub, SpanExportResult, @@ -277,7 +285,7 @@ def test_otlp_exporter_otlp_compression_unspecified(self, mock_insecure_channel) """No env or kwarg should be NoCompression""" OTLPSpanExporterForTesting(insecure=True) mock_insecure_channel.assert_called_once_with( - "localhost:4317", + "127.0.0.1:4317", compression=Compression.NoCompression, options=( ( @@ -339,7 +347,7 @@ def test_otlp_exporter_otlp_compression_envvar(self, mock_insecure_channel): """Just OTEL_EXPORTER_OTLP_COMPRESSION should work""" OTLPSpanExporterForTesting(insecure=True) mock_insecure_channel.assert_called_once_with( - "localhost:4317", + "127.0.0.1:4317", compression=Compression.Gzip, options=( ( @@ -529,7 +537,7 @@ def test_timeout_set_correctly(self): ) after = time.time() self.assertEqual( - "Failed to export traces to localhost:4317, error code: StatusCode.DEADLINE_EXCEEDED, error details: Deadline Exceeded", + "Failed to export traces to 127.0.0.1:4317, error code: StatusCode.DEADLINE_EXCEEDED, error details: Deadline Exceeded", warning.records[-1].message, ) self.assertEqual(mock_trace_service.num_requests, 2) @@ -565,7 +573,7 @@ def test_permanent_failure(self): self.assertEqual(exporter.export([self.span]), SpanExportResult.FAILURE) self.assertEqual( warning.records[-1].message, - "Failed to export traces to localhost:4317, error code: StatusCode.ALREADY_EXISTS, error details: This already exists.", + "Failed to export traces to 127.0.0.1:4317, error code: StatusCode.ALREADY_EXISTS, error details: This already exists.", ) metrics_data = self.metric_reader.get_metrics_data() @@ -683,5 +691,5 @@ def test_retryable_error_codes_custom(self): def assert_standard_metric_attrs(self, attributes): self.assertEqual(attributes["otel.component.type"], "otlp_grpc_span_exporter") self.assertTrue(attributes["otel.component.name"].startswith("otlp_grpc_span_exporter/")) - self.assertEqual(attributes["server.address"], "localhost") + self.assertEqual(attributes["server.address"], "127.0.0.1") self.assertEqual(attributes["server.port"], 4317)