diff --git a/appmap/django.py b/appmap/django.py index 4171a445..ebe515a2 100644 --- a/appmap/django.py +++ b/appmap/django.py @@ -6,6 +6,7 @@ """ import json +import logging import re import sys import time @@ -37,6 +38,8 @@ from ._implementation.web_framework import AppmapMiddleware from ._implementation.web_framework import TemplateHandler as BaseTemplateHandler +logger = logging.getLogger(__name__) + def parse_pg_version(version): """Transform postgres version number like 120005 to a tuple like 12.0.5.""" @@ -296,10 +299,23 @@ def after_request_main(self, rec, response, start, call_event_id): def inject_middleware(): """Make sure AppMap middleware is added to the stack""" if "appmap.django.Middleware" not in settings.MIDDLEWARE: + stack = list(settings.MIDDLEWARE) + new_middleware = ["appmap.django.Middleware"] if DetectEnabled.should_enable("remote"): new_middleware.insert(0, "appmap._implementation.django.RemoteRecording") - settings.MIDDLEWARE[0:0] = new_middleware + + stack[0:0] = new_middleware + # Django is ok with settings.MIDDLEWARE being any kind iterable. Update it, without changing + # its type, if we can. + if isinstance(settings.MIDDLEWARE, list): + settings.MIDDLEWARE = stack + elif isinstance(settings.MIDDLEWARE, tuple): + settings.MIDDLEWARE = tuple(stack) + else: + logger.warning( + f"Don't know how to update settings.MIDDLEWARE of type {type(settings.MIDDLEWARE)}, recording is not enabled." + ) original_load_middleware = BaseHandler.load_middleware diff --git a/appmap/test/data/django/test/test_app.py b/appmap/test/data/django/test/test_app.py index c57b9fc5..33ac9a2a 100644 --- a/appmap/test/data/django/test/test_app.py +++ b/appmap/test/data/django/test/test_app.py @@ -1,13 +1,19 @@ import app +import pytest from django.core.handlers.base import BaseHandler from django.test import Client -def test_middleware(rf, settings): - settings.MIDDLEWARE = ["app.middleware.hello_world"] - request = rf.get("/") +@pytest.mark.parametrize( + "mware", [["app.middleware.hello_world"], ("app.middleware.hello_world",)] +) +def test_middleware(rf, settings, mware): + settings.MIDDLEWARE = mware + orig_type = type(settings.MIDDLEWARE) + request = rf.get("/_appmap/record") handler = BaseHandler() handler.load_middleware() + assert type(settings.MIDDLEWARE) == orig_type response = handler.get_response(request) assert response.status_code == 200 diff --git a/appmap/test/test_django.py b/appmap/test/test_django.py index 31f487cd..55691c53 100644 --- a/appmap/test/test_django.py +++ b/appmap/test/test_django.py @@ -191,7 +191,8 @@ def test_middleware_reset(pytester, monkeypatch): # To really check middleware reset, the tests must run in order, # so disable randomly. - pytester.runpytest("-svv", "-p", "no:randomly") + result = pytester.runpytest("-svv", "-p", "no:randomly") + result.assert_outcomes(passed=3, failed=0, errors=0) # Look for the http_server_request event in test_app's appmap. If # middleware reset is broken, it won't be there.