Skip to content

Commit 6cb776e

Browse files
GSVarshaFerenc-
authored andcommitted
[FastAPI] Add TC for non-async functions run in threadpool
Signed-off-by: Varsha GS <[email protected]>
1 parent 0ad0316 commit 6cb776e

File tree

2 files changed

+66
-6
lines changed

2 files changed

+66
-6
lines changed

tests/apps/fastapi_app/app.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from fastapi import FastAPI, HTTPException, Response
77
from fastapi.exceptions import RequestValidationError
88
from fastapi.responses import PlainTextResponse
9+
from fastapi.concurrency import run_in_threadpool
910
from starlette.exceptions import HTTPException as StarletteHTTPException
1011
import requests
1112

@@ -55,7 +56,12 @@ def trigger_outgoing_call():
5556
response = requests.get(testenv["fastapi_server"]+"/users/1")
5657
return response.json()
5758

58-
@fastapi_server.get("/non_async")
59+
@fastapi_server.get("/non_async_simple")
5960
def non_async_complex_call():
6061
response = trigger_outgoing_call()
61-
return response
62+
return response
63+
64+
@fastapi_server.get("/non_async_threadpool")
65+
def non_async_threadpool():
66+
run_in_threadpool(trigger_outgoing_call)
67+
return {"message": "non async functions executed on a thread pool can't be followed through thread boundaries"}

tests/frameworks/test_fastapi.py

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -504,9 +504,9 @@ def test_response_header_capture(self):
504504
self.assertIn("X-Capture-That-Too", asgi_span.data["http"]["header"])
505505
self.assertEqual("that too", asgi_span.data["http"]["header"]["X-Capture-That-Too"])
506506

507-
def test_non_async_function(self):
507+
def test_non_async_simple(self):
508508
with async_tracer.start_active_span("test"):
509-
result = requests.get(testenv["fastapi_server"] + "/non_async")
509+
result = requests.get(testenv["fastapi_server"] + "/non_async_simple")
510510

511511
self.assertEqual(result.status_code, 200)
512512

@@ -565,10 +565,64 @@ def test_non_async_function(self):
565565

566566
self.assertIsNone(asgi_span1.ec)
567567
self.assertEqual(asgi_span1.data["http"]["host"], "127.0.0.1")
568-
self.assertEqual(asgi_span1.data["http"]["path"], "/non_async")
569-
self.assertEqual(asgi_span1.data["http"]["path_tpl"], "/non_async")
568+
self.assertEqual(asgi_span1.data["http"]["path"], "/non_async_simple")
569+
self.assertEqual(asgi_span1.data["http"]["path_tpl"], "/non_async_simple")
570570
self.assertEqual(asgi_span1.data["http"]["method"], "GET")
571571
self.assertEqual(asgi_span1.data["http"]["status"], 200)
572572

573573
self.assertIsNone(asgi_span1.data["http"]["error"])
574574
self.assertIsNone(asgi_span1.data["http"]["params"])
575+
576+
def test_non_async_threadpool(self):
577+
with async_tracer.start_active_span("test"):
578+
result = requests.get(testenv["fastapi_server"] + "/non_async_threadpool")
579+
580+
self.assertEqual(result.status_code, 200)
581+
582+
spans = async_tracer.recorder.queued_spans()
583+
self.assertEqual(3, len(spans))
584+
585+
span_filter = (
586+
lambda span: span.n == "sdk" and span.data["sdk"]["name"] == "test"
587+
)
588+
test_span = get_first_span_by_filter(spans, span_filter)
589+
self.assertTrue(test_span)
590+
591+
span_filter = lambda span: span.n == "urllib3"
592+
urllib3_span = get_first_span_by_filter(spans, span_filter)
593+
self.assertTrue(urllib3_span)
594+
595+
span_filter = lambda span: span.n == "asgi"
596+
asgi_span = get_first_span_by_filter(spans, span_filter)
597+
self.assertTrue(asgi_span)
598+
599+
# Same traceId
600+
self.assertEqual(test_span.t, urllib3_span.t)
601+
self.assertEqual(urllib3_span.t, asgi_span.t)
602+
603+
# Parent relationships
604+
self.assertEqual(asgi_span.p, urllib3_span.s)
605+
self.assertEqual(urllib3_span.p, test_span.s)
606+
607+
self.assertIn("X-INSTANA-T", result.headers)
608+
self.assertEqual(result.headers["X-INSTANA-T"], asgi_span.t)
609+
610+
self.assertIn("X-INSTANA-S", result.headers)
611+
self.assertEqual(result.headers["X-INSTANA-S"], asgi_span.s)
612+
613+
self.assertIn("X-INSTANA-L", result.headers)
614+
self.assertEqual(result.headers["X-INSTANA-L"], "1")
615+
616+
self.assertIn("Server-Timing", result.headers)
617+
server_timing_value = "intid;desc=%s" % asgi_span.t
618+
self.assertEqual(result.headers["Server-Timing"], server_timing_value)
619+
620+
self.assertIsNone(asgi_span.ec)
621+
self.assertEqual(asgi_span.data["http"]["host"], "127.0.0.1")
622+
self.assertEqual(asgi_span.data["http"]["path"], "/non_async_threadpool")
623+
self.assertEqual(asgi_span.data["http"]["path_tpl"], "/non_async_threadpool")
624+
self.assertEqual(asgi_span.data["http"]["method"], "GET")
625+
self.assertEqual(asgi_span.data["http"]["status"], 200)
626+
627+
self.assertIsNone(asgi_span.data["http"]["error"])
628+
self.assertIsNone(asgi_span.data["http"]["params"])

0 commit comments

Comments
 (0)