|
1 | 1 | from dataclasses import asdict, dataclass |
2 | | -from typing import List, Optional |
| 2 | +from typing import Any, Dict, List, Optional |
| 3 | +from unittest import mock |
3 | 4 |
|
4 | 5 | import pytest |
5 | 6 |
|
| 7 | +import sentry_sdk |
6 | 8 | from sentry_sdk.tracing_utils import ( |
7 | 9 | Baggage, |
8 | 10 | _should_be_included, |
9 | 11 | _should_continue_trace, |
| 12 | + record_sql_queries, |
10 | 13 | ) |
11 | 14 | from tests.conftest import TestTransportWithOptions |
12 | 15 |
|
@@ -286,3 +289,128 @@ def test_baggage_from_incoming_header_value_with_equals_sign(): |
286 | 289 | header = "sentry-release=v1.0==1,sentry-trace_id=abc123" |
287 | 290 | baggage = Baggage.from_incoming_header(header) |
288 | 291 | assert baggage.sentry_items == {"release": "v1.0==1", "trace_id": "abc123"} |
| 292 | + |
| 293 | + |
| 294 | +def _get_query_breadcrumb_data( |
| 295 | + sentry_init, |
| 296 | + capture_events, |
| 297 | + sentry_options: "Dict[str, Any]", |
| 298 | + params_list: "Any" = [1, 2], |
| 299 | + paramstyle: "Optional[str]" = "pyformat", |
| 300 | +) -> "Dict[str, Any]": |
| 301 | + sentry_init(**sentry_options) |
| 302 | + events = capture_events() |
| 303 | + |
| 304 | + with record_sql_queries( |
| 305 | + cursor=mock.MagicMock(), |
| 306 | + query="SELECT * FROM users WHERE id IN (%s, %s)", |
| 307 | + params_list=params_list, |
| 308 | + paramstyle=paramstyle, |
| 309 | + executemany=False, |
| 310 | + ): |
| 311 | + pass |
| 312 | + |
| 313 | + sentry_sdk.capture_message("hi") |
| 314 | + (event,) = events |
| 315 | + (crumb,) = event["breadcrumbs"]["values"] |
| 316 | + assert crumb["category"] == "query" |
| 317 | + return crumb["data"] |
| 318 | + |
| 319 | + |
| 320 | +@pytest.mark.parametrize( |
| 321 | + "sentry_options, expected_data", |
| 322 | + ( |
| 323 | + pytest.param( |
| 324 | + {"_experiments": {"data_collection": {"database_query_data": True}}}, |
| 325 | + {"db.params": [1, 2], "db.paramstyle": "format"}, |
| 326 | + id="data_collection_on_records_params", |
| 327 | + ), |
| 328 | + pytest.param( |
| 329 | + {"_experiments": {"data_collection": {"database_query_data": False}}}, |
| 330 | + {}, |
| 331 | + id="data_collection_off_strips_params", |
| 332 | + ), |
| 333 | + pytest.param( |
| 334 | + {"_experiments": {"data_collection": {}}}, |
| 335 | + {"db.params": [1, 2], "db.paramstyle": "format"}, |
| 336 | + id="data_collection_default_records_params", |
| 337 | + ), |
| 338 | + pytest.param( |
| 339 | + {"_experiments": {"record_sql_params": True}}, |
| 340 | + {"db.params": [1, 2], "db.paramstyle": "format"}, |
| 341 | + id="legacy_record_sql_params_on_records_params", |
| 342 | + ), |
| 343 | + pytest.param( |
| 344 | + {"_experiments": {"record_sql_params": False}}, |
| 345 | + {}, |
| 346 | + id="legacy_record_sql_params_off_strips_params", |
| 347 | + ), |
| 348 | + pytest.param( |
| 349 | + {}, |
| 350 | + {}, |
| 351 | + id="no_options_strips_params", |
| 352 | + ), |
| 353 | + pytest.param( |
| 354 | + { |
| 355 | + "_experiments": { |
| 356 | + "record_sql_params": True, |
| 357 | + "data_collection": {"database_query_data": False}, |
| 358 | + } |
| 359 | + }, |
| 360 | + {}, |
| 361 | + id="data_collection_off_takes_precedence_over_legacy_on", |
| 362 | + ), |
| 363 | + pytest.param( |
| 364 | + { |
| 365 | + "_experiments": { |
| 366 | + "record_sql_params": False, |
| 367 | + "data_collection": {"database_query_data": True}, |
| 368 | + } |
| 369 | + }, |
| 370 | + {"db.params": [1, 2], "db.paramstyle": "format"}, |
| 371 | + id="data_collection_on_takes_precedence_over_legacy_off", |
| 372 | + ), |
| 373 | + ), |
| 374 | +) |
| 375 | +def test_record_sql_queries_data_collection( |
| 376 | + sentry_init, capture_events, sentry_options, expected_data |
| 377 | +): |
| 378 | + assert ( |
| 379 | + _get_query_breadcrumb_data(sentry_init, capture_events, sentry_options) |
| 380 | + == expected_data |
| 381 | + ) |
| 382 | + |
| 383 | + |
| 384 | +@pytest.mark.parametrize("params_list", (None, [], [None])) |
| 385 | +def test_record_sql_queries_empty_params_not_recorded( |
| 386 | + sentry_init, capture_events, params_list |
| 387 | +): |
| 388 | + data = _get_query_breadcrumb_data( |
| 389 | + sentry_init, |
| 390 | + capture_events, |
| 391 | + {"_experiments": {"data_collection": {"database_query_data": True}}}, |
| 392 | + params_list=params_list, |
| 393 | + ) |
| 394 | + assert "db.params" not in data |
| 395 | + |
| 396 | + |
| 397 | +def test_record_sql_queries_paramstyle_passthrough(sentry_init, capture_events): |
| 398 | + data = _get_query_breadcrumb_data( |
| 399 | + sentry_init, |
| 400 | + capture_events, |
| 401 | + {"_experiments": {"data_collection": {"database_query_data": True}}}, |
| 402 | + paramstyle="qmark", |
| 403 | + ) |
| 404 | + assert data["db.paramstyle"] == "qmark" |
| 405 | + |
| 406 | + |
| 407 | +def test_record_sql_queries_paramstyle_dropped_when_collection_off( |
| 408 | + sentry_init, capture_events |
| 409 | +): |
| 410 | + data = _get_query_breadcrumb_data( |
| 411 | + sentry_init, |
| 412 | + capture_events, |
| 413 | + {"_experiments": {"data_collection": {"database_query_data": False}}}, |
| 414 | + paramstyle="qmark", |
| 415 | + ) |
| 416 | + assert "db.paramstyle" not in data |
0 commit comments