Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added tests/integrations/fastapi/photo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
154 changes: 153 additions & 1 deletion tests/integrations/fastapi/test_fastapi.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import base64
import json
import logging
import os
import threading
import warnings
from unittest import mock

import fastapi
import pytest
import starlette
from fastapi import FastAPI, HTTPException, Request
from fastapi import Body, FastAPI, File, Form, HTTPException, Request, UploadFile
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.testclient import TestClient

Expand All @@ -22,6 +24,28 @@
FASTAPI_VERSION = parse_version(fastapi.__version__)
STARLETTE_VERSION = parse_version(starlette.__version__)

PICTURE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "photo.jpg")

BODY_JSON = {"some": "json", "for": "testing", "nested": {"numbers": 123}}

BODY_FORM = """--fd721ef49ea403a6\r\nContent-Disposition: form-data; name="username"\r\n\r\nJane\r\n--fd721ef49ea403a6\r\nContent-Disposition: form-data; name="password"\r\n\r\nhello123\r\n--fd721ef49ea403a6\r\nContent-Disposition: form-data; name="photo"; filename="photo.jpg"\r\nContent-Type: image/jpg\r\nContent-Transfer-Encoding: base64\r\n\r\n{{image_data}}\r\n--fd721ef49ea403a6--\r\n""".replace(
"{{image_data}}", str(base64.b64encode(open(PICTURE, "rb").read()))
)

PARSED_FORM = starlette.datastructures.FormData(
[
("username", "Jane"),
("password", "hello123"),
(
"photo",
starlette.datastructures.UploadFile(
filename="photo.jpg",
file=open(PICTURE, "rb"),
),
),
]
)

from tests.integrations.conftest import parametrize_test_configurable_status_codes
from tests.integrations.starlette import test_starlette

Expand Down Expand Up @@ -70,9 +94,137 @@ async def _thread_ids_async():
"active": str(threading.current_thread().ident),
}

@app.post("/body/json")
async def body_json(payload: dict = Body(...)):
capture_message("hi")
return {"status": "ok"}

@app.post("/body/form")
async def body_form(
username: str = Form(...),
password: str = Form(...),
photo: UploadFile = File(...),
):
capture_message("hi")
return {"status": "ok"}

return app


@pytest.mark.asyncio
async def test_request_info_json_body(sentry_init, capture_events):
sentry_init(
traces_sample_rate=1.0,
send_default_pii=True,
integrations=[StarletteIntegration()],
)

app = fastapi_app_factory()
client = TestClient(app)

events = capture_events()

client.post(
"/body/json",
json=BODY_JSON,
headers={
"cookie": "yummy_cookie=choco; tasty_cookie=strawberry",
},
)

(event, transaction_event) = events

assert event["request"]["cookies"] == {
"tasty_cookie": "strawberry",
"yummy_cookie": "choco",
}
assert event["request"]["data"] == BODY_JSON

assert transaction_event["request"]["cookies"] == {
"tasty_cookie": "strawberry",
"yummy_cookie": "choco",
}
assert transaction_event["request"]["data"] == BODY_JSON


@pytest.mark.asyncio
async def test_formdata_request_body(sentry_init, capture_events):
sentry_init(
traces_sample_rate=1.0,
send_default_pii=True,
max_request_body_size="always",
integrations=[StarletteIntegration()],
)

app = fastapi_app_factory()
client = TestClient(app)

events = capture_events()

client.post(
"/body/form",
data=BODY_FORM.encode("utf-8"),
headers={
"content-type": "multipart/form-data; boundary=fd721ef49ea403a6",
},
)

(event, transaction_event) = events
assert event["request"]["data"].keys() == PARSED_FORM.keys()
assert event["request"]["data"]["username"] == PARSED_FORM["username"]
assert event["request"]["data"]["password"] == "[Filtered]"
assert event["request"]["data"]["photo"] == ""
assert event["_meta"]["request"]["data"]["photo"] == {"": {"rem": [["!raw", "x"]]}}

assert transaction_event["request"]["data"].keys() == PARSED_FORM.keys()
assert transaction_event["request"]["data"]["username"] == PARSED_FORM["username"]
assert transaction_event["request"]["data"]["password"] == "[Filtered]"
assert transaction_event["request"]["data"]["photo"] == ""
assert transaction_event["_meta"]["request"]["data"]["photo"] == {
"": {"rem": [["!raw", "x"]]}
}


@pytest.mark.asyncio
async def test_request_body_too_big(sentry_init, capture_events):
sentry_init(
traces_sample_rate=1.0,
send_default_pii=True,
integrations=[StarletteIntegration()],
)

app = fastapi_app_factory()
client = TestClient(app)

events = capture_events()

client.post(
"/body/form",
data=BODY_FORM.encode("utf-8"),
headers={
"content-type": "multipart/form-data; boundary=fd721ef49ea403a6",
"cookie": "yummy_cookie=choco; tasty_cookie=strawberry",
},
)

(event, transaction_event) = events
assert event["request"]["cookies"] == {
"tasty_cookie": "strawberry",
"yummy_cookie": "choco",
}
# Because request is too big only the AnnotatedValue is extracted.
assert event["_meta"]["request"]["data"] == {"": {"rem": [["!config", "x"]]}}

assert transaction_event["request"]["cookies"] == {
"tasty_cookie": "strawberry",
"yummy_cookie": "choco",
}
# Because request is too big only the AnnotatedValue is extracted.
assert transaction_event["_meta"]["request"]["data"] == {
"": {"rem": [["!config", "x"]]}
}


@pytest.mark.asyncio
async def test_response(sentry_init, capture_events):
# FastAPI is heavily based on Starlette so we also need
Expand Down
Loading