Skip to content

Commit 0a3f2c3

Browse files
gnufedebrettlangdon
authored andcommitted
chore(ci_visibility): change unexpected coverage format error logging (#14089)
1 parent dee2032 commit 0a3f2c3

File tree

2 files changed

+137
-2
lines changed

2 files changed

+137
-2
lines changed

ddtrace/contrib/internal/pytest/_plugin_v2.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -824,8 +824,16 @@ def _pytest_sessionfinish(session: pytest.Session, exitstatus: int) -> None:
824824
run_coverage_report()
825825

826826
lines_pct_value = _coverage_data.get(PCT_COVERED_KEY, None)
827-
if not isinstance(lines_pct_value, float):
828-
log.warning("Tried to add total covered percentage to session span but the format was unexpected")
827+
if lines_pct_value is None:
828+
log.debug("Unable to retrieve coverage data for the session span")
829+
elif not isinstance(lines_pct_value, (float, int)):
830+
t = type(lines_pct_value)
831+
log.warning(
832+
"Unexpected format for total covered percentage: type=%s.%s, value=%r",
833+
t.__module__,
834+
t.__name__,
835+
lines_pct_value,
836+
)
829837
else:
830838
InternalTestSession.set_covered_lines_pct(lines_pct_value)
831839

tests/contrib/pytest/test_pytest.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4182,3 +4182,130 @@ def test_dependency_collection_disabled():
41824182

41834183
result = self.subprocess_run("--ddtrace", file_name)
41844184
assert result.ret == 0
4185+
4186+
4187+
def test_pytest_coverage_data_format_handling_none_value():
4188+
"""Test that coverage data format issues are handled correctly with proper logging for None value."""
4189+
from ddtrace.contrib.internal.coverage.constants import PCT_COVERED_KEY
4190+
from ddtrace.contrib.internal.pytest._plugin_v2 import _pytest_sessionfinish
4191+
4192+
# Create a mock session object
4193+
mock_session = mock.MagicMock()
4194+
mock_session.exitstatus = 0
4195+
4196+
ci_visibility_instance = mock.MagicMock(spec=CIVisibility)
4197+
4198+
# Test case 1: coverage data is None
4199+
with mock.patch(
4200+
"ddtrace.contrib.internal.pytest._plugin_v2._coverage_data",
4201+
{PCT_COVERED_KEY: None},
4202+
), mock.patch(
4203+
"ddtrace.ext.test_visibility.api.require_ci_visibility_service",
4204+
return_value=ci_visibility_instance,
4205+
), mock.patch(
4206+
"ddtrace.contrib.internal.pytest._plugin_v2.is_test_visibility_enabled",
4207+
return_value=True,
4208+
), mock.patch(
4209+
"ddtrace.contrib.internal.pytest._plugin_v2._is_coverage_patched",
4210+
return_value=True,
4211+
), mock.patch(
4212+
"ddtrace.contrib.internal.pytest._plugin_v2._is_coverage_invoked_by_coverage_run",
4213+
return_value=True,
4214+
), mock.patch(
4215+
"ddtrace.contrib.internal.pytest._plugin_v2.run_coverage_report"
4216+
), mock.patch(
4217+
"ddtrace.internal.test_visibility.api.InternalTestSession.set_covered_lines_pct"
4218+
) as mock_set_covered_lines_pct, mock.patch(
4219+
"ddtrace.contrib.internal.pytest._plugin_v2.log"
4220+
) as mock_log:
4221+
_pytest_sessionfinish(mock_session, 0)
4222+
4223+
mock_log.debug.assert_called_with("Unable to retrieve coverage data for the session span")
4224+
mock_set_covered_lines_pct.assert_not_called()
4225+
4226+
4227+
def test_pytest_coverage_data_format_handling_invalid_type():
4228+
"""Test that coverage data format issues are handled correctly with proper logging for invalid value."""
4229+
from ddtrace.contrib.internal.coverage.constants import PCT_COVERED_KEY
4230+
from ddtrace.contrib.internal.pytest._plugin_v2 import _pytest_sessionfinish
4231+
4232+
# Create a mock session object
4233+
mock_session = mock.MagicMock()
4234+
mock_session.exitstatus = 0
4235+
4236+
ci_visibility_instance = mock.MagicMock(spec=CIVisibility)
4237+
4238+
# Test case 2: coverage data is not a float (e.g., string)
4239+
invalid_value = "not_a_float"
4240+
with mock.patch(
4241+
"ddtrace.contrib.internal.pytest._plugin_v2._coverage_data",
4242+
{PCT_COVERED_KEY: invalid_value},
4243+
), mock.patch(
4244+
"ddtrace.ext.test_visibility.api.require_ci_visibility_service",
4245+
return_value=ci_visibility_instance,
4246+
), mock.patch(
4247+
"ddtrace.contrib.internal.pytest._plugin_v2.is_test_visibility_enabled",
4248+
return_value=True,
4249+
), mock.patch(
4250+
"ddtrace.contrib.internal.pytest._plugin_v2._is_coverage_patched",
4251+
return_value=True,
4252+
), mock.patch(
4253+
"ddtrace.contrib.internal.pytest._plugin_v2._is_coverage_invoked_by_coverage_run",
4254+
return_value=True,
4255+
), mock.patch(
4256+
"ddtrace.contrib.internal.pytest._plugin_v2.run_coverage_report"
4257+
), mock.patch(
4258+
"ddtrace.internal.test_visibility.api.InternalTestSession.set_covered_lines_pct"
4259+
) as mock_set_covered_lines_pct, mock.patch(
4260+
"ddtrace.contrib.internal.pytest._plugin_v2.log"
4261+
) as mock_log:
4262+
_pytest_sessionfinish(mock_session, 0)
4263+
4264+
mock_log.warning.assert_called_with(
4265+
"Unexpected format for total covered percentage: type=%s.%s, value=%r",
4266+
"builtins",
4267+
"str",
4268+
invalid_value,
4269+
)
4270+
mock_set_covered_lines_pct.assert_not_called()
4271+
4272+
4273+
@pytest.mark.parametrize("valid_value", [75, 86.01])
4274+
def test_pytest_coverage_data_format_handling_valid_values(valid_value):
4275+
"""Test that coverage data format issues are handled correctly with proper logging."""
4276+
from ddtrace.contrib.internal.coverage.constants import PCT_COVERED_KEY
4277+
from ddtrace.contrib.internal.pytest._plugin_v2 import _pytest_sessionfinish
4278+
4279+
# Create a mock session object
4280+
mock_session = mock.MagicMock()
4281+
mock_session.exitstatus = 0
4282+
4283+
ci_visibility_instance = mock.MagicMock(spec=CIVisibility)
4284+
4285+
with mock.patch(
4286+
"ddtrace.contrib.internal.pytest._plugin_v2._coverage_data", {PCT_COVERED_KEY: valid_value}
4287+
), mock.patch(
4288+
"ddtrace.ext.test_visibility.api.require_ci_visibility_service",
4289+
return_value=ci_visibility_instance,
4290+
), mock.patch(
4291+
"ddtrace.contrib.internal.pytest._plugin_v2.is_test_visibility_enabled",
4292+
return_value=True,
4293+
), mock.patch(
4294+
"ddtrace.contrib.internal.pytest._plugin_v2._is_coverage_patched",
4295+
return_value=True,
4296+
), mock.patch(
4297+
"ddtrace.contrib.internal.pytest._plugin_v2._is_coverage_invoked_by_coverage_run",
4298+
return_value=True,
4299+
), mock.patch(
4300+
"ddtrace.contrib.internal.pytest._plugin_v2.run_coverage_report"
4301+
), mock.patch(
4302+
"ddtrace.internal.test_visibility.api.InternalTestSession.set_covered_lines_pct"
4303+
) as mock_set_covered_lines_pct, mock.patch(
4304+
"ddtrace.contrib.internal.pytest._plugin_v2.log"
4305+
) as mock_log:
4306+
_pytest_sessionfinish(mock_session, 0)
4307+
4308+
# No warning or debug should be called for valid case
4309+
mock_log.warning.assert_not_called()
4310+
mock_log.debug.assert_not_called()
4311+
mock_set_covered_lines_pct.assert_called_once_with(valid_value)

0 commit comments

Comments
 (0)