Skip to content

Commit

Permalink
Cleaning up ASGI tests for Django (#3180)
Browse files Browse the repository at this point in the history
Cleaning up the ASGI tests for Django. Making sure it is always `wait()`ed for the application to finish and also made the tests a bit more readable and removed some useless asserts.

Fixes #3142
  • Loading branch information
antonpirker authored Jun 18, 2024
1 parent 009fa4f commit 56d2cc6
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 46 deletions.
122 changes: 76 additions & 46 deletions tests/integrations/django/asgi/test_asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,17 @@
@pytest.mark.asyncio
@pytest.mark.forked
async def test_basic(sentry_init, capture_events, application):
sentry_init(integrations=[DjangoIntegration()], send_default_pii=True)
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=True,
)

events = capture_events()

comm = HttpCommunicator(application, "GET", "/view-exc?test=query")
response = await comm.get_response()
await comm.wait()

assert response["status"] == 500

(event,) = events
Expand Down Expand Up @@ -67,12 +72,17 @@ async def test_basic(sentry_init, capture_events, application):
django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1"
)
async def test_async_views(sentry_init, capture_events, application):
sentry_init(integrations=[DjangoIntegration()], send_default_pii=True)
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=True,
)

events = capture_events()

comm = HttpCommunicator(application, "GET", "/async_message")
response = await comm.get_response()
await comm.wait()

assert response["status"] == 200

(event,) = events
Expand Down Expand Up @@ -108,17 +118,16 @@ async def test_active_thread_id(sentry_init, capture_envelopes, endpoint, applic

comm = HttpCommunicator(application, "GET", endpoint)
response = await comm.get_response()
assert response["status"] == 200, response["body"]

await comm.wait()

data = json.loads(response["body"])
envelopes = [envelope for envelope in envelopes]
assert response["status"] == 200, response["body"]
assert len(envelopes) == 1

profiles = [item for item in envelopes[0].items if item.type == "profile"]
assert len(profiles) == 1

data = json.loads(response["body"])

for profile in profiles:
transactions = profile.payload.json["transactions"]
assert len(transactions) == 1
Expand All @@ -137,7 +146,10 @@ async def test_async_views_concurrent_execution(sentry_init, settings):
settings.MIDDLEWARE = []
asgi_application.load_middleware(is_async=True)

sentry_init(integrations=[DjangoIntegration()], send_default_pii=True)
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=True,
)

comm = HttpCommunicator(
asgi_application, "GET", "/my_async_view"
Expand Down Expand Up @@ -181,7 +193,10 @@ async def test_async_middleware_that_is_function_concurrent_execution(
]
asgi_application.load_middleware(is_async=True)

sentry_init(integrations=[DjangoIntegration()], send_default_pii=True)
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=True,
)

comm = HttpCommunicator(
asgi_application, "GET", "/my_async_view"
Expand Down Expand Up @@ -233,13 +248,13 @@ async def test_async_middleware_spans(

events = capture_events()

comm = HttpCommunicator(asgi_application, "GET", "/async_message")
comm = HttpCommunicator(asgi_application, "GET", "/simple_async_view")
response = await comm.get_response()
assert response["status"] == 200

await comm.wait()

message, transaction = events
assert response["status"] == 200

(transaction,) = events

assert (
render_span_tree(transaction)
Expand All @@ -252,7 +267,7 @@ async def test_async_middleware_spans(
- op="middleware.django": description="django.middleware.csrf.CsrfViewMiddleware.__acall__"
- op="middleware.django": description="tests.integrations.django.myapp.settings.TestMiddleware.__acall__"
- op="middleware.django": description="django.middleware.csrf.CsrfViewMiddleware.process_view"
- op="view.render": description="async_message"
- op="view.render": description="simple_async_view"
- op="event.django": description="django.db.close_old_connections"
- op="event.django": description="django.core.cache.close_caches"
- op="event.django": description="django.core.handlers.base.reset_urlconf\""""
Expand All @@ -265,27 +280,25 @@ async def test_async_middleware_spans(
django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1"
)
async def test_has_trace_if_performance_enabled(sentry_init, capture_events):
sentry_init(integrations=[DjangoIntegration()], traces_sample_rate=1.0)
sentry_init(
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
)

events = capture_events()

comm = HttpCommunicator(asgi_application, "GET", "/view-exc-with-msg")
response = await comm.get_response()
assert response["status"] == 500

# ASGI Django does not create transactions per default,
# so we do not have a transaction_event here.
(msg_event, error_event) = events
await comm.wait()

assert msg_event["contexts"]["trace"]
assert "trace_id" in msg_event["contexts"]["trace"]
assert response["status"] == 500

assert error_event["contexts"]["trace"]
assert "trace_id" in error_event["contexts"]["trace"]
(msg_event, error_event, transaction_event) = events

assert (
msg_event["contexts"]["trace"]["trace_id"]
== error_event["contexts"]["trace"]["trace_id"]
== transaction_event["contexts"]["trace"]["trace_id"]
)


Expand All @@ -295,12 +308,16 @@ async def test_has_trace_if_performance_enabled(sentry_init, capture_events):
django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1"
)
async def test_has_trace_if_performance_disabled(sentry_init, capture_events):
sentry_init(integrations=[DjangoIntegration()])
sentry_init(
integrations=[DjangoIntegration()],
)

events = capture_events()

comm = HttpCommunicator(asgi_application, "GET", "/view-exc-with-msg")
response = await comm.get_response()
await comm.wait()

assert response["status"] == 500

(msg_event, error_event) = events
Expand All @@ -322,7 +339,10 @@ async def test_has_trace_if_performance_disabled(sentry_init, capture_events):
django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1"
)
async def test_trace_from_headers_if_performance_enabled(sentry_init, capture_events):
sentry_init(integrations=[DjangoIntegration()], traces_sample_rate=1.0)
sentry_init(
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
)

events = capture_events()

Expand All @@ -336,20 +356,15 @@ async def test_trace_from_headers_if_performance_enabled(sentry_init, capture_ev
headers=[(b"sentry-trace", sentry_trace_header.encode())],
)
response = await comm.get_response()
assert response["status"] == 500
await comm.wait()

# ASGI Django does not create transactions per default,
# so we do not have a transaction_event here.
(msg_event, error_event) = events
assert response["status"] == 500

assert msg_event["contexts"]["trace"]
assert "trace_id" in msg_event["contexts"]["trace"]

assert error_event["contexts"]["trace"]
assert "trace_id" in error_event["contexts"]["trace"]
(msg_event, error_event, transaction_event) = events

assert msg_event["contexts"]["trace"]["trace_id"] == trace_id
assert error_event["contexts"]["trace"]["trace_id"] == trace_id
assert transaction_event["contexts"]["trace"]["trace_id"] == trace_id


@pytest.mark.asyncio
Expand All @@ -358,7 +373,9 @@ async def test_trace_from_headers_if_performance_enabled(sentry_init, capture_ev
django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1"
)
async def test_trace_from_headers_if_performance_disabled(sentry_init, capture_events):
sentry_init(integrations=[DjangoIntegration()])
sentry_init(
integrations=[DjangoIntegration()],
)

events = capture_events()

Expand All @@ -372,16 +389,12 @@ async def test_trace_from_headers_if_performance_disabled(sentry_init, capture_e
headers=[(b"sentry-trace", sentry_trace_header.encode())],
)
response = await comm.get_response()
await comm.wait()

assert response["status"] == 500

(msg_event, error_event) = events

assert msg_event["contexts"]["trace"]
assert "trace_id" in msg_event["contexts"]["trace"]

assert error_event["contexts"]["trace"]
assert "trace_id" in error_event["contexts"]["trace"]

assert msg_event["contexts"]["trace"]["trace_id"] == trace_id
assert error_event["contexts"]["trace"]["trace_id"] == trace_id

Expand Down Expand Up @@ -504,10 +517,8 @@ async def test_asgi_request_body(
expected_data,
):
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=send_default_pii,
integrations=[
DjangoIntegration(),
],
)

envelopes = capture_envelopes()
Expand All @@ -520,9 +531,9 @@ async def test_asgi_request_body(
body=body,
)
response = await comm.get_response()
assert response["status"] == 200

await comm.wait()

assert response["status"] == 200
assert response["body"] == body

(envelope,) = envelopes
Expand Down Expand Up @@ -594,3 +605,22 @@ def get_response(): ...

instance = sentry_asgi_mixin(get_response)
assert not inspect.iscoroutinefunction(instance)


@pytest.mark.parametrize("application", APPS)
@pytest.mark.asyncio
async def test_async_view(sentry_init, capture_events, application):
sentry_init(
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
)

events = capture_events()

comm = HttpCommunicator(application, "GET", "/simple_async_view")
await comm.get_response()
await comm.wait()

(event,) = events
assert event["type"] == "transaction"
assert event["transaction"] == "/simple_async_view"
5 changes: 5 additions & 0 deletions tests/integrations/django/myapp/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ def path(path, *args, **kwargs):
if views.my_async_view is not None:
urlpatterns.append(path("my_async_view", views.my_async_view, name="my_async_view"))

if views.my_async_view is not None:
urlpatterns.append(
path("simple_async_view", views.simple_async_view, name="simple_async_view")
)

if views.thread_ids_async is not None:
urlpatterns.append(
path("async/thread_ids", views.thread_ids_async, name="thread_ids_async")
Expand Down
4 changes: 4 additions & 0 deletions tests/integrations/django/myapp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ async def my_async_view(request):
return HttpResponse("Hello World")


async def simple_async_view(request):
return HttpResponse("Simple Hello World")


async def thread_ids_async(request):
response = json.dumps(
{
Expand Down

0 comments on commit 56d2cc6

Please sign in to comment.