|
32 | 32 | _get_installed_modules,
|
33 | 33 | _generate_installed_modules,
|
34 | 34 | ensure_integration_enabled,
|
| 35 | + to_string, |
| 36 | + exc_info_from_error, |
| 37 | + get_lines_from_file, |
| 38 | + package_version, |
35 | 39 | )
|
36 | 40 |
|
37 | 41 |
|
@@ -61,55 +65,72 @@ def _normalize_distribution_name(name):
|
61 | 65 | return re.sub(r"[-_.]+", "-", name).lower()
|
62 | 66 |
|
63 | 67 |
|
64 |
| -@pytest.mark.parametrize( |
65 |
| - ("input_str", "expected_output"), |
| 68 | +isoformat_inputs_and_datetime_outputs = ( |
66 | 69 | (
|
67 |
| - ( |
68 |
| - "2021-01-01T00:00:00.000000Z", |
69 |
| - datetime(2021, 1, 1, tzinfo=timezone.utc), |
70 |
| - ), # UTC time |
71 |
| - ( |
72 |
| - "2021-01-01T00:00:00.000000", |
73 |
| - datetime(2021, 1, 1).astimezone(timezone.utc), |
74 |
| - ), # No TZ -- assume local but convert to UTC |
75 |
| - ( |
76 |
| - "2021-01-01T00:00:00Z", |
77 |
| - datetime(2021, 1, 1, tzinfo=timezone.utc), |
78 |
| - ), # UTC - No milliseconds |
79 |
| - ( |
80 |
| - "2021-01-01T00:00:00.000000+00:00", |
81 |
| - datetime(2021, 1, 1, tzinfo=timezone.utc), |
82 |
| - ), |
83 |
| - ( |
84 |
| - "2021-01-01T00:00:00.000000-00:00", |
85 |
| - datetime(2021, 1, 1, tzinfo=timezone.utc), |
86 |
| - ), |
87 |
| - ( |
88 |
| - "2021-01-01T00:00:00.000000+0000", |
89 |
| - datetime(2021, 1, 1, tzinfo=timezone.utc), |
90 |
| - ), |
91 |
| - ( |
92 |
| - "2021-01-01T00:00:00.000000-0000", |
93 |
| - datetime(2021, 1, 1, tzinfo=timezone.utc), |
94 |
| - ), |
95 |
| - ( |
96 |
| - "2020-12-31T00:00:00.000000+02:00", |
97 |
| - datetime(2020, 12, 31, tzinfo=timezone(timedelta(hours=2))), |
98 |
| - ), # UTC+2 time |
99 |
| - ( |
100 |
| - "2020-12-31T00:00:00.000000-0200", |
101 |
| - datetime(2020, 12, 31, tzinfo=timezone(timedelta(hours=-2))), |
102 |
| - ), # UTC-2 time |
103 |
| - ( |
104 |
| - "2020-12-31T00:00:00-0200", |
105 |
| - datetime(2020, 12, 31, tzinfo=timezone(timedelta(hours=-2))), |
106 |
| - ), # UTC-2 time - no milliseconds |
| 70 | + "2021-01-01T00:00:00.000000Z", |
| 71 | + datetime(2021, 1, 1, tzinfo=timezone.utc), |
| 72 | + ), # UTC time |
| 73 | + ( |
| 74 | + "2021-01-01T00:00:00.000000", |
| 75 | + datetime(2021, 1, 1).astimezone(timezone.utc), |
| 76 | + ), # No TZ -- assume local but convert to UTC |
| 77 | + ( |
| 78 | + "2021-01-01T00:00:00Z", |
| 79 | + datetime(2021, 1, 1, tzinfo=timezone.utc), |
| 80 | + ), # UTC - No milliseconds |
| 81 | + ( |
| 82 | + "2021-01-01T00:00:00.000000+00:00", |
| 83 | + datetime(2021, 1, 1, tzinfo=timezone.utc), |
| 84 | + ), |
| 85 | + ( |
| 86 | + "2021-01-01T00:00:00.000000-00:00", |
| 87 | + datetime(2021, 1, 1, tzinfo=timezone.utc), |
| 88 | + ), |
| 89 | + ( |
| 90 | + "2021-01-01T00:00:00.000000+0000", |
| 91 | + datetime(2021, 1, 1, tzinfo=timezone.utc), |
| 92 | + ), |
| 93 | + ( |
| 94 | + "2021-01-01T00:00:00.000000-0000", |
| 95 | + datetime(2021, 1, 1, tzinfo=timezone.utc), |
107 | 96 | ),
|
| 97 | + ( |
| 98 | + "2020-12-31T00:00:00.000000+02:00", |
| 99 | + datetime(2020, 12, 31, tzinfo=timezone(timedelta(hours=2))), |
| 100 | + ), # UTC+2 time |
| 101 | + ( |
| 102 | + "2020-12-31T00:00:00.000000-0200", |
| 103 | + datetime(2020, 12, 31, tzinfo=timezone(timedelta(hours=-2))), |
| 104 | + ), # UTC-2 time |
| 105 | + ( |
| 106 | + "2020-12-31T00:00:00-0200", |
| 107 | + datetime(2020, 12, 31, tzinfo=timezone(timedelta(hours=-2))), |
| 108 | + ), # UTC-2 time - no milliseconds |
| 109 | +) |
| 110 | + |
| 111 | + |
| 112 | +@pytest.mark.parametrize( |
| 113 | + ("input_str", "expected_output"), |
| 114 | + isoformat_inputs_and_datetime_outputs, |
108 | 115 | )
|
109 | 116 | def test_datetime_from_isoformat(input_str, expected_output):
|
110 | 117 | assert datetime_from_isoformat(input_str) == expected_output, input_str
|
111 | 118 |
|
112 | 119 |
|
| 120 | +@pytest.mark.parametrize( |
| 121 | + ("input_str", "expected_output"), |
| 122 | + isoformat_inputs_and_datetime_outputs, |
| 123 | +) |
| 124 | +def test_datetime_from_isoformat_with_py_36_or_lower(input_str, expected_output): |
| 125 | + """ |
| 126 | + `fromisoformat` was added in Python version 3.7 |
| 127 | + """ |
| 128 | + with mock.patch("sentry_sdk.utils.datetime") as datetime_mocked: |
| 129 | + datetime_mocked.fromisoformat.side_effect = AttributeError() |
| 130 | + datetime_mocked.strptime = datetime.strptime |
| 131 | + assert datetime_from_isoformat(input_str) == expected_output, input_str |
| 132 | + |
| 133 | + |
113 | 134 | @pytest.mark.parametrize(
|
114 | 135 | "env_var_value,strict,expected",
|
115 | 136 | [
|
@@ -346,6 +367,12 @@ def test_sanitize_url_and_split(url, expected_result):
|
346 | 367 | assert sanitized_url.fragment == expected_result.fragment
|
347 | 368 |
|
348 | 369 |
|
| 370 | +def test_sanitize_url_remove_authority_is_false(): |
| 371 | + url = "https://usr:[email protected]" |
| 372 | + sanitized_url = sanitize_url(url, remove_authority=False) |
| 373 | + assert sanitized_url == url |
| 374 | + |
| 375 | + |
349 | 376 | @pytest.mark.parametrize(
|
350 | 377 | ("url", "sanitize", "expected_url", "expected_query", "expected_fragment"),
|
351 | 378 | [
|
@@ -629,6 +656,17 @@ def test_get_error_message(error, expected_result):
|
629 | 656 | assert get_error_message(exc_value) == expected_result(exc_value)
|
630 | 657 |
|
631 | 658 |
|
| 659 | +def test_safe_str_fails(): |
| 660 | + class ExplodingStr: |
| 661 | + def __str__(self): |
| 662 | + raise Exception |
| 663 | + |
| 664 | + obj = ExplodingStr() |
| 665 | + result = safe_str(obj) |
| 666 | + |
| 667 | + assert result == repr(obj) |
| 668 | + |
| 669 | + |
632 | 670 | def test_installed_modules():
|
633 | 671 | try:
|
634 | 672 | from importlib.metadata import distributions, version
|
@@ -712,6 +750,20 @@ def test_default_release_empty_string():
|
712 | 750 | assert release is None
|
713 | 751 |
|
714 | 752 |
|
| 753 | +def test_get_default_release_sentry_release_env(monkeypatch): |
| 754 | + monkeypatch.setenv("SENTRY_RELEASE", "sentry-env-release") |
| 755 | + assert get_default_release() == "sentry-env-release" |
| 756 | + |
| 757 | + |
| 758 | +def test_get_default_release_other_release_env(monkeypatch): |
| 759 | + monkeypatch.setenv("SOURCE_VERSION", "other-env-release") |
| 760 | + |
| 761 | + with mock.patch("sentry_sdk.utils.get_git_revision", return_value=""): |
| 762 | + release = get_default_release() |
| 763 | + |
| 764 | + assert release == "other-env-release" |
| 765 | + |
| 766 | + |
715 | 767 | def test_ensure_integration_enabled_integration_enabled(sentry_init):
|
716 | 768 | def original_function():
|
717 | 769 | return "original"
|
@@ -973,3 +1025,55 @@ def test_function(): ...
|
973 | 1025 | sentry_sdk.utils.qualname_from_function(test_function)
|
974 | 1026 | == "test_qualname_from_function_none_name.<locals>.test_function"
|
975 | 1027 | )
|
| 1028 | + |
| 1029 | + |
| 1030 | +def test_to_string_unicode_decode_error(): |
| 1031 | + class BadStr: |
| 1032 | + def __str__(self): |
| 1033 | + raise UnicodeDecodeError("utf-8", b"", 0, 1, "reason") |
| 1034 | + |
| 1035 | + obj = BadStr() |
| 1036 | + result = to_string(obj) |
| 1037 | + assert result == repr(obj)[1:-1] |
| 1038 | + |
| 1039 | + |
| 1040 | +def test_exc_info_from_error_dont_get_an_exc(): |
| 1041 | + class NotAnException: |
| 1042 | + pass |
| 1043 | + |
| 1044 | + with pytest.raises(ValueError) as exc: |
| 1045 | + exc_info_from_error(NotAnException()) |
| 1046 | + |
| 1047 | + assert "Expected Exception object to report, got <class" in str(exc.value) |
| 1048 | + |
| 1049 | + |
| 1050 | +def test_get_lines_from_file_handle_linecache_errors(): |
| 1051 | + expected_result = ([], None, []) |
| 1052 | + |
| 1053 | + class Loader: |
| 1054 | + @staticmethod |
| 1055 | + def get_source(module): |
| 1056 | + raise IOError("something went wrong") |
| 1057 | + |
| 1058 | + result = get_lines_from_file("filename", 10, loader=Loader()) |
| 1059 | + assert result == expected_result |
| 1060 | + |
| 1061 | + with mock.patch( |
| 1062 | + "sentry_sdk.utils.linecache.getlines", |
| 1063 | + side_effect=OSError("something went wrong"), |
| 1064 | + ): |
| 1065 | + result = get_lines_from_file("filename", 10) |
| 1066 | + assert result == expected_result |
| 1067 | + |
| 1068 | + lines = ["line1", "line2", "line3"] |
| 1069 | + |
| 1070 | + def fake_getlines(filename): |
| 1071 | + return lines |
| 1072 | + |
| 1073 | + with mock.patch("sentry_sdk.utils.linecache.getlines", fake_getlines): |
| 1074 | + result = get_lines_from_file("filename", 10) |
| 1075 | + assert result == expected_result |
| 1076 | + |
| 1077 | + |
| 1078 | +def test_package_version_is_none(): |
| 1079 | + assert package_version("non_existent_package") is None |
0 commit comments