Skip to content

Commit

Permalink
[FastAPI] Add TC for non-async functions
Browse files Browse the repository at this point in the history
Signed-off-by: Varsha GS <varsha.gs@ibm.com>
  • Loading branch information
Varsha GS committed Mar 8, 2024
1 parent f0d4786 commit e31aabd
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 19 deletions.
14 changes: 13 additions & 1 deletion tests/apps/fastapi_app/app.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# (c) Copyright IBM Corp. 2021
# (c) Copyright Instana Inc. 2020

from ...helpers import testenv

from fastapi import FastAPI, HTTPException, Response
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
import requests

fastapi_server = FastAPI()

Expand Down Expand Up @@ -46,4 +49,13 @@ async def five_hundred():

@fastapi_server.get("/starlette_exception")
async def starlette_exception():
raise StarletteHTTPException(status_code=500, detail="500 response")
raise StarletteHTTPException(status_code=500, detail="500 response")

def trigger_outgoing_call():
response = requests.get(testenv["fastapi_server"]+"/users/1")
return response.json()

@fastapi_server.get("/non_async")
def non_async_complex_call():
response = trigger_outgoing_call()
return response
105 changes: 87 additions & 18 deletions tests/frameworks/test_fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import requests

from instana.singletons import tracer
from instana.singletons import async_tracer
from tests.apps.fastapi_app import launch_fastapi
from ..helpers import testenv
from ..helpers import get_first_span_by_filter
Expand All @@ -33,19 +33,19 @@ def test_vanilla_get(self):
self.assertEqual(result.headers["X-INSTANA-L"], "1")
self.assertIn("Server-Timing", result.headers)

spans = tracer.recorder.queued_spans()
spans = async_tracer.recorder.queued_spans()
# FastAPI instrumentation (like all instrumentation) _always_ traces unless told otherwise
self.assertEqual(len(spans), 1)
self.assertEqual(spans[0].n, "asgi")

def test_basic_get(self):
result = None
with tracer.start_active_span("test"):
with async_tracer.start_active_span("test"):
result = requests.get(testenv["fastapi_server"] + "/")

self.assertEqual(result.status_code, 200)

spans = tracer.recorder.queued_spans()
spans = async_tracer.recorder.queued_spans()
self.assertEqual(len(spans), 3)

span_filter = (
Expand Down Expand Up @@ -95,12 +95,12 @@ def test_basic_get(self):

def test_400(self):
result = None
with tracer.start_active_span("test"):
with async_tracer.start_active_span("test"):
result = requests.get(testenv["fastapi_server"] + "/400")

self.assertEqual(result.status_code, 400)

spans = tracer.recorder.queued_spans()
spans = async_tracer.recorder.queued_spans()
self.assertEqual(len(spans), 3)

span_filter = (
Expand Down Expand Up @@ -150,12 +150,12 @@ def test_400(self):

def test_500(self):
result = None
with tracer.start_active_span("test"):
with async_tracer.start_active_span("test"):
result = requests.get(testenv["fastapi_server"] + "/500")

self.assertEqual(result.status_code, 500)

spans = tracer.recorder.queued_spans()
spans = async_tracer.recorder.queued_spans()
self.assertEqual(len(spans), 3)

span_filter = (
Expand Down Expand Up @@ -205,12 +205,12 @@ def test_500(self):

def test_path_templates(self):
result = None
with tracer.start_active_span("test"):
with async_tracer.start_active_span("test"):
result = requests.get(testenv["fastapi_server"] + "/users/1")

self.assertEqual(result.status_code, 200)

spans = tracer.recorder.queued_spans()
spans = async_tracer.recorder.queued_spans()
self.assertEqual(len(spans), 3)

span_filter = (
Expand Down Expand Up @@ -260,12 +260,12 @@ def test_path_templates(self):

def test_secret_scrubbing(self):
result = None
with tracer.start_active_span("test"):
with async_tracer.start_active_span("test"):
result = requests.get(testenv["fastapi_server"] + "/?secret=shhh")

self.assertEqual(result.status_code, 200)

spans = tracer.recorder.queued_spans()
spans = async_tracer.recorder.queued_spans()
self.assertEqual(len(spans), 3)

span_filter = (
Expand Down Expand Up @@ -315,14 +315,14 @@ def test_secret_scrubbing(self):

def test_synthetic_request(self):
request_headers = {"X-INSTANA-SYNTHETIC": "1"}
with tracer.start_active_span("test"):
with async_tracer.start_active_span("test"):
result = requests.get(
testenv["fastapi_server"] + "/", headers=request_headers
)

self.assertEqual(result.status_code, 200)

spans = tracer.recorder.queued_spans()
spans = async_tracer.recorder.queued_spans()
self.assertEqual(len(spans), 3)

span_filter = (
Expand Down Expand Up @@ -381,14 +381,14 @@ def test_request_header_capture(self):

request_headers = {"X-Capture-This": "this", "X-Capture-That": "that"}

with tracer.start_active_span("test"):
with async_tracer.start_active_span("test"):
result = requests.get(
testenv["fastapi_server"] + "/", headers=request_headers
)

self.assertEqual(result.status_code, 200)

spans = tracer.recorder.queued_spans()
spans = async_tracer.recorder.queued_spans()
self.assertEqual(len(spans), 3)

span_filter = (
Expand Down Expand Up @@ -446,12 +446,12 @@ def test_response_header_capture(self):

# The background FastAPI server is pre-configured with custom headers to capture

with tracer.start_active_span("test"):
with async_tracer.start_active_span("test"):
result = requests.get(testenv["fastapi_server"] + "/response_headers")

self.assertEqual(result.status_code, 200)

spans = tracer.recorder.queued_spans()
spans = async_tracer.recorder.queued_spans()
self.assertEqual(len(spans), 3)

span_filter = (
Expand Down Expand Up @@ -503,3 +503,72 @@ def test_response_header_capture(self):
self.assertEqual("this too", asgi_span.data["http"]["header"]["X-Capture-This-Too"])
self.assertIn("X-Capture-That-Too", asgi_span.data["http"]["header"])
self.assertEqual("that too", asgi_span.data["http"]["header"]["X-Capture-That-Too"])

def test_non_async_function(self):
with async_tracer.start_active_span("test"):
result = requests.get(testenv["fastapi_server"] + "/non_async")

self.assertEqual(result.status_code, 200)

spans = async_tracer.recorder.queued_spans()
self.assertEqual(5, len(spans))

span_filter = (
lambda span: span.n == "sdk" and span.data["sdk"]["name"] == "test"
)
test_span = get_first_span_by_filter(spans, span_filter)
self.assertTrue(test_span)

span_filter = (
lambda span: span.n == "urllib3" and span.p == test_span.s
)
urllib3_span1 = get_first_span_by_filter(spans, span_filter)
self.assertTrue(urllib3_span1)

span_filter = (
lambda span: span.n == "asgi" and span.p == urllib3_span1.s
)
asgi_span1 = get_first_span_by_filter(spans, span_filter)
self.assertTrue(asgi_span1)

span_filter = (
lambda span: span.n == "urllib3" and span.p == asgi_span1.s
)
urllib3_span2 = get_first_span_by_filter(spans, span_filter)
self.assertTrue(urllib3_span2)

span_filter = (
lambda span: span.n == "asgi" and span.p == urllib3_span2.s
)
asgi_span2 = get_first_span_by_filter(spans, span_filter)
self.assertTrue(asgi_span2)

# Same traceId
traceId = test_span.t
self.assertEqual(traceId, urllib3_span1.t)
self.assertEqual(traceId, asgi_span1.t)
self.assertEqual(traceId, urllib3_span2.t)
self.assertEqual(traceId, asgi_span2.t)

self.assertIn("X-INSTANA-T", result.headers)
self.assertEqual(result.headers["X-INSTANA-T"], asgi_span1.t)

self.assertIn("X-INSTANA-S", result.headers)
self.assertEqual(result.headers["X-INSTANA-S"], asgi_span1.s)

self.assertIn("X-INSTANA-L", result.headers)
self.assertEqual(result.headers["X-INSTANA-L"], "1")

self.assertIn("Server-Timing", result.headers)
server_timing_value = "intid;desc=%s" % asgi_span1.t
self.assertEqual(result.headers["Server-Timing"], server_timing_value)

self.assertIsNone(asgi_span1.ec)
self.assertEqual(asgi_span1.data["http"]["host"], "127.0.0.1")
self.assertEqual(asgi_span1.data["http"]["path"], "/non_async")
self.assertEqual(asgi_span1.data["http"]["path_tpl"], "/non_async")
self.assertEqual(asgi_span1.data["http"]["method"], "GET")
self.assertEqual(asgi_span1.data["http"]["status"], 200)

self.assertIsNone(asgi_span1.data["http"]["error"])
self.assertIsNone(asgi_span1.data["http"]["params"])

0 comments on commit e31aabd

Please sign in to comment.