|
3 | 3 | import os |
4 | 4 | from unittest.mock import patch |
5 | 5 |
|
| 6 | +import pytest |
| 7 | + |
6 | 8 | from openadapt_telemetry.client import ( |
7 | 9 | TelemetryClient, |
8 | 10 | get_telemetry, |
@@ -188,6 +190,8 @@ def test_initialize_with_dsn(self, mock_sentry): |
188 | 190 | assert result is True |
189 | 191 | assert client.initialized is True |
190 | 192 | mock_sentry.init.assert_called_once() |
| 193 | + init_kwargs = mock_sentry.init.call_args.kwargs |
| 194 | + assert init_kwargs["send_default_pii"] is False |
191 | 195 |
|
192 | 196 | @patch("openadapt_telemetry.client.sentry_sdk") |
193 | 197 | def test_capture_exception_when_enabled(self, mock_sentry): |
@@ -254,6 +258,54 @@ def test_set_user_hashes_identifier_and_drops_extra_fields(self, mock_sentry): |
254 | 258 | assert payload["id"].startswith("anon:") |
255 | 259 | assert payload["id"] != "user@example.com" |
256 | 260 |
|
| 261 | + @patch("openadapt_telemetry.client.sentry_sdk") |
| 262 | + def test_custom_before_send_is_composed_after_privacy_filter(self, mock_sentry): |
| 263 | + """Custom before_send should run after built-in scrubbing.""" |
| 264 | + |
| 265 | + def custom_before_send(event, hint): |
| 266 | + event.setdefault("tags", {})["custom"] = "true" |
| 267 | + return event |
| 268 | + |
| 269 | + with patch.dict(os.environ, {"DO_NOT_TRACK": ""}, clear=False): |
| 270 | + TelemetryClient.reset_instance() |
| 271 | + client = TelemetryClient.get_instance() |
| 272 | + with pytest.warns(UserWarning, match="Custom before_send is composed after OpenAdapt privacy filtering"): |
| 273 | + client.initialize( |
| 274 | + dsn="https://test@example.com/1", |
| 275 | + before_send=custom_before_send, |
| 276 | + ) |
| 277 | + |
| 278 | + before_send = mock_sentry.init.call_args.kwargs["before_send"] |
| 279 | + event = {"user": {"id": "user@example.com", "email": "user@example.com"}} |
| 280 | + output = before_send(event, hint={}) |
| 281 | + assert output is not None |
| 282 | + assert output["user"]["id"].startswith("anon:") |
| 283 | + assert "email" not in output["user"] |
| 284 | + assert output["tags"]["custom"] == "true" |
| 285 | + |
| 286 | + @patch("openadapt_telemetry.client.sentry_sdk") |
| 287 | + def test_send_default_pii_override_is_ignored(self, mock_sentry): |
| 288 | + """send_default_pii should always be enforced to False.""" |
| 289 | + with patch.dict(os.environ, {"DO_NOT_TRACK": ""}, clear=False): |
| 290 | + TelemetryClient.reset_instance() |
| 291 | + client = TelemetryClient.get_instance() |
| 292 | + with pytest.warns(UserWarning, match="Ignoring sentry init override for send_default_pii"): |
| 293 | + client.initialize( |
| 294 | + dsn="https://test@example.com/1", |
| 295 | + send_default_pii=True, |
| 296 | + ) |
| 297 | + |
| 298 | + assert mock_sentry.init.call_args.kwargs["send_default_pii"] is False |
| 299 | + |
| 300 | + def test_initialize_rejects_non_callable_before_send(self): |
| 301 | + """Non-callable before_send should raise TypeError.""" |
| 302 | + with patch.dict(os.environ, {"DO_NOT_TRACK": ""}, clear=False): |
| 303 | + TelemetryClient.reset_instance() |
| 304 | + client = TelemetryClient.get_instance() |
| 305 | + with patch("openadapt_telemetry.client.sentry_sdk"): |
| 306 | + with pytest.raises(TypeError, match="before_send must be callable"): |
| 307 | + client.initialize(dsn="https://test@example.com/1", before_send="invalid") |
| 308 | + |
257 | 309 | @patch("openadapt_telemetry.client.sentry_sdk") |
258 | 310 | def test_add_breadcrumb(self, mock_sentry): |
259 | 311 | """add_breadcrumb should call sentry when enabled.""" |
|
0 commit comments