Skip to content

Commit 9d598ce

Browse files
Sparkyczbeniwohlibasepi
authored
Fix Starlette middleware - providing only static files (#1137)
* Fix Starlette middleware - providing only static files closes #1131 * Fix failing tests * CHANGELOG Co-authored-by: Benjamin Wohlwend <beni@elastic.co> Co-authored-by: Colton Myers <colton.myers@gmail.com>
1 parent df56477 commit 9d598ce

File tree

5 files changed

+79
-3
lines changed

5 files changed

+79
-3
lines changed

CHANGELOG.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ endif::[]
4242
[float]
4343
===== Bug fixes
4444
45+
* Fix for Starlette static files {pull}1137[#1137]
4546
4647
[[release-notes-6.x]]
4748
=== Python Agent version 6.x

elasticapm/contrib/starlette/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def _get_route_name(self, scope, routes, route_name=None):
237237
if match == Match.FULL:
238238
route_name = route.path
239239
child_scope = {**scope, **child_scope}
240-
if isinstance(route, Mount):
240+
if isinstance(route, Mount) and route.routes:
241241
child_route_name = self._get_route_name(child_scope, route.routes, route_name)
242242
if child_route_name is None:
243243
route_name = None

tests/contrib/asyncio/starlette_tests.py

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,18 @@
2828
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2929
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3030

31+
import os
3132
import pytest # isort:skip
3233

3334
from tests.fixtures import TempStoreClient
3435

3536
starlette = pytest.importorskip("starlette") # isort:skip
3637

37-
import types
38-
3938
import mock
4039
import urllib3
4140
from starlette.applications import Starlette
4241
from starlette.responses import PlainTextResponse
42+
from starlette.staticfiles import StaticFiles
4343
from starlette.testclient import TestClient
4444

4545
import elasticapm
@@ -53,6 +53,8 @@
5353

5454
starlette_version_tuple = tuple(map(int, starlette.__version__.split(".")[:3]))
5555

56+
file_path, file_name = os.path.split(__file__)
57+
5658

5759
@pytest.fixture
5860
def app(elasticapm_client):
@@ -371,6 +373,77 @@ def test_capture_body_error(app, elasticapm_client):
371373
response = client.post("/raise-exception", data="[0, 1]")
372374

373375

376+
@pytest.fixture
377+
def app_static_files_only(elasticapm_client):
378+
app = Starlette()
379+
app.add_middleware(ElasticAPM, client=elasticapm_client)
380+
app.mount("/tmp", StaticFiles(directory=file_path), name="static")
381+
382+
yield app
383+
384+
elasticapm.uninstrument()
385+
386+
387+
def test_static_files_only(app_static_files_only, elasticapm_client):
388+
client = TestClient(app_static_files_only)
389+
390+
response = client.get(
391+
"/tmp/" + file_name,
392+
headers={
393+
constants.TRACEPARENT_HEADER_NAME: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-03",
394+
constants.TRACESTATE_HEADER_NAME: "foo=bar,bar=baz",
395+
"REMOTE_ADDR": "127.0.0.1",
396+
},
397+
)
398+
399+
assert response.status_code == 200
400+
401+
assert len(elasticapm_client.events[constants.TRANSACTION]) == 1
402+
transaction = elasticapm_client.events[constants.TRANSACTION][0]
403+
spans = elasticapm_client.spans_for_transaction(transaction)
404+
assert len(spans) == 0
405+
406+
assert transaction["name"] == "GET /tmp"
407+
assert transaction["result"] == "HTTP 2xx"
408+
assert transaction["outcome"] == "success"
409+
assert transaction["type"] == "request"
410+
assert transaction["span_count"]["started"] == 0
411+
assert transaction["context"]["request"]["url"]["pathname"] == "/tmp/" + file_name
412+
request = transaction["context"]["request"]
413+
assert request["method"] == "GET"
414+
assert request["socket"] == {"remote_address": "127.0.0.1", "encrypted": False}
415+
416+
417+
def test_static_files_only_file_notfound(app_static_files_only, elasticapm_client):
418+
client = TestClient(app_static_files_only)
419+
420+
response = client.get(
421+
"/tmp/whatever",
422+
headers={
423+
constants.TRACEPARENT_HEADER_NAME: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-03",
424+
constants.TRACESTATE_HEADER_NAME: "foo=bar,bar=baz",
425+
"REMOTE_ADDR": "127.0.0.1",
426+
},
427+
)
428+
429+
assert response.status_code == 404
430+
431+
assert len(elasticapm_client.events[constants.TRANSACTION]) == 1
432+
transaction = elasticapm_client.events[constants.TRANSACTION][0]
433+
spans = elasticapm_client.spans_for_transaction(transaction)
434+
assert len(spans) == 0
435+
436+
assert transaction["name"] == "GET /tmp"
437+
assert transaction["result"] == "HTTP 4xx"
438+
assert transaction["outcome"] == "success"
439+
assert transaction["type"] == "request"
440+
assert transaction["span_count"]["started"] == 0
441+
assert transaction["context"]["request"]["url"]["pathname"] == "/tmp/whatever"
442+
request = transaction["context"]["request"]
443+
assert request["method"] == "GET"
444+
assert request["socket"] == {"remote_address": "127.0.0.1", "encrypted": False}
445+
446+
374447
def test_make_client_with_config():
375448
c = make_apm_client(config={"SERVICE_NAME": "foo"}, client_cls=TempStoreClient)
376449
c.close()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
starlette==0.13.0
2+
aiofiles==0.7.0
23
requests==2.23.0
34
-r reqs-base.txt
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
starlette
2+
aiofiles
23
requests
34
flask
45
-r reqs-base.txt

0 commit comments

Comments
 (0)