diff --git a/CHANGELOG.md b/CHANGELOG.md index 89d8599419d..7a1cd452338 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgrade markupsafe, Flask and related dependencies to dev and test environments ([#3609](https://github.com/open-telemetry/opentelemetry-python/pull/3609)) +- Handle HTTP 2XX responses as successful in OTLP exporters + ([#3623](https://github.com/open-telemetry/opentelemetry-python/pull/3623)) +- Improve Resource Detector timeout messaging + ([#3645](https://github.com/open-telemetry/opentelemetry-python/pull/3645)) ## Version 1.22.0/0.43b0 (2023-12-15) -- Prometheus exporter sanitize info metric ([#3572](https://github.com/open-telemetry/opentelemetry-python/pull/3572)) +- Prometheus exporter sanitize info metric + ([#3572](https://github.com/open-telemetry/opentelemetry-python/pull/3572)) - Remove Jaeger exporters ([#3554](https://github.com/open-telemetry/opentelemetry-python/pull/3554)) - Log stacktrace on `UNKNOWN` status OTLP export error diff --git a/docs/examples/opencensus-exporter-tracer/collector.py b/docs/examples/opencensus-exporter-tracer/collector.py index 5c98cc4ce9f..cd33c89617b 100644 --- a/docs/examples/opencensus-exporter-tracer/collector.py +++ b/docs/examples/opencensus-exporter-tracer/collector.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/pyproject.toml b/exporter/opentelemetry-exporter-otlp-proto-http/pyproject.toml index d7503773013..dfab84f6f92 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/pyproject.toml +++ b/exporter/opentelemetry-exporter-otlp-proto-http/pyproject.toml @@ -38,7 +38,7 @@ dependencies = [ [project.optional-dependencies] test = [ - "responses == 0.22.0", + "responses >= 0.22.0, < 0.25", ] [project.entry-points.opentelemetry_traces_exporter] diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py index caacdbdfcab..4703b102863 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py @@ -146,7 +146,7 @@ def export(self, batch: Sequence[LogData]) -> LogExportResult: resp = self._export(serialized_data) # pylint: disable=no-else-return - if resp.status_code in (200, 202): + if resp.ok: return LogExportResult.SUCCESS elif self._retryable(resp): _logger.warning( diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/metric_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/metric_exporter/__init__.py index ed878dabe87..becdab257fe 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/metric_exporter/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/metric_exporter/__init__.py @@ -178,7 +178,7 @@ def export( resp = self._export(serialized_data.SerializeToString()) # pylint: disable=no-else-return - if resp.status_code in (200, 202): + if resp.ok: return MetricExportResult.SUCCESS elif self._retryable(resp): _logger.warning( diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py index 2ab7e97e026..d98a1b84a75 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py @@ -144,7 +144,7 @@ def export(self, spans) -> SpanExportResult: resp = self._export(serialized_data) # pylint: disable=no-else-return - if resp.status_code in (200, 202): + if resp.ok: return SpanExportResult.SUCCESS elif self._retryable(resp): _logger.warning( diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/metrics/test_otlp_metrics_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/metrics/test_otlp_metrics_exporter.py index d9011322b92..c06b5db3c22 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/metrics/test_otlp_metrics_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/metrics/test_otlp_metrics_exporter.py @@ -15,7 +15,7 @@ from logging import WARNING from os import environ from unittest import TestCase -from unittest.mock import patch +from unittest.mock import MagicMock, Mock, patch from requests import Session from requests.models import Response @@ -476,3 +476,14 @@ def test_exponential_explicit_bucket_histogram(self): OTLPMetricExporter()._preferred_aggregation[Histogram], ExplicitBucketHistogramAggregation, ) + + @patch.object(OTLPMetricExporter, "_export", return_value=Mock(ok=True)) + def test_2xx_status_code(self, mock_otlp_metric_exporter): + """ + Test that any HTTP 2XX code returns a successful result + """ + + self.assertEqual( + OTLPMetricExporter().export(MagicMock()), + MetricExportResult.SUCCESS, + ) diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py index 5300ce85dee..e601e5d00cb 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py @@ -16,7 +16,7 @@ import unittest from typing import List -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock, Mock, patch import requests import responses @@ -34,6 +34,7 @@ from opentelemetry.exporter.otlp.proto.http.version import __version__ from opentelemetry.sdk._logs import LogData from opentelemetry.sdk._logs import LogRecord as SDKLogRecord +from opentelemetry.sdk._logs.export import LogExportResult from opentelemetry.sdk.environment_variables import ( OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_COMPRESSION, @@ -262,3 +263,13 @@ def _get_sdk_log_data() -> List[LogData]: ) return [log1, log2, log3, log4] + + @patch.object(OTLPLogExporter, "_export", return_value=Mock(ok=True)) + def test_2xx_status_code(self, mock_otlp_metric_exporter): + """ + Test that any HTTP 2XX code returns a successful result + """ + + self.assertEqual( + OTLPLogExporter().export(MagicMock()), LogExportResult.SUCCESS + ) diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py index 9a1d1604a25..eb5b375e40d 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py @@ -14,7 +14,7 @@ import unittest from collections import OrderedDict -from unittest.mock import Mock, patch +from unittest.mock import MagicMock, Mock, patch import requests import responses @@ -42,6 +42,7 @@ OTEL_EXPORTER_OTLP_TRACES_TIMEOUT, ) from opentelemetry.sdk.trace import _Span +from opentelemetry.sdk.trace.export import SpanExportResult OS_ENV_ENDPOINT = "os.env.base" OS_ENV_CERTIFICATE = "os/env/base.crt" @@ -239,3 +240,13 @@ def generate_delays(*args, **kwargs): exporter.export([span]) mock_sleep.assert_called_once_with(1) + + @patch.object(OTLPSpanExporter, "_export", return_value=Mock(ok=True)) + def test_2xx_status_code(self, mock_otlp_metric_exporter): + """ + Test that any HTTP 2XX code returns a successful result + """ + + self.assertEqual( + OTLPSpanExporter().export(MagicMock()), SpanExportResult.SUCCESS + ) diff --git a/exporter/opentelemetry-exporter-otlp/tests/test_otlp.py b/exporter/opentelemetry-exporter-otlp/tests/test_otlp.py index 5b574a9d603..7e180022895 100644 --- a/exporter/opentelemetry-exporter-otlp/tests/test_otlp.py +++ b/exporter/opentelemetry-exporter-otlp/tests/test_otlp.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import unittest from opentelemetry.exporter.otlp.proto.grpc._log_exporter import ( OTLPLogExporter, @@ -26,9 +25,10 @@ from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( OTLPSpanExporter as HTTPSpanExporter, ) +from opentelemetry.test import TestCase -class TestOTLPExporters(unittest.TestCase): +class TestOTLPExporters(TestCase): def test_constructors(self): for exporter in [ OTLPSpanExporter, @@ -36,9 +36,5 @@ def test_constructors(self): OTLPLogExporter, OTLPMetricExporter, ]: - try: + with self.assertNotRaises(Exception): exporter() - except Exception: # pylint: disable=broad-except - self.fail( - f"Unexpected exception raised when instantiating {exporter.__name__}" - ) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py index f92fdb964e0..852b23f5002 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py @@ -390,6 +390,14 @@ def get_aggregated_resources( detected_resource: Resource = _EMPTY_RESOURCE try: detected_resource = future.result(timeout=timeout) + except concurrent.futures.TimeoutError as ex: + if detector.raise_on_error: + raise ex + logger.warning( + "Detector %s took longer than %s seconds, skipping", + detector, + timeout, + ) # pylint: disable=broad-except except Exception as ex: if detector.raise_on_error: diff --git a/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponent_mapping.py b/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponent_mapping.py index ae06d963abd..96ba3991819 100644 --- a/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponent_mapping.py +++ b/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponent_mapping.py @@ -14,7 +14,6 @@ from math import inf from sys import float_info, version_info -from unittest import TestCase from unittest.mock import patch from pytest import mark @@ -31,6 +30,7 @@ MIN_NORMAL_EXPONENT, MIN_NORMAL_VALUE, ) +from opentelemetry.test import TestCase if version_info >= (3, 9): from math import nextafter @@ -69,12 +69,9 @@ def test_init_called_once(self, mock_init): def test_exponent_mapping_0(self): - try: + with self.assertNotRaises(Exception): ExponentMapping(0) - except Exception as error: - self.fail(f"Unexpected exception raised: {error}") - def test_exponent_mapping_zero(self): exponent_mapping = ExponentMapping(0) diff --git a/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponential_bucket_histogram_aggregation.py b/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponential_bucket_histogram_aggregation.py index 9bea75e426b..311f00a0b00 100644 --- a/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponential_bucket_histogram_aggregation.py +++ b/opentelemetry-sdk/tests/metrics/exponential_histogram/test_exponential_bucket_histogram_aggregation.py @@ -17,7 +17,6 @@ from math import ldexp from sys import float_info from types import MethodType -from unittest import TestCase from unittest.mock import Mock, patch from opentelemetry.sdk.metrics._internal.aggregation import ( @@ -41,6 +40,7 @@ from opentelemetry.sdk.metrics.view import ( ExponentialBucketHistogramAggregation, ) +from opentelemetry.test import TestCase def get_counts(buckets: Buckets) -> int: @@ -793,11 +793,8 @@ def test_boundary_statistics(self): index = mapping.map_to_index(value) - try: + with self.assertNotRaises(Exception): boundary = mapping.get_lower_boundary(index + 1) - except Exception as error: - raise error - self.fail(f"Unexpected exception {error} raised") if boundary < value: above += 1 @@ -836,30 +833,6 @@ def test_aggregate_collect(self): """ Tests a repeated cycle of aggregation and collection. """ - """ - try: - exponential_histogram_aggregation = ( - _ExponentialBucketHistogramAggregation( - Mock(), - Mock(), - ) - ) - - exponential_histogram_aggregation.aggregate(Measurement(2, Mock())) - exponential_histogram_aggregation.collect( - AggregationTemporality.CUMULATIVE, 0 - ) - exponential_histogram_aggregation.aggregate(Measurement(2, Mock())) - exponential_histogram_aggregation.collect( - AggregationTemporality.CUMULATIVE, 0 - ) - exponential_histogram_aggregation.aggregate(Measurement(2, Mock())) - exponential_histogram_aggregation.collect( - AggregationTemporality.CUMULATIVE, 0 - ) - except Exception as error: - self.fail(f"Unexpected exception raised: {error}") - """ exponential_histogram_aggregation = ( _ExponentialBucketHistogramAggregation( Mock(), diff --git a/opentelemetry-sdk/tests/metrics/test_backward_compat.py b/opentelemetry-sdk/tests/metrics/test_backward_compat.py index 7f8fff2acf2..46008554fe6 100644 --- a/opentelemetry-sdk/tests/metrics/test_backward_compat.py +++ b/opentelemetry-sdk/tests/metrics/test_backward_compat.py @@ -26,7 +26,6 @@ """ from typing import Iterable, Sequence -from unittest import TestCase from opentelemetry.metrics import CallbackOptions, Observation from opentelemetry.sdk.metrics import MeterProvider @@ -38,6 +37,7 @@ MetricReader, PeriodicExportingMetricReader, ) +from opentelemetry.test import TestCase # Do not change these classes until after major version 1 @@ -82,30 +82,24 @@ def test_metric_exporter(self): ) # produce some data meter_provider.get_meter("foo").create_counter("mycounter").add(12) - try: + with self.assertNotRaises(Exception): meter_provider.shutdown() - except Exception: - self.fail() def test_metric_reader(self): reader = OrigMetricReader() meter_provider = MeterProvider(metric_readers=[reader]) # produce some data meter_provider.get_meter("foo").create_counter("mycounter").add(12) - try: + with self.assertNotRaises(Exception): meter_provider.shutdown() - except Exception: - self.fail() def test_observable_callback(self): reader = InMemoryMetricReader() meter_provider = MeterProvider(metric_readers=[reader]) # produce some data meter_provider.get_meter("foo").create_counter("mycounter").add(12) - try: + with self.assertNotRaises(Exception): metrics_data = reader.get_metrics_data() - except Exception: - self.fail() self.assertEqual(len(metrics_data.resource_metrics), 1) self.assertEqual( diff --git a/opentelemetry-sdk/tests/metrics/test_import.py b/opentelemetry-sdk/tests/metrics/test_import.py index 70afa91497f..f0302e00de4 100644 --- a/opentelemetry-sdk/tests/metrics/test_import.py +++ b/opentelemetry-sdk/tests/metrics/test_import.py @@ -14,7 +14,7 @@ # pylint: disable=unused-import -from unittest import TestCase +from opentelemetry.test import TestCase class TestImport(TestCase): @@ -23,7 +23,7 @@ def test_import_init(self): Test that the metrics root module has the right symbols """ - try: + with self.assertNotRaises(Exception): from opentelemetry.sdk.metrics import ( # noqa: F401 Counter, Histogram, @@ -34,15 +34,13 @@ def test_import_init(self): ObservableUpDownCounter, UpDownCounter, ) - except Exception as error: - self.fail(f"Unexpected error {error} was raised") def test_import_export(self): """ Test that the metrics export module has the right symbols """ - try: + with self.assertNotRaises(Exception): from opentelemetry.sdk.metrics.export import ( # noqa: F401 AggregationTemporality, ConsoleMetricExporter, @@ -63,15 +61,13 @@ def test_import_export(self): ScopeMetrics, Sum, ) - except Exception as error: - self.fail(f"Unexpected error {error} was raised") def test_import_view(self): """ Test that the metrics view module has the right symbols """ - try: + with self.assertNotRaises(Exception): from opentelemetry.sdk.metrics.view import ( # noqa: F401 Aggregation, DefaultAggregation, @@ -81,5 +77,3 @@ def test_import_view(self): SumAggregation, View, ) - except Exception as error: - self.fail(f"Unexpected error {error} was raised") diff --git a/opentelemetry-sdk/tests/metrics/test_metrics.py b/opentelemetry-sdk/tests/metrics/test_metrics.py index 8373d3dfe0d..0ccadf47cee 100644 --- a/opentelemetry-sdk/tests/metrics/test_metrics.py +++ b/opentelemetry-sdk/tests/metrics/test_metrics.py @@ -16,7 +16,6 @@ from logging import WARNING from time import sleep from typing import Iterable, Sequence -from unittest import TestCase from unittest.mock import MagicMock, Mock, patch from opentelemetry.metrics import NoOpMeter @@ -40,6 +39,7 @@ ) from opentelemetry.sdk.metrics.view import SumAggregation, View from opentelemetry.sdk.resources import Resource +from opentelemetry.test import TestCase from opentelemetry.test.concurrency_test import ConcurrencyTestBase, MockFunc @@ -59,7 +59,7 @@ def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None: return True -class TestMeterProvider(ConcurrencyTestBase): +class TestMeterProvider(ConcurrencyTestBase, TestCase): def tearDown(self): MeterProvider._all_metric_readers = set() @@ -86,11 +86,9 @@ def test_register_metric_readers(self): metric_reader_0 = PeriodicExportingMetricReader(mock_exporter) metric_reader_1 = PeriodicExportingMetricReader(mock_exporter) - try: + with self.assertNotRaises(Exception): MeterProvider(metric_readers=(metric_reader_0,)) MeterProvider(metric_readers=(metric_reader_1,)) - except Exception as error: - self.fail(f"Unexpected exception {error} raised") with self.assertRaises(Exception): MeterProvider(metric_readers=(metric_reader_0,)) @@ -356,7 +354,7 @@ def setUp(self): self.meter = Meter(Mock(), Mock()) def test_repeated_instrument_names(self): - try: + with self.assertNotRaises(Exception): self.meter.create_counter("counter") self.meter.create_up_down_counter("up_down_counter") self.meter.create_observable_counter( @@ -369,8 +367,6 @@ def test_repeated_instrument_names(self): self.meter.create_observable_up_down_counter( "observable_up_down_counter", callbacks=[Mock()] ) - except Exception as error: - self.fail(f"Unexpected exception raised {error}") for instrument_name in [ "counter", diff --git a/opentelemetry-sdk/tests/resources/test_resources.py b/opentelemetry-sdk/tests/resources/test_resources.py index 53ecf30cab9..da3f9469617 100644 --- a/opentelemetry-sdk/tests/resources/test_resources.py +++ b/opentelemetry-sdk/tests/resources/test_resources.py @@ -15,6 +15,7 @@ import sys import unittest import uuid +from concurrent.futures import TimeoutError from logging import ERROR, WARNING from os import environ from unittest.mock import Mock, patch @@ -420,6 +421,23 @@ def test_resource_detector_raise_error(self): Exception, get_aggregated_resources, [resource_detector] ) + @patch("opentelemetry.sdk.resources.logger") + def test_resource_detector_timeout(self, mock_logger): + resource_detector = Mock(spec=ResourceDetector) + resource_detector.detect.side_effect = TimeoutError() + resource_detector.raise_on_error = False + self.assertEqual( + get_aggregated_resources([resource_detector]), + _DEFAULT_RESOURCE.merge( + Resource({SERVICE_NAME: "unknown_service"}, "") + ), + ) + mock_logger.warning.assert_called_with( + "Detector %s took longer than %s seconds, skipping", + resource_detector, + 5, + ) + @patch.dict( environ, {"OTEL_RESOURCE_ATTRIBUTES": "key1=env_value1,key2=env_value2"}, diff --git a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py index 81187389a16..a836cdf4033 100644 --- a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py +++ b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import unittest from unittest.mock import Mock import opentelemetry.trace as trace_api @@ -24,6 +23,7 @@ ) from opentelemetry.sdk import trace from opentelemetry.sdk.trace import id_generator +from opentelemetry.test import TestCase FORMAT = jaeger.JaegerPropagator() @@ -57,7 +57,7 @@ def get_context_new_carrier(old_carrier, carrier_baggage=None): return ctx, new_carrier -class TestJaegerPropagator(unittest.TestCase): +class TestJaegerPropagator(TestCase): @classmethod def setUpClass(cls): generator = id_generator.RandomIdGenerator() @@ -236,7 +236,5 @@ def test_non_recording_span_does_not_crash(self): mock_setter = Mock() span = trace_api.NonRecordingSpan(trace_api.SpanContext(1, 1, True)) with trace_api.use_span(span, end_on_exit=True): - try: + with self.assertNotRaises(Exception): FORMAT.inject({}, setter=mock_setter) - except Exception as exc: # pylint: disable=broad-except - self.fail(f"Injecting failed for NonRecordingSpan with {exc}") diff --git a/tests/opentelemetry-test-utils/src/opentelemetry/test/__init__.py b/tests/opentelemetry-test-utils/src/opentelemetry/test/__init__.py new file mode 100644 index 00000000000..068ed12e86c --- /dev/null +++ b/tests/opentelemetry-test-utils/src/opentelemetry/test/__init__.py @@ -0,0 +1,55 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# type: ignore + +from traceback import format_tb +from unittest import TestCase + + +class _AssertNotRaisesMixin: + class _AssertNotRaises: + def __init__(self, test_case): + self._test_case = test_case + + def __enter__(self): + return self + + def __exit__(self, type_, value, tb): # pylint: disable=invalid-name + if value is not None and type_ in self._exception_types: + + self._test_case.fail( + "Unexpected exception was raised:\n{}".format( + "\n".join(format_tb(tb)) + ) + ) + + return True + + def __call__(self, exception, *exceptions): + # pylint: disable=attribute-defined-outside-init + self._exception_types = (exception, *exceptions) + return self + + def __init__(self, *args, **kwargs): + + super().__init__(*args, **kwargs) + # pylint: disable=invalid-name + self.assertNotRaises = self._AssertNotRaises(self) + + +class TestCase( + _AssertNotRaisesMixin, TestCase +): # pylint: disable=function-redefined + pass diff --git a/tests/opentelemetry-test-utils/tests/__init__.py b/tests/opentelemetry-test-utils/tests/__init__.py new file mode 100644 index 00000000000..b0a6f428417 --- /dev/null +++ b/tests/opentelemetry-test-utils/tests/__init__.py @@ -0,0 +1,13 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/opentelemetry-test-utils/tests/test_utils.py b/tests/opentelemetry-test-utils/tests/test_utils.py new file mode 100644 index 00000000000..ce97951f86d --- /dev/null +++ b/tests/opentelemetry-test-utils/tests/test_utils.py @@ -0,0 +1,82 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from opentelemetry.test import TestCase + + +class TestAssertNotRaises(TestCase): + def test_no_exception(self): + + try: + + with self.assertNotRaises(Exception): + pass + + except Exception as error: # pylint: disable=broad-except + + self.fail( # pylint: disable=no-member + f"Unexpected exception {error} was raised" + ) + + def test_no_specified_exception_single(self): + + try: + + with self.assertNotRaises(KeyError): + 1 / 0 # pylint: disable=pointless-statement + + except Exception as error: # pylint: disable=broad-except + + self.fail( # pylint: disable=no-member + f"Unexpected exception {error} was raised" + ) + + def test_no_specified_exception_multiple(self): + + try: + + with self.assertNotRaises(KeyError, IndexError): + 1 / 0 # pylint: disable=pointless-statement + + except Exception as error: # pylint: disable=broad-except + + self.fail( # pylint: disable=no-member + f"Unexpected exception {error} was raised" + ) + + def test_exception(self): + + with self.assertRaises(AssertionError): + + with self.assertNotRaises(ZeroDivisionError): + 1 / 0 # pylint: disable=pointless-statement + + def test_missing_exception(self): + + with self.assertRaises(AssertionError) as error: + + with self.assertNotRaises(ZeroDivisionError): + + def raise_zero_division_error(): + raise ZeroDivisionError() + + raise_zero_division_error() + + error_lines = error.exception.args[0].split("\n") + + self.assertEqual( + error_lines[0].strip(), "Unexpected exception was raised:" + ) + self.assertEqual(error_lines[2].strip(), "raise_zero_division_error()") + self.assertEqual(error_lines[5].strip(), "raise ZeroDivisionError()") diff --git a/tests/w3c_tracecontext_validation_server.py b/tests/w3c_tracecontext_validation_server.py index d6c468025e4..5c47708ee1c 100644 --- a/tests/w3c_tracecontext_validation_server.py +++ b/tests/w3c_tracecontext_validation_server.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # Copyright The OpenTelemetry Authors # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tox.ini b/tox.ini index efce521d42d..090a2f98ab9 100644 --- a/tox.ini +++ b/tox.ini @@ -61,6 +61,9 @@ envlist = py3{7,8,9,10,11}-opentelemetry-propagator-jaeger pypy3-opentelemetry-propagator-jaeger + py3{7,8,9,10,11}-opentelemetry-test-utils + pypy3-opentelemetry-test-utils + lint spellcheck tracecontext @@ -112,6 +115,7 @@ changedir = propagator-b3: propagator/opentelemetry-propagator-b3/tests propagator-jaeger: propagator/opentelemetry-propagator-jaeger/tests + test-utils: tests/opentelemetry-test-utils/tests commands_pre = ; Install without -e to test the actual installation