diff --git a/tests/unit/test_configurator/test_configurator_metrics_exporter.py b/tests/unit/test_configurator/test_configurator_metrics_exporter.py index 4887a2d0..1d7f30e7 100644 --- a/tests/unit/test_configurator/test_configurator_metrics_exporter.py +++ b/tests/unit/test_configurator/test_configurator_metrics_exporter.py @@ -201,3 +201,154 @@ def test_configure_metrics_exporter_valid( # Restore old EXPORTER if old_metrics_exporter: os.environ["OTEL_METRICS_EXPORTER"] = old_metrics_exporter + + def test_configure_metrics_exporter_invalid_valid_mixed( + self, + mocker, + mock_apmconfig_enabled_expt, + mock_pemreader, + mock_resource, + ): + # Save any EXPORTER env var for later + old_metrics_exporter = os.environ.get("OTEL_METRICS_EXPORTER", None) + if old_metrics_exporter: + del os.environ["OTEL_METRICS_EXPORTER"] + + # Mock entry points + mock_exporter_class = mocker.MagicMock() + mock_exporter_entry_point = mocker.Mock() + mock_exporter_class_invalid = mocker.Mock() + mock_exporter_class_invalid.configure_mock( + side_effect=Exception("mock error invalid exporter") + ) + mock_exporter_entry_point_invalid = mocker.Mock() + mock_exporter_entry_point_invalid.configure_mock( + **{ + "load": mock_exporter_class_invalid + } + ) + mock_points = iter( + [ + mock_exporter_entry_point_invalid, + mock_exporter_entry_point, + ] + ) + mock_iter_entry_points = mocker.patch( + "solarwinds_apm.configurator.iter_entry_points" + ) + mock_iter_entry_points.configure_mock( + return_value=mock_points + ) + mocker.patch.dict( + os.environ, + { + "OTEL_METRICS_EXPORTER": "invalid_exporter,valid_exporter" + } + ) + + # Mock Otel + mock_metrics, mock_set_meter_provider, mock_meter_provider = get_metrics_mocks(mocker) + + mock_trace, mock_get_tracer_provider, mock_add_span_processor, mock_tracer = get_trace_mocks(mocker) + + # Test! + test_configurator = configurator.SolarWindsConfigurator() + with pytest.raises(Exception): + test_configurator._configure_metrics_exporter( + mock_apmconfig_enabled_expt, + ) + # Only called once before exception + mock_iter_entry_points.assert_has_calls( + [ + mocker.call("opentelemetry_metrics_exporter", "invalid_exporter"), + ] + ) + # Not called at all + mock_pemreader.assert_not_called() + mock_get_tracer_provider.assert_not_called() + mock_tracer.assert_not_called() + mock_set_meter_provider.assert_not_called() + mock_meter_provider.assert_not_called() + + # Restore old EXPORTER + if old_metrics_exporter: + os.environ["OTEL_METRICS_EXPORTER"] = old_metrics_exporter + + def test_configure_metrics_exporter_valid_invalid_mixed( + self, + mocker, + mock_apmconfig_enabled_expt, + mock_pemreader, + mock_resource, + ): + # Save any EXPORTER env var for later + old_metrics_exporter = os.environ.get("OTEL_METRICS_EXPORTER", None) + if old_metrics_exporter: + del os.environ["OTEL_METRICS_EXPORTER"] + + # Mock entry points + mock_exporter_class = mocker.MagicMock() + mock_exporter_entry_point = mocker.Mock() + mock_exporter_entry_point.configure_mock( + **{ + "load": mock_exporter_class + } + ) + mock_exporter_class_invalid = mocker.Mock() + mock_exporter_class_invalid.configure_mock( + side_effect=Exception("mock error invalid exporter") + ) + mock_exporter_entry_point_invalid = mocker.Mock() + mock_exporter_entry_point_invalid.configure_mock( + **{ + "load": mock_exporter_class_invalid + } + ) + + mock_points = iter( + [ + mock_exporter_entry_point, + mock_exporter_entry_point_invalid, + ] + ) + mock_iter_entry_points = mocker.patch( + "solarwinds_apm.configurator.iter_entry_points" + ) + mock_iter_entry_points.configure_mock( + return_value=mock_points + ) + mocker.patch.dict( + os.environ, + { + "OTEL_METRICS_EXPORTER": "valid_exporter,invalid_exporter" + } + ) + + # Mock Otel + mock_metrics, mock_set_meter_provider, mock_meter_provider = get_metrics_mocks(mocker) + + mock_trace, mock_get_tracer_provider, mock_add_span_processor, mock_tracer = get_trace_mocks(mocker) + + # Test! + test_configurator = configurator.SolarWindsConfigurator() + with pytest.raises(Exception): + test_configurator._configure_metrics_exporter( + mock_apmconfig_enabled_expt, + ) + mock_iter_entry_points.assert_has_calls( + [ + mocker.call("opentelemetry_metrics_exporter", "valid_exporter"), + mocker.call("opentelemetry_metrics_exporter", "invalid_exporter"), + ] + ) + # Called for the valid one + mock_pemreader.assert_called_once() + # Rest not called at all + mock_get_tracer_provider.assert_not_called() + mock_tracer.assert_not_called() + mock_set_meter_provider.assert_not_called() + mock_meter_provider.assert_not_called() + + # Restore old EXPORTER + if old_metrics_exporter: + os.environ["OTEL_METRICS_EXPORTER"] = old_metrics_exporter \ No newline at end of file diff --git a/tests/unit/test_configurator/test_configurator_traces_exporter.py b/tests/unit/test_configurator/test_configurator_traces_exporter.py index 69274df4..24521307 100644 --- a/tests/unit/test_configurator/test_configurator_traces_exporter.py +++ b/tests/unit/test_configurator/test_configurator_traces_exporter.py @@ -185,3 +185,164 @@ def test_configure_traces_exporter_valid( # Restore old EXPORTER if old_traces_exporter: os.environ["OTEL_TRACES_EXPORTER"] = old_traces_exporter + + def test_configure_traces_exporter_invalid_valid_mixed( + self, + mocker, + mock_reporter, + mock_txn_name_manager, + mock_fwkv_manager, + mock_apmconfig_enabled, + mock_bsprocessor, + ): + # Save any EXPORTER env var for later + old_traces_exporter = os.environ.get("OTEL_TRACES_EXPORTER", None) + if old_traces_exporter: + del os.environ["OTEL_TRACES_EXPORTER"] + + + # Mock entry points + mock_exporter_class = mocker.MagicMock() + mock_exporter_entry_point = mocker.Mock() + mock_exporter_entry_point.configure_mock( + **{ + "load": mock_exporter_class + } + ) + mock_exporter_class_invalid = mocker.Mock() + mock_exporter_class_invalid.configure_mock( + side_effect=Exception("mock error invalid exporter") + ) + mock_exporter_entry_point_invalid = mocker.Mock() + mock_exporter_entry_point_invalid.configure_mock( + **{ + "load": mock_exporter_class_invalid + } + ) + + mock_points = iter( + [ + mock_exporter_entry_point_invalid, + mock_exporter_entry_point, + ] + ) + mock_iter_entry_points = mocker.patch( + "solarwinds_apm.configurator.iter_entry_points" + ) + mock_iter_entry_points.configure_mock( + return_value=mock_points + ) + + mocker.patch.dict( + os.environ, + { + "OTEL_TRACES_EXPORTER": "invalid_exporter,valid_exporter" + } + ) + + # Mock Otel + _, mock_get_tracer_provider, mock_add_span_processor, _ = get_trace_mocks(mocker) + + # Test! + test_configurator = configurator.SolarWindsConfigurator() + with pytest.raises(Exception): + test_configurator._configure_traces_exporter( + mock_reporter, + mock_txn_name_manager, + mock_fwkv_manager, + mock_apmconfig_enabled, + ) + # Only called once before exception + mock_iter_entry_points.assert_has_calls( + [ + mocker.call("opentelemetry_traces_exporter", "invalid_exporter"), + ] + ) + # Not called at all + mock_bsprocessor.assert_not_called() + mock_get_tracer_provider.assert_not_called() + mock_add_span_processor.assert_not_called() + + # Restore old EXPORTER + if old_traces_exporter: + os.environ["OTEL_TRACES_EXPORTER"] = old_traces_exporter + + def test_configure_traces_exporter_valid_invalid_mixed( + self, + mocker, + mock_reporter, + mock_txn_name_manager, + mock_fwkv_manager, + mock_apmconfig_enabled, + mock_bsprocessor, + ): + # Save any EXPORTER env var for later + old_traces_exporter = os.environ.get("OTEL_TRACES_EXPORTER", None) + if old_traces_exporter: + del os.environ["OTEL_TRACES_EXPORTER"] + + # Mock entry points + mock_exporter_class = mocker.MagicMock() + mock_exporter_entry_point = mocker.Mock() + mock_exporter_entry_point.configure_mock( + **{ + "load": mock_exporter_class + } + ) + mock_exporter_class_invalid = mocker.Mock() + mock_exporter_class_invalid.configure_mock( + side_effect=Exception("mock error invalid exporter") + ) + mock_exporter_entry_point_invalid = mocker.Mock() + mock_exporter_entry_point_invalid.configure_mock( + **{ + "load": mock_exporter_class_invalid + } + ) + + mock_points = iter( + [ + mock_exporter_entry_point, + mock_exporter_entry_point_invalid, + ] + ) + mock_iter_entry_points = mocker.patch( + "solarwinds_apm.configurator.iter_entry_points" + ) + mock_iter_entry_points.configure_mock( + return_value=mock_points + ) + + mocker.patch.dict( + os.environ, + { + "OTEL_TRACES_EXPORTER": "valid_exporter,invalid_exporter" + } + ) + + # Mock Otel + _, mock_get_tracer_provider, mock_add_span_processor, _ = get_trace_mocks(mocker) + + # Test! + test_configurator = configurator.SolarWindsConfigurator() + with pytest.raises(Exception): + test_configurator._configure_traces_exporter( + mock_reporter, + mock_txn_name_manager, + mock_fwkv_manager, + mock_apmconfig_enabled, + ) + mock_iter_entry_points.assert_has_calls( + [ + mocker.call("opentelemetry_traces_exporter", "valid_exporter"), + mocker.call("opentelemetry_traces_exporter", "invalid_exporter"), + ] + ) + # Ends up called once for the valid exporter + mock_bsprocessor.assert_called_once() + mock_get_tracer_provider.assert_called_once() + mock_add_span_processor.assert_called_once() + + # Restore old EXPORTER + if old_traces_exporter: + os.environ["OTEL_TRACES_EXPORTER"] = old_traces_exporter \ No newline at end of file