|
| 1 | +import json |
1 | 2 | import random
|
| 3 | +from textwrap import dedent |
| 4 | +from urllib.parse import urlencode |
2 | 5 |
|
3 | 6 | import pytest
|
4 | 7 |
|
|
16 | 19 | # py3
|
17 | 20 | from http.client import HTTPConnection, HTTPSConnection
|
18 | 21 |
|
| 22 | +try: |
| 23 | + # py3 |
| 24 | + from urllib.parse import parse_qsl |
| 25 | +except ImportError: |
| 26 | + # py2 |
| 27 | + from urlparse import parse_qsl # type: ignore |
| 28 | + |
19 | 29 | try:
|
20 | 30 | from unittest import mock # python 3.3 and above
|
21 | 31 | except ImportError:
|
|
27 | 37 | from sentry_sdk.tracing import Transaction
|
28 | 38 | from sentry_sdk.integrations.stdlib import StdlibIntegration
|
29 | 39 |
|
30 |
| -from tests.conftest import create_mock_http_server |
| 40 | +from tests.conftest import MockServerRequestHandler, create_mock_http_server |
31 | 41 |
|
32 | 42 | PORT = create_mock_http_server()
|
33 | 43 |
|
@@ -340,3 +350,110 @@ def test_option_trace_propagation_targets(
|
340 | 350 | else:
|
341 | 351 | assert "sentry-trace" not in request_headers
|
342 | 352 | assert "baggage" not in request_headers
|
| 353 | + |
| 354 | + |
| 355 | +def test_graphql_get_client_error_captured(sentry_init, capture_events): |
| 356 | + sentry_init(integrations=[StdlibIntegration()]) |
| 357 | + |
| 358 | + graphql_response = { |
| 359 | + "data": None, |
| 360 | + "errors": [ |
| 361 | + { |
| 362 | + "message": "some error", |
| 363 | + "locations": [{"line": 2, "column": 3}], |
| 364 | + "path": ["user"], |
| 365 | + } |
| 366 | + ], |
| 367 | + } |
| 368 | + |
| 369 | + events = capture_events() |
| 370 | + |
| 371 | + params = {"query": "query QueryName {user{name}}"} |
| 372 | + |
| 373 | + def do_GET(self): |
| 374 | + self.send_response(200) |
| 375 | + self.end_headers() |
| 376 | + self.wfile.write(json.dumps(graphql_response).encode()) |
| 377 | + |
| 378 | + with mock.patch.object(MockServerRequestHandler, "do_GET", do_GET): |
| 379 | + conn = HTTPConnection("localhost:{}".format(PORT)) |
| 380 | + conn.request("GET", "/graphql?" + urlencode(params)) |
| 381 | + response = conn.getresponse() |
| 382 | + |
| 383 | + assert response.read() == json.dumps(graphql_response).encode() |
| 384 | + |
| 385 | + (event,) = events |
| 386 | + |
| 387 | + assert event["request"]["url"] == "http://localhost:{}/graphql".format(PORT) |
| 388 | + assert event["request"]["method"] == "GET" |
| 389 | + assert dict(parse_qsl(event["request"]["query_string"])) == params |
| 390 | + assert "data" not in event["request"] |
| 391 | + assert ( |
| 392 | + event["contexts"]["response"]["data"] == json.dumps(graphql_response).encode() |
| 393 | + ) |
| 394 | + |
| 395 | + assert event["request"]["api_target"] == "graphql" |
| 396 | + assert event["fingerprint"] == ["QueryName", "query", 200] |
| 397 | + assert ( |
| 398 | + event["exception"]["values"][0]["value"] |
| 399 | + == "GraphQL request failed, name: QueryName, type: query" |
| 400 | + ) |
| 401 | + |
| 402 | + |
| 403 | +def test_graphql_post_client_error_captured(sentry_init, capture_events): |
| 404 | + sentry_init(integrations=[StdlibIntegration()]) |
| 405 | + |
| 406 | + graphql_request = { |
| 407 | + "query": dedent( |
| 408 | + """ |
| 409 | + mutation AddPet ($name: String!) { |
| 410 | + addPet(name: $name) { |
| 411 | + id |
| 412 | + name |
| 413 | + } |
| 414 | + } |
| 415 | + """ |
| 416 | + ), |
| 417 | + "variables": { |
| 418 | + "name": "Lucy", |
| 419 | + }, |
| 420 | + } |
| 421 | + graphql_response = { |
| 422 | + "data": None, |
| 423 | + "errors": [ |
| 424 | + { |
| 425 | + "message": "already have too many pets", |
| 426 | + "locations": [{"line": 1, "column": 1}], |
| 427 | + } |
| 428 | + ], |
| 429 | + } |
| 430 | + |
| 431 | + events = capture_events() |
| 432 | + |
| 433 | + def do_POST(self): |
| 434 | + self.send_response(200) |
| 435 | + self.end_headers() |
| 436 | + self.wfile.write(json.dumps(graphql_response).encode()) |
| 437 | + |
| 438 | + with mock.patch.object(MockServerRequestHandler, "do_POST", do_POST): |
| 439 | + conn = HTTPConnection("localhost:{}".format(PORT)) |
| 440 | + conn.request("POST", "/graphql", body=json.dumps(graphql_request).encode()) |
| 441 | + response = conn.getresponse() |
| 442 | + |
| 443 | + # the response can still be read normally |
| 444 | + assert response.read() == json.dumps(graphql_response).encode() |
| 445 | + |
| 446 | + (event,) = events |
| 447 | + |
| 448 | + assert event["request"]["url"] == "http://localhost:{}/graphql".format(PORT) |
| 449 | + assert event["request"]["method"] == "POST" |
| 450 | + assert event["request"]["query_string"] == "" |
| 451 | + assert event["request"]["data"] == graphql_request |
| 452 | + assert event["contexts"]["response"]["data"] == graphql_response |
| 453 | + |
| 454 | + assert event["request"]["api_target"] == "graphql" |
| 455 | + assert event["fingerprint"] == ["AddPet", "mutation", 200] |
| 456 | + assert ( |
| 457 | + event["exception"]["values"][0]["value"] |
| 458 | + == "GraphQL request failed, name: AddPet, type: mutation" |
| 459 | + ) |
0 commit comments