diff --git a/newrelic/hooks/framework_django.py b/newrelic/hooks/framework_django.py index 005f282795..18cfc74156 100644 --- a/newrelic/hooks/framework_django.py +++ b/newrelic/hooks/framework_django.py @@ -12,48 +12,73 @@ # See the License for the specific language governing permissions and # limitations under the License. +import functools +import logging import sys import threading -import logging -import functools - -from newrelic.packages import six from newrelic.api.application import register_application from newrelic.api.background_task import BackgroundTaskWrapper from newrelic.api.error_trace import wrap_error_trace -from newrelic.api.function_trace import (FunctionTrace, wrap_function_trace, - FunctionTraceWrapper) +from newrelic.api.function_trace import ( + FunctionTrace, + FunctionTraceWrapper, + wrap_function_trace, +) from newrelic.api.html_insertion import insert_html_snippet -from newrelic.api.transaction import current_transaction from newrelic.api.time_trace import notice_error +from newrelic.api.transaction import current_transaction from newrelic.api.transaction_name import wrap_transaction_name from newrelic.api.wsgi_application import WSGIApplicationWrapper - -from newrelic.common.object_wrapper import (FunctionWrapper, wrap_in_function, - wrap_post_function, wrap_function_wrapper, function_wrapper) +from newrelic.common.coroutine import is_asyncio_coroutine, is_coroutine_function from newrelic.common.object_names import callable_name +from newrelic.common.object_wrapper import ( + FunctionWrapper, + function_wrapper, + wrap_function_wrapper, + wrap_in_function, + wrap_post_function, +) from newrelic.config import extra_settings from newrelic.core.config import global_settings -from newrelic.common.coroutine import is_coroutine_function, is_asyncio_coroutine +from newrelic.packages import six if six.PY3: from newrelic.hooks.framework_django_py3 import ( - _nr_wrapper_BaseHandler_get_response_async_, _nr_wrap_converted_middleware_async_, + _nr_wrapper_BaseHandler_get_response_async_, ) +# These middleware are not useful to wrap as they don't do anything particularly +# interesting that could cause performance issues. +MIDDLEWARE_DENY_WRAP = frozenset( + { + "django.middleware.csrf:CsrfViewMiddleware", + "django.middleware.clickjacking:XFrameOptionsMiddleware", + "django.contrib.messages.middleware:MessageMiddleware", + "django.middleware.csrf:CsrfViewMiddleware", + "django.middleware.common:CommonMiddleware", + "django.middleware.security:SecurityMiddleware", + } +) + _logger = logging.getLogger(__name__) _boolean_states = { - '1': True, 'yes': True, 'true': True, 'on': True, - '0': False, 'no': False, 'false': False, 'off': False + "1": True, + "yes": True, + "true": True, + "on": True, + "0": False, + "no": False, + "false": False, + "off": False, } def _setting_boolean(value): if value.lower() not in _boolean_states: - raise ValueError('Not a boolean: %s' % value) + raise ValueError("Not a boolean: %s" % value) return _boolean_states[value.lower()] @@ -62,21 +87,20 @@ def _setting_set(value): _settings_types = { - 'browser_monitoring.auto_instrument': _setting_boolean, - 'instrumentation.templates.inclusion_tag': _setting_set, - 'instrumentation.background_task.startup_timeout': float, - 'instrumentation.scripts.django_admin': _setting_set, + "browser_monitoring.auto_instrument": _setting_boolean, + "instrumentation.templates.inclusion_tag": _setting_set, + "instrumentation.background_task.startup_timeout": float, + "instrumentation.scripts.django_admin": _setting_set, } _settings_defaults = { - 'browser_monitoring.auto_instrument': True, - 'instrumentation.templates.inclusion_tag': set(), - 'instrumentation.background_task.startup_timeout': 10.0, - 'instrumentation.scripts.django_admin': set(), + "browser_monitoring.auto_instrument": True, + "instrumentation.templates.inclusion_tag": set(), + "instrumentation.background_task.startup_timeout": 10.0, + "instrumentation.scripts.django_admin": set(), } -django_settings = extra_settings('import-hook:django', - types=_settings_types, defaults=_settings_defaults) +django_settings = extra_settings("import-hook:django", types=_settings_types, defaults=_settings_defaults) def should_add_browser_timing(response, transaction): @@ -92,7 +116,7 @@ def should_add_browser_timing(response, transaction): # do RUM insertion, need to move to a WSGI middleware and # deal with how to update the content length. - if hasattr(response, 'streaming_content'): + if hasattr(response, "streaming_content"): return False # Need to be running within a valid web transaction. @@ -121,21 +145,21 @@ def should_add_browser_timing(response, transaction): # a user may want to also perform insertion for # 'application/xhtml+xml'. - ctype = response.get('Content-Type', '').lower().split(';')[0] + ctype = response.get("Content-Type", "").lower().split(";")[0] if ctype not in transaction.settings.browser_monitoring.content_type: return False # Don't risk it if content encoding already set. - if response.has_header('Content-Encoding'): + if response.has_header("Content-Encoding"): return False # Don't risk it if content is actually within an attachment. - cdisposition = response.get('Content-Disposition', '').lower() + cdisposition = response.get("Content-Disposition", "").lower() - if cdisposition.split(';')[0].strip().lower() == 'attachment': + if cdisposition.split(";")[0].strip().lower() == "attachment": return False return True @@ -144,6 +168,7 @@ def should_add_browser_timing(response, transaction): # Response middleware for automatically inserting RUM header and # footer into HTML response returned by application + def browser_timing_insertion(response, transaction): # No point continuing if header is empty. This can occur if @@ -175,14 +200,15 @@ def html_to_be_inserted(): if result is not None: if transaction.settings.debug.log_autorum_middleware: - _logger.debug('RUM insertion from Django middleware ' - 'triggered. Bytes added was %r.', - len(result) - len(response.content)) + _logger.debug( + "RUM insertion from Django middleware " "triggered. Bytes added was %r.", + len(result) - len(response.content), + ) response.content = result - if response.get('Content-Length', None): - response['Content-Length'] = str(len(response.content)) + if response.get("Content-Length", None): + response["Content-Length"] = str(len(response.content)) return response @@ -192,18 +218,19 @@ def html_to_be_inserted(): # 'newrelic' will be automatically inserted into set of tag # libraries when performing step to instrument the middleware. + def newrelic_browser_timing_header(): from django.utils.safestring import mark_safe transaction = current_transaction() - return transaction and mark_safe(transaction.browser_timing_header()) or '' + return transaction and mark_safe(transaction.browser_timing_header()) or "" # nosec def newrelic_browser_timing_footer(): from django.utils.safestring import mark_safe transaction = current_transaction() - return transaction and mark_safe(transaction.browser_timing_footer()) or '' + return transaction and mark_safe(transaction.browser_timing_footer()) or "" # nosec # Addition of instrumentation for middleware. Can only do this @@ -253,73 +280,12 @@ def wrapper(wrapped, instance, args, kwargs): return FunctionWrapper(wrapped, wrapper) for wrapped in middleware: - yield wrapper(wrapped) - - -def wrap_view_middleware(middleware): - - # XXX This is no longer being used. The changes to strip the - # wrapper from the view handler when passed into the function - # urlresolvers.reverse() solves most of the problems. To back - # that up, the object wrapper now proxies various special - # methods so that comparisons like '==' will work. The object - # wrapper can even be used as a standin for the wrapped object - # when used as a key in a dictionary and will correctly match - # the original wrapped object. - - # Wrapper to be applied to view middleware. Records the time - # spent in the middleware as separate function node and also - # attempts to name the web transaction after the name of the - # middleware with success being determined by the priority. - # This wrapper is special in that it must strip the wrapper - # from the view handler when being passed to the view - # middleware to avoid issues where middleware wants to do - # comparisons between the passed middleware and some other - # value. It is believed that the view handler should never - # actually be called from the view middleware so not an - # issue that no longer wrapped at this point. + do_not_wrap = is_denied_middleware(callable_name(wrapped)) - def wrapper(wrapped): - # The middleware if a class method would already be - # bound at this point, so is safe to determine the name - # when it is being wrapped rather than on each - # invocation. - - name = callable_name(wrapped) - - def wrapper(wrapped, instance, args, kwargs): - transaction = current_transaction() - - def _wrapped(request, view_func, view_args, view_kwargs): - # This strips the view handler wrapper before call. - - if hasattr(view_func, '_nr_last_object'): - view_func = view_func._nr_last_object - - return wrapped(request, view_func, view_args, view_kwargs) - - if transaction is None: - return _wrapped(*args, **kwargs) - - before = (transaction.name, transaction.group) - - with FunctionTrace(name=name, source=wrapped): - try: - return _wrapped(*args, **kwargs) - - finally: - # We want to name the transaction after this - # middleware but only if the transaction wasn't - # named from within the middleware itself explicitly. - - after = (transaction.name, transaction.group) - if before == after: - transaction.set_transaction_name(name, priority=2) - - return FunctionWrapper(wrapped, wrapper) - - for wrapped in middleware: - yield wrapper(wrapped) + if do_not_wrap: + yield wrapped + else: + yield wrapper(wrapped) def wrap_trailing_middleware(middleware): @@ -335,7 +301,13 @@ def wrap_trailing_middleware(middleware): # invocation. for wrapped in middleware: - yield FunctionTraceWrapper(wrapped, name=callable_name(wrapped)) + name = callable_name(wrapped) + do_not_wrap = is_denied_middleware(name) + + if do_not_wrap: + yield wrapped + else: + yield FunctionTraceWrapper(wrapped, name=name) def insert_and_wrap_middleware(handler, *args, **kwargs): @@ -370,37 +342,28 @@ def insert_and_wrap_middleware(handler, *args, **kwargs): # priority than that for view handler so view handler # name always takes precedence. - if hasattr(handler, '_request_middleware'): - handler._request_middleware = list( - wrap_leading_middleware( - handler._request_middleware)) + if hasattr(handler, "_request_middleware"): + handler._request_middleware = list(wrap_leading_middleware(handler._request_middleware)) - if hasattr(handler, '_view_middleware'): - handler._view_middleware = list( - wrap_leading_middleware( - handler._view_middleware)) + if hasattr(handler, "_view_middleware"): + handler._view_middleware = list(wrap_leading_middleware(handler._view_middleware)) - if hasattr(handler, '_template_response_middleware'): + if hasattr(handler, "_template_response_middleware"): handler._template_response_middleware = list( - wrap_trailing_middleware( - handler._template_response_middleware)) + wrap_trailing_middleware(handler._template_response_middleware) + ) - if hasattr(handler, '_response_middleware'): - handler._response_middleware = list( - wrap_trailing_middleware( - handler._response_middleware)) + if hasattr(handler, "_response_middleware"): + handler._response_middleware = list(wrap_trailing_middleware(handler._response_middleware)) - if hasattr(handler, '_exception_middleware'): - handler._exception_middleware = list( - wrap_trailing_middleware( - handler._exception_middleware)) + if hasattr(handler, "_exception_middleware"): + handler._exception_middleware = list(wrap_trailing_middleware(handler._exception_middleware)) finally: lock.release() -def _nr_wrapper_GZipMiddleware_process_response_(wrapped, instance, args, - kwargs): +def _nr_wrapper_GZipMiddleware_process_response_(wrapped, instance, args, kwargs): transaction = current_transaction() @@ -433,36 +396,33 @@ def _nr_wrapper_BaseHandler_get_response_(wrapped, instance, args, kwargs): request = _bind_get_response(*args, **kwargs) - if hasattr(request, '_nr_exc_info'): + if hasattr(request, "_nr_exc_info"): notice_error(error=request._nr_exc_info, status_code=response.status_code) - delattr(request, '_nr_exc_info') + delattr(request, "_nr_exc_info") return response # Post import hooks for modules. + def instrument_django_core_handlers_base(module): # Attach a post function to load_middleware() method of # BaseHandler to trigger insertion of browser timing # middleware and wrapping of middleware for timing etc. - wrap_post_function(module, 'BaseHandler.load_middleware', - insert_and_wrap_middleware) + wrap_post_function(module, "BaseHandler.load_middleware", insert_and_wrap_middleware) - if six.PY3 and hasattr(module.BaseHandler, 'get_response_async'): - wrap_function_wrapper(module, 'BaseHandler.get_response_async', - _nr_wrapper_BaseHandler_get_response_async_) + if six.PY3 and hasattr(module.BaseHandler, "get_response_async"): + wrap_function_wrapper(module, "BaseHandler.get_response_async", _nr_wrapper_BaseHandler_get_response_async_) - wrap_function_wrapper(module, 'BaseHandler.get_response', - _nr_wrapper_BaseHandler_get_response_) + wrap_function_wrapper(module, "BaseHandler.get_response", _nr_wrapper_BaseHandler_get_response_) def instrument_django_gzip_middleware(module): - wrap_function_wrapper(module, 'GZipMiddleware.process_response', - _nr_wrapper_GZipMiddleware_process_response_) + wrap_function_wrapper(module, "GZipMiddleware.process_response", _nr_wrapper_GZipMiddleware_process_response_) def wrap_handle_uncaught_exception(middleware): @@ -506,10 +466,9 @@ def instrument_django_core_handlers_wsgi(module): import django - framework = ('Django', django.get_version()) + framework = ("Django", django.get_version()) - module.WSGIHandler.__call__ = WSGIApplicationWrapper( - module.WSGIHandler.__call__, framework=framework) + module.WSGIHandler.__call__ = WSGIApplicationWrapper(module.WSGIHandler.__call__, framework=framework) # Wrap handle_uncaught_exception() of WSGIHandler so that # can capture exception details of any exception which @@ -519,10 +478,10 @@ def instrument_django_core_handlers_wsgi(module): # exception, so last chance to do this as exception will not # propagate up to the WSGI application. - if hasattr(module.WSGIHandler, 'handle_uncaught_exception'): - module.WSGIHandler.handle_uncaught_exception = ( - wrap_handle_uncaught_exception( - module.WSGIHandler.handle_uncaught_exception)) + if hasattr(module.WSGIHandler, "handle_uncaught_exception"): + module.WSGIHandler.handle_uncaught_exception = wrap_handle_uncaught_exception( + module.WSGIHandler.handle_uncaught_exception + ) def wrap_view_handler(wrapped, priority=3): @@ -532,7 +491,7 @@ def wrap_view_handler(wrapped, priority=3): # called recursively. We flag that view handler was wrapped # using the '_nr_django_view_handler' attribute. - if hasattr(wrapped, '_nr_django_view_handler'): + if hasattr(wrapped, "_nr_django_view_handler"): return wrapped if hasattr(wrapped, "view_class"): @@ -584,7 +543,7 @@ def wrapper(wrapped, instance, args, kwargs): if transaction is None: return wrapped(*args, **kwargs) - if hasattr(transaction, '_nr_django_url_resolver'): + if hasattr(transaction, "_nr_django_url_resolver"): return wrapped(*args, **kwargs) # Tag the transaction so we know when we are in the top @@ -602,8 +561,7 @@ def _wrapped(path): if type(result) is tuple: callback, callback_args, callback_kwargs = result - result = (wrap_view_handler(callback, priority=5), - callback_args, callback_kwargs) + result = (wrap_view_handler(callback, priority=5), callback_args, callback_kwargs) else: result.func = wrap_view_handler(result.func, priority=5) @@ -636,8 +594,7 @@ def wrapper(wrapped, instance, args, kwargs): return wrap_view_handler(result, priority=priority) else: callback, param_dict = result - return (wrap_view_handler(callback, priority=priority), - param_dict) + return (wrap_view_handler(callback, priority=priority), param_dict) return FunctionWrapper(wrapped, wrapper) @@ -653,9 +610,10 @@ def wrap_url_reverse(wrapped): def wrapper(wrapped, instance, args, kwargs): def execute(viewname, *args, **kwargs): - if hasattr(viewname, '_nr_last_object'): + if hasattr(viewname, "_nr_last_object"): viewname = viewname._nr_last_object return wrapped(viewname, *args, **kwargs) + return execute(*args, **kwargs) return FunctionWrapper(wrapped, wrapper) @@ -672,20 +630,19 @@ def instrument_django_core_urlresolvers(module): # lost. We thus intercept it here so can capture that # traceback which is otherwise lost. - wrap_error_trace(module, 'get_callable') + wrap_error_trace(module, "get_callable") # Wrap methods which resolves a request to a view handler. # This can be called against a resolver initialised against # a custom URL conf associated with a specific request, or a # resolver which uses the default URL conf. - if hasattr(module, 'RegexURLResolver'): + if hasattr(module, "RegexURLResolver"): urlresolver = module.RegexURLResolver else: urlresolver = module.URLResolver - urlresolver.resolve = wrap_url_resolver( - urlresolver.resolve) + urlresolver.resolve = wrap_url_resolver(urlresolver.resolve) # Wrap methods which resolve error handlers. For 403 and 404 # we give these higher naming priority over any prior @@ -695,26 +652,22 @@ def instrument_django_core_urlresolvers(module): # handler in place so error details identify the correct # transaction. - if hasattr(urlresolver, 'resolve403'): - urlresolver.resolve403 = wrap_url_resolver_nnn( - urlresolver.resolve403, priority=3) + if hasattr(urlresolver, "resolve403"): + urlresolver.resolve403 = wrap_url_resolver_nnn(urlresolver.resolve403, priority=3) - if hasattr(urlresolver, 'resolve404'): - urlresolver.resolve404 = wrap_url_resolver_nnn( - urlresolver.resolve404, priority=3) + if hasattr(urlresolver, "resolve404"): + urlresolver.resolve404 = wrap_url_resolver_nnn(urlresolver.resolve404, priority=3) - if hasattr(urlresolver, 'resolve500'): - urlresolver.resolve500 = wrap_url_resolver_nnn( - urlresolver.resolve500, priority=1) + if hasattr(urlresolver, "resolve500"): + urlresolver.resolve500 = wrap_url_resolver_nnn(urlresolver.resolve500, priority=1) - if hasattr(urlresolver, 'resolve_error_handler'): - urlresolver.resolve_error_handler = wrap_url_resolver_nnn( - urlresolver.resolve_error_handler, priority=1) + if hasattr(urlresolver, "resolve_error_handler"): + urlresolver.resolve_error_handler = wrap_url_resolver_nnn(urlresolver.resolve_error_handler, priority=1) # Wrap function for performing reverse URL lookup to strip any # instrumentation wrapper when view handler is passed in. - if hasattr(module, 'reverse'): + if hasattr(module, "reverse"): module.reverse = wrap_url_reverse(module.reverse) @@ -723,7 +676,7 @@ def instrument_django_urls_base(module): # Wrap function for performing reverse URL lookup to strip any # instrumentation wrapper when view handler is passed in. - if hasattr(module, 'reverse'): + if hasattr(module, "reverse"): module.reverse = wrap_url_reverse(module.reverse) @@ -742,17 +695,15 @@ def instrument_django_template(module): def template_name(template, *args): return template.name - if hasattr(module.Template, '_render'): - wrap_function_trace(module, 'Template._render', - name=template_name, group='Template/Render') + if hasattr(module.Template, "_render"): + wrap_function_trace(module, "Template._render", name=template_name, group="Template/Render") else: - wrap_function_trace(module, 'Template.render', - name=template_name, group='Template/Render') + wrap_function_trace(module, "Template.render", name=template_name, group="Template/Render") # Django 1.8 no longer has module.libraries. As automatic way is not # preferred we can just skip this now. - if not hasattr(module, 'libraries'): + if not hasattr(module, "libraries"): return # Register template tags used for manual insertion of RUM @@ -766,12 +717,12 @@ def template_name(template, *args): library.simple_tag(newrelic_browser_timing_header) library.simple_tag(newrelic_browser_timing_footer) - module.libraries['django.templatetags.newrelic'] = library + module.libraries["django.templatetags.newrelic"] = library def wrap_template_block(wrapped): def wrapper(wrapped, instance, args, kwargs): - return FunctionTraceWrapper(wrapped, name=instance.name, group='Template/Block')(*args, **kwargs) + return FunctionTraceWrapper(wrapped, name=instance.name, group="Template/Block")(*args, **kwargs) return FunctionWrapper(wrapped, wrapper) @@ -812,11 +763,15 @@ def instrument_django_core_servers_basehttp(module): # instrumentation of the wsgiref module or some other means. def wrap_wsgi_application_entry_point(server, application, **kwargs): - return ((server, WSGIApplicationWrapper(application, - framework='Django'),), kwargs) + return ( + ( + server, + WSGIApplicationWrapper(application, framework="Django"), + ), + kwargs, + ) - if (not hasattr(module, 'simple_server') and - hasattr(module.ServerHandler, 'run')): + if not hasattr(module, "simple_server") and hasattr(module.ServerHandler, "run"): # Patch the server to make it work properly. @@ -833,11 +788,10 @@ def run(self, application): def close(self): if self.result is not None: try: - self.request_handler.log_request( - self.status.split(' ', 1)[0], self.bytes_sent) + self.request_handler.log_request(self.status.split(" ", 1)[0], self.bytes_sent) finally: try: - if hasattr(self.result, 'close'): + if hasattr(self.result, "close"): self.result.close() finally: self.result = None @@ -855,17 +809,16 @@ def close(self): # Now wrap it with our instrumentation. - wrap_in_function(module, 'ServerHandler.run', - wrap_wsgi_application_entry_point) + wrap_in_function(module, "ServerHandler.run", wrap_wsgi_application_entry_point) def instrument_django_contrib_staticfiles_views(module): - if not hasattr(module.serve, '_nr_django_view_handler'): + if not hasattr(module.serve, "_nr_django_view_handler"): module.serve = wrap_view_handler(module.serve, priority=3) def instrument_django_contrib_staticfiles_handlers(module): - wrap_transaction_name(module, 'StaticFilesHandler.serve') + wrap_transaction_name(module, "StaticFilesHandler.serve") def instrument_django_views_debug(module): @@ -878,10 +831,8 @@ def instrument_django_views_debug(module): # from a middleware or view handler in place so error # details identify the correct transaction. - module.technical_404_response = wrap_view_handler( - module.technical_404_response, priority=3) - module.technical_500_response = wrap_view_handler( - module.technical_500_response, priority=1) + module.technical_404_response = wrap_view_handler(module.technical_404_response, priority=3) + module.technical_500_response = wrap_view_handler(module.technical_500_response, priority=1) def resolve_view_handler(view, request): @@ -890,8 +841,7 @@ def resolve_view_handler(view, request): # duplicate the lookup mechanism. if request.method.lower() in view.http_method_names: - handler = getattr(view, request.method.lower(), - view.http_method_not_allowed) + handler = getattr(view, request.method.lower(), view.http_method_not_allowed) else: handler = view.http_method_not_allowed @@ -936,7 +886,7 @@ def _args(request, *args, **kwargs): priority = 4 - if transaction.group == 'Function': + if transaction.group == "Function": if transaction.name == callable_name(view): priority = 5 @@ -953,22 +903,22 @@ def instrument_django_views_generic_base(module): def instrument_django_http_multipartparser(module): - wrap_function_trace(module, 'MultiPartParser.parse') + wrap_function_trace(module, "MultiPartParser.parse") def instrument_django_core_mail(module): - wrap_function_trace(module, 'mail_admins') - wrap_function_trace(module, 'mail_managers') - wrap_function_trace(module, 'send_mail') + wrap_function_trace(module, "mail_admins") + wrap_function_trace(module, "mail_managers") + wrap_function_trace(module, "send_mail") def instrument_django_core_mail_message(module): - wrap_function_trace(module, 'EmailMessage.send') + wrap_function_trace(module, "EmailMessage.send") def _nr_wrapper_BaseCommand___init___(wrapped, instance, args, kwargs): instance.handle = FunctionTraceWrapper(instance.handle) - if hasattr(instance, 'handle_noargs'): + if hasattr(instance, "handle_noargs"): instance.handle_noargs = FunctionTraceWrapper(instance.handle_noargs) return wrapped(*args, **kwargs) @@ -982,29 +932,25 @@ def _args(argv, *args, **kwargs): subcommand = _argv[1] commands = django_settings.instrumentation.scripts.django_admin - startup_timeout = \ - django_settings.instrumentation.background_task.startup_timeout + startup_timeout = django_settings.instrumentation.background_task.startup_timeout if subcommand not in commands: return wrapped(*args, **kwargs) application = register_application(timeout=startup_timeout) - return BackgroundTaskWrapper(wrapped, application, subcommand, 'Django')(*args, **kwargs) + return BackgroundTaskWrapper(wrapped, application, subcommand, "Django")(*args, **kwargs) def instrument_django_core_management_base(module): - wrap_function_wrapper(module, 'BaseCommand.__init__', - _nr_wrapper_BaseCommand___init___) - wrap_function_wrapper(module, 'BaseCommand.run_from_argv', - _nr_wrapper_BaseCommand_run_from_argv_) + wrap_function_wrapper(module, "BaseCommand.__init__", _nr_wrapper_BaseCommand___init___) + wrap_function_wrapper(module, "BaseCommand.run_from_argv", _nr_wrapper_BaseCommand_run_from_argv_) @function_wrapper -def _nr_wrapper_django_inclusion_tag_wrapper_(wrapped, instance, - args, kwargs): +def _nr_wrapper_django_inclusion_tag_wrapper_(wrapped, instance, args, kwargs): - name = hasattr(wrapped, '__name__') and wrapped.__name__ + name = hasattr(wrapped, "__name__") and wrapped.__name__ if name is None: return wrapped(*args, **kwargs) @@ -1013,16 +959,14 @@ def _nr_wrapper_django_inclusion_tag_wrapper_(wrapped, instance, tags = django_settings.instrumentation.templates.inclusion_tag - if '*' not in tags and name not in tags and qualname not in tags: + if "*" not in tags and name not in tags and qualname not in tags: return wrapped(*args, **kwargs) - return FunctionTraceWrapper(wrapped, name=name, group='Template/Tag')(*args, **kwargs) + return FunctionTraceWrapper(wrapped, name=name, group="Template/Tag")(*args, **kwargs) @function_wrapper -def _nr_wrapper_django_inclusion_tag_decorator_(wrapped, instance, - args, kwargs): - +def _nr_wrapper_django_inclusion_tag_decorator_(wrapped, instance, args, kwargs): def _bind_params(func, *args, **kwargs): return func, args, kwargs @@ -1033,63 +977,56 @@ def _bind_params(func, *args, **kwargs): return wrapped(func, *_args, **_kwargs) -def _nr_wrapper_django_template_base_Library_inclusion_tag_(wrapped, - instance, args, kwargs): +def _nr_wrapper_django_template_base_Library_inclusion_tag_(wrapped, instance, args, kwargs): - return _nr_wrapper_django_inclusion_tag_decorator_( - wrapped(*args, **kwargs)) + return _nr_wrapper_django_inclusion_tag_decorator_(wrapped(*args, **kwargs)) @function_wrapper -def _nr_wrapper_django_template_base_InclusionNode_render_(wrapped, - instance, args, kwargs): +def _nr_wrapper_django_template_base_InclusionNode_render_(wrapped, instance, args, kwargs): if wrapped.__self__ is None: return wrapped(*args, **kwargs) - file_name = getattr(wrapped.__self__, '_nr_file_name', None) + file_name = getattr(wrapped.__self__, "_nr_file_name", None) if file_name is None: return wrapped(*args, **kwargs) name = wrapped.__self__._nr_file_name - return FunctionTraceWrapper(wrapped, name=name, group='Template/Include')(*args, **kwargs) + return FunctionTraceWrapper(wrapped, name=name, group="Template/Include")(*args, **kwargs) -def _nr_wrapper_django_template_base_generic_tag_compiler_(wrapped, instance, - args, kwargs): +def _nr_wrapper_django_template_base_generic_tag_compiler_(wrapped, instance, args, kwargs): if wrapped.__code__.co_argcount > 6: # Django > 1.3. - def _bind_params(parser, token, params, varargs, varkw, defaults, - name, takes_context, node_class, *args, **kwargs): + def _bind_params( + parser, token, params, varargs, varkw, defaults, name, takes_context, node_class, *args, **kwargs + ): return node_class + else: # Django <= 1.3. - def _bind_params(params, defaults, name, node_class, parser, token, - *args, **kwargs): + def _bind_params(params, defaults, name, node_class, parser, token, *args, **kwargs): return node_class node_class = _bind_params(*args, **kwargs) - if node_class.__name__ == 'InclusionNode': + if node_class.__name__ == "InclusionNode": result = wrapped(*args, **kwargs) - result.render = ( - _nr_wrapper_django_template_base_InclusionNode_render_( - result.render)) + result.render = _nr_wrapper_django_template_base_InclusionNode_render_(result.render) return result return wrapped(*args, **kwargs) -def _nr_wrapper_django_template_base_Library_tag_(wrapped, instance, - args, kwargs): - +def _nr_wrapper_django_template_base_Library_tag_(wrapped, instance, args, kwargs): def _bind_params(name=None, compile_function=None, *args, **kwargs): return compile_function @@ -1105,14 +1042,16 @@ def _get_node_class(compile_function): # Django >= 1.4 uses functools.partial if isinstance(compile_function, functools.partial): - node_class = compile_function.keywords.get('node_class') + node_class = compile_function.keywords.get("node_class") # Django < 1.4 uses their home-grown "curry" function, # not functools.partial. - if (hasattr(compile_function, 'func_closure') and - hasattr(compile_function, '__name__') and - compile_function.__name__ == '_curried'): + if ( + hasattr(compile_function, "func_closure") + and hasattr(compile_function, "__name__") + and compile_function.__name__ == "_curried" + ): # compile_function here is generic_tag_compiler(), which has been # curried. To get node_class, we first get the function obj, args, @@ -1121,19 +1060,20 @@ def _get_node_class(compile_function): # is not consistent from platform to platform, so we need to map # them to the variables in compile_function.__code__.co_freevars. - cells = dict(zip(compile_function.__code__.co_freevars, - (c.cell_contents for c in compile_function.func_closure))) + cells = dict( + zip(compile_function.__code__.co_freevars, (c.cell_contents for c in compile_function.func_closure)) + ) # node_class is the 4th arg passed to generic_tag_compiler() - if 'args' in cells and len(cells['args']) > 3: - node_class = cells['args'][3] + if "args" in cells and len(cells["args"]) > 3: + node_class = cells["args"][3] return node_class node_class = _get_node_class(compile_function) - if node_class is None or node_class.__name__ != 'InclusionNode': + if node_class is None or node_class.__name__ != "InclusionNode": return wrapped(*args, **kwargs) # Climb stack to find the file_name of the include template. @@ -1146,9 +1086,8 @@ def _get_node_class(compile_function): for i in range(1, stack_levels + 1): frame = sys._getframe(i) - if ('generic_tag_compiler' in frame.f_code.co_names and - 'file_name' in frame.f_code.co_freevars): - file_name = frame.f_locals.get('file_name') + if "generic_tag_compiler" in frame.f_code.co_names and "file_name" in frame.f_code.co_freevars: + file_name = frame.f_locals.get("file_name") if file_name is None: return wrapped(*args, **kwargs) @@ -1167,22 +1106,22 @@ def instrument_django_template_base(module): settings = global_settings() - if 'django.instrumentation.inclusion-tags.r1' in settings.feature_flag: + if "django.instrumentation.inclusion-tags.r1" in settings.feature_flag: - if hasattr(module, 'generic_tag_compiler'): - wrap_function_wrapper(module, 'generic_tag_compiler', - _nr_wrapper_django_template_base_generic_tag_compiler_) + if hasattr(module, "generic_tag_compiler"): + wrap_function_wrapper( + module, "generic_tag_compiler", _nr_wrapper_django_template_base_generic_tag_compiler_ + ) - if hasattr(module, 'Library'): - wrap_function_wrapper(module, 'Library.tag', - _nr_wrapper_django_template_base_Library_tag_) + if hasattr(module, "Library"): + wrap_function_wrapper(module, "Library.tag", _nr_wrapper_django_template_base_Library_tag_) - wrap_function_wrapper(module, 'Library.inclusion_tag', - _nr_wrapper_django_template_base_Library_inclusion_tag_) + wrap_function_wrapper( + module, "Library.inclusion_tag", _nr_wrapper_django_template_base_Library_inclusion_tag_ + ) def _nr_wrap_converted_middleware_(middleware, name): - @function_wrapper def _wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() @@ -1197,38 +1136,45 @@ def _wrapper(wrapped, instance, args, kwargs): return _wrapper(middleware) -def _nr_wrapper_convert_exception_to_response_(wrapped, instance, args, - kwargs): +def is_denied_middleware(callable_name): + for middleware in MIDDLEWARE_DENY_WRAP: + if middleware in callable_name: + return True + return False + +def _nr_wrapper_convert_exception_to_response_(wrapped, instance, args, kwargs): def _bind_params(original_middleware, *args, **kwargs): return original_middleware original_middleware = _bind_params(*args, **kwargs) converted_middleware = wrapped(*args, **kwargs) name = callable_name(original_middleware) + do_not_wrap = is_denied_middleware(name) - if is_coroutine_function(converted_middleware) or is_asyncio_coroutine(converted_middleware): - return _nr_wrap_converted_middleware_async_(converted_middleware, name) - return _nr_wrap_converted_middleware_(converted_middleware, name) + if do_not_wrap: + return converted_middleware + else: + if is_coroutine_function(converted_middleware) or is_asyncio_coroutine(converted_middleware): + return _nr_wrap_converted_middleware_async_(converted_middleware, name) + return _nr_wrap_converted_middleware_(converted_middleware, name) def instrument_django_core_handlers_exception(module): - if hasattr(module, 'convert_exception_to_response'): - wrap_function_wrapper(module, 'convert_exception_to_response', - _nr_wrapper_convert_exception_to_response_) + if hasattr(module, "convert_exception_to_response"): + wrap_function_wrapper(module, "convert_exception_to_response", _nr_wrapper_convert_exception_to_response_) - if hasattr(module, 'handle_uncaught_exception'): - module.handle_uncaught_exception = ( - wrap_handle_uncaught_exception( - module.handle_uncaught_exception)) + if hasattr(module, "handle_uncaught_exception"): + module.handle_uncaught_exception = wrap_handle_uncaught_exception(module.handle_uncaught_exception) def instrument_django_core_handlers_asgi(module): import django - framework = ('Django', django.get_version()) + framework = ("Django", django.get_version()) - if hasattr(module, 'ASGIHandler'): + if hasattr(module, "ASGIHandler"): from newrelic.api.asgi_application import wrap_asgi_application - wrap_asgi_application(module, 'ASGIHandler.__call__', framework=framework) + + wrap_asgi_application(module, "ASGIHandler.__call__", framework=framework) diff --git a/tests/component_djangorestframework/test_application.py b/tests/component_djangorestframework/test_application.py index 9ed60aa33d..19e9f54d36 100644 --- a/tests/component_djangorestframework/test_application.py +++ b/tests/component_djangorestframework/test_application.py @@ -12,190 +12,169 @@ # See the License for the specific language governing permissions and # limitations under the License. +import django import pytest import webtest +from testing_support.fixtures import function_not_called, override_generic_settings +from testing_support.validators.validate_code_level_metrics import ( + validate_code_level_metrics, +) +from testing_support.validators.validate_transaction_errors import ( + validate_transaction_errors, +) +from testing_support.validators.validate_transaction_metrics import ( + validate_transaction_metrics, +) -from newrelic.packages import six from newrelic.core.config import global_settings +from newrelic.packages import six -from testing_support.fixtures import ( - override_generic_settings, - function_not_called) -from testing_support.validators.validate_transaction_errors import validate_transaction_errors -from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics -from testing_support.validators.validate_code_level_metrics import validate_code_level_metrics -import django - -DJANGO_VERSION = tuple(map(int, django.get_version().split('.')[:2])) +DJANGO_VERSION = tuple(map(int, django.get_version().split(".")[:2])) -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def target_application(): from wsgi import application + test_application = webtest.TestApp(application) return test_application if DJANGO_VERSION >= (1, 10): - url_module_path = 'django.urls.resolvers' + url_module_path = "django.urls.resolvers" # Django 1.10 new style middleware removed individual process_* methods. # All middleware in Django 1.10+ is called through the __call__ methods on # middlwares. - process_request_method = '' - process_view_method = '' - process_response_method = '' + process_request_method = "" + process_view_method = "" + process_response_method = "" else: - url_module_path = 'django.core.urlresolvers' - process_request_method = '.process_request' - process_view_method = '.process_view' - process_response_method = '.process_response' + url_module_path = "django.core.urlresolvers" + process_request_method = ".process_request" + process_view_method = ".process_view" + process_response_method = ".process_response" if DJANGO_VERSION >= (2, 0): - url_resolver_cls = 'URLResolver' + url_resolver_cls = "URLResolver" else: - url_resolver_cls = 'RegexURLResolver' + url_resolver_cls = "RegexURLResolver" _scoped_metrics = [ - ('Function/django.core.handlers.wsgi:WSGIHandler.__call__', 1), - ('Python/WSGI/Application', 1), - ('Python/WSGI/Response', 1), - ('Python/WSGI/Finalize', 1), - (('Function/django.middleware.common:' - 'CommonMiddleware' + process_request_method), 1), - (('Function/django.contrib.sessions.middleware:' - 'SessionMiddleware' + process_request_method), 1), - (('Function/django.contrib.auth.middleware:' - 'AuthenticationMiddleware' + process_request_method), 1), - (('Function/django.contrib.messages.middleware:' - 'MessageMiddleware' + process_request_method), 1), - (('Function/%s:' % url_module_path + - '%s.resolve' % url_resolver_cls), 1), - (('Function/django.middleware.csrf:' - 'CsrfViewMiddleware' + process_view_method), 1), - (('Function/django.contrib.messages.middleware:' - 'MessageMiddleware' + process_response_method), 1), - (('Function/django.middleware.csrf:' - 'CsrfViewMiddleware' + process_response_method), 1), - (('Function/django.contrib.sessions.middleware:' - 'SessionMiddleware' + process_response_method), 1), - (('Function/django.middleware.common:' - 'CommonMiddleware' + process_response_method), 1), + ("Function/django.core.handlers.wsgi:WSGIHandler.__call__", 1), + ("Python/WSGI/Application", 1), + ("Python/WSGI/Response", 1), + ("Python/WSGI/Finalize", 1), + (("Function/django.middleware.common:" "CommonMiddleware" + process_request_method), None), + (("Function/django.contrib.sessions.middleware:" "SessionMiddleware" + process_request_method), 1), + (("Function/django.contrib.auth.middleware:" "AuthenticationMiddleware" + process_request_method), 1), + (("Function/django.contrib.messages.middleware:" "MessageMiddleware" + process_request_method), None), + (("Function/%s:" % url_module_path + "%s.resolve" % url_resolver_cls), 1), + (("Function/django.middleware.csrf:" "CsrfViewMiddleware" + process_view_method), None), + (("Function/django.contrib.messages.middleware:" "MessageMiddleware" + process_response_method), None), + (("Function/django.middleware.csrf:" "CsrfViewMiddleware" + process_response_method), None), + (("Function/django.contrib.sessions.middleware:" "SessionMiddleware" + process_response_method), 1), + (("Function/django.middleware.common:" "CommonMiddleware" + process_response_method), None), ] _test_application_index_scoped_metrics = list(_scoped_metrics) -_test_application_index_scoped_metrics.append(('Function/views:index', 1)) +_test_application_index_scoped_metrics.append(("Function/views:index", 1)) if DJANGO_VERSION >= (1, 5): - _test_application_index_scoped_metrics.extend([ - ('Function/django.http.response:HttpResponse.close', 1)]) + _test_application_index_scoped_metrics.extend([("Function/django.http.response:HttpResponse.close", 1)]) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('views:index', - scoped_metrics=_test_application_index_scoped_metrics) +@validate_transaction_metrics("views:index", scoped_metrics=_test_application_index_scoped_metrics) @validate_code_level_metrics("views", "index") def test_application_index(target_application): - response = target_application.get('') - response.mustcontain('INDEX RESPONSE') + response = target_application.get("") + response.mustcontain("INDEX RESPONSE") _test_application_view_scoped_metrics = list(_scoped_metrics) -_test_application_view_scoped_metrics.append(('Function/urls:View.get', 1)) +_test_application_view_scoped_metrics.append(("Function/urls:View.get", 1)) if DJANGO_VERSION >= (1, 5): - _test_application_view_scoped_metrics.extend([ - ('Function/rest_framework.response:Response.close', 1)]) + _test_application_view_scoped_metrics.extend([("Function/rest_framework.response:Response.close", 1)]) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('urls:View.get', - scoped_metrics=_test_application_view_scoped_metrics) +@validate_transaction_metrics("urls:View.get", scoped_metrics=_test_application_view_scoped_metrics) @validate_code_level_metrics("urls.View", "get") def test_application_view(target_application): - response = target_application.get('/view/') + response = target_application.get("/view/") assert response.status_int == 200 - response.mustcontain('restframework view response') + response.mustcontain("restframework view response") _test_application_view_error_scoped_metrics = list(_scoped_metrics) -_test_application_view_error_scoped_metrics.append( - ('Function/urls:ViewError.get', 1)) +_test_application_view_error_scoped_metrics.append(("Function/urls:ViewError.get", 1)) -@validate_transaction_errors(errors=['urls:Error']) -@validate_transaction_metrics('urls:ViewError.get', - scoped_metrics=_test_application_view_error_scoped_metrics) +@validate_transaction_errors(errors=["urls:Error"]) +@validate_transaction_metrics("urls:ViewError.get", scoped_metrics=_test_application_view_error_scoped_metrics) @validate_code_level_metrics("urls.ViewError", "get") def test_application_view_error(target_application): - target_application.get('/view_error/', status=500) + target_application.get("/view_error/", status=500) _test_application_view_handle_error_scoped_metrics = list(_scoped_metrics) -_test_application_view_handle_error_scoped_metrics.append( - ('Function/urls:ViewHandleError.get', 1)) +_test_application_view_handle_error_scoped_metrics.append(("Function/urls:ViewHandleError.get", 1)) -@pytest.mark.parametrize('status,should_record', [(418, True), (200, False)]) -@pytest.mark.parametrize('use_global_exc_handler', [True, False]) +@pytest.mark.parametrize("status,should_record", [(418, True), (200, False)]) +@pytest.mark.parametrize("use_global_exc_handler", [True, False]) @validate_code_level_metrics("urls.ViewHandleError", "get") -def test_application_view_handle_error(status, should_record, - use_global_exc_handler, target_application): - errors = ['urls:Error'] if should_record else [] +def test_application_view_handle_error(status, should_record, use_global_exc_handler, target_application): + errors = ["urls:Error"] if should_record else [] @validate_transaction_errors(errors=errors) - @validate_transaction_metrics('urls:ViewHandleError.get', - scoped_metrics=_test_application_view_handle_error_scoped_metrics) + @validate_transaction_metrics( + "urls:ViewHandleError.get", scoped_metrics=_test_application_view_handle_error_scoped_metrics + ) def _test(): - response = target_application.get( - '/view_handle_error/%s/%s/' % (status, use_global_exc_handler), - status=status) + response = target_application.get("/view_handle_error/%s/%s/" % (status, use_global_exc_handler), status=status) if use_global_exc_handler: - response.mustcontain('exception was handled global') + response.mustcontain("exception was handled global") else: - response.mustcontain('exception was handled not global') + response.mustcontain("exception was handled not global") _test() -_test_api_view_view_name_get = 'urls:wrapped_view.get' +_test_api_view_view_name_get = "urls:wrapped_view.get" _test_api_view_scoped_metrics_get = list(_scoped_metrics) -_test_api_view_scoped_metrics_get.append( - ('Function/%s' % _test_api_view_view_name_get, 1)) +_test_api_view_scoped_metrics_get.append(("Function/%s" % _test_api_view_view_name_get, 1)) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics(_test_api_view_view_name_get, - scoped_metrics=_test_api_view_scoped_metrics_get) +@validate_transaction_metrics(_test_api_view_view_name_get, scoped_metrics=_test_api_view_scoped_metrics_get) @validate_code_level_metrics("urls.WrappedAPIView" if six.PY3 else "urls", "wrapped_view") def test_api_view_get(target_application): - response = target_application.get('/api_view/') - response.mustcontain('wrapped_view response') + response = target_application.get("/api_view/") + response.mustcontain("wrapped_view response") -_test_api_view_view_name_post = 'urls:wrapped_view.http_method_not_allowed' +_test_api_view_view_name_post = "urls:wrapped_view.http_method_not_allowed" _test_api_view_scoped_metrics_post = list(_scoped_metrics) -_test_api_view_scoped_metrics_post.append( - ('Function/%s' % _test_api_view_view_name_post, 1)) +_test_api_view_scoped_metrics_post.append(("Function/%s" % _test_api_view_view_name_post, 1)) -@validate_transaction_errors( - errors=['rest_framework.exceptions:MethodNotAllowed']) -@validate_transaction_metrics(_test_api_view_view_name_post, - scoped_metrics=_test_api_view_scoped_metrics_post) +@validate_transaction_errors(errors=["rest_framework.exceptions:MethodNotAllowed"]) +@validate_transaction_metrics(_test_api_view_view_name_post, scoped_metrics=_test_api_view_scoped_metrics_post) def test_api_view_method_not_allowed(target_application): - target_application.post('/api_view/', status=405) + target_application.post("/api_view/", status=405) def test_application_view_agent_disabled(target_application): settings = global_settings() - @override_generic_settings(settings, {'enabled': False}) - @function_not_called('newrelic.core.stats_engine', - 'StatsEngine.record_transaction') + @override_generic_settings(settings, {"enabled": False}) + @function_not_called("newrelic.core.stats_engine", "StatsEngine.record_transaction") def _test(): - response = target_application.get('/view/') + response = target_application.get("/view/") assert response.status_int == 200 - response.mustcontain('restframework view response') + response.mustcontain("restframework view response") _test() diff --git a/tests/framework_django/test_application.py b/tests/framework_django/test_application.py index 1f2616b0fa..dce272d0cc 100644 --- a/tests/framework_django/test_application.py +++ b/tests/framework_django/test_application.py @@ -12,24 +12,33 @@ # See the License for the specific language governing permissions and # limitations under the License. -from testing_support.fixtures import ( - override_application_settings, - override_generic_settings, override_ignore_status_codes) -from testing_support.validators.validate_code_level_metrics import validate_code_level_metrics -from newrelic.hooks.framework_django import django_settings -from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics -from testing_support.validators.validate_transaction_errors import validate_transaction_errors - import os import django +from testing_support.fixtures import ( + override_application_settings, + override_generic_settings, + override_ignore_status_codes, +) +from testing_support.validators.validate_code_level_metrics import ( + validate_code_level_metrics, +) +from testing_support.validators.validate_transaction_errors import ( + validate_transaction_errors, +) +from testing_support.validators.validate_transaction_metrics import ( + validate_transaction_metrics, +) + +from newrelic.hooks.framework_django import django_settings -DJANGO_VERSION = tuple(map(int, django.get_version().split('.')[:2])) -DJANGO_SETTINGS_MODULE = os.environ.get('DJANGO_SETTINGS_MODULE', None) +DJANGO_VERSION = tuple(map(int, django.get_version().split(".")[:2])) +DJANGO_SETTINGS_MODULE = os.environ.get("DJANGO_SETTINGS_MODULE", None) def target_application(): from _target_application import _target_application + return _target_application @@ -37,272 +46,225 @@ def target_application(): # MIDDLEWARE defined in the version-specific Django settings.py file. _test_django_pre_1_10_middleware_scoped_metrics = [ - (('Function/django.middleware.common:' - 'CommonMiddleware.process_request'), 1), - (('Function/django.contrib.sessions.middleware:' - 'SessionMiddleware.process_request'), 1), - (('Function/django.contrib.auth.middleware:' - 'AuthenticationMiddleware.process_request'), 1), - (('Function/django.contrib.messages.middleware:' - 'MessageMiddleware.process_request'), 1), - (('Function/django.middleware.csrf:' - 'CsrfViewMiddleware.process_view'), 1), - (('Function/django.contrib.messages.middleware:' - 'MessageMiddleware.process_response'), 1), - (('Function/django.middleware.csrf:' - 'CsrfViewMiddleware.process_response'), 1), - (('Function/django.contrib.sessions.middleware:' - 'SessionMiddleware.process_response'), 1), - (('Function/django.middleware.common:' - 'CommonMiddleware.process_response'), 1), - (('Function/django.middleware.gzip:' - 'GZipMiddleware.process_response'), 1), - (('Function/newrelic.hooks.framework_django:' - 'browser_timing_insertion'), 1), + (("Function/django.middleware.common:" "CommonMiddleware.process_request"), None), + (("Function/django.contrib.sessions.middleware:" "SessionMiddleware.process_request"), 1), + (("Function/django.contrib.auth.middleware:" "AuthenticationMiddleware.process_request"), 1), + (("Function/django.contrib.messages.middleware:" "MessageMiddleware.process_request"), None), + (("Function/django.middleware.csrf:" "CsrfViewMiddleware.process_view"), None), + (("Function/django.contrib.messages.middleware:" "MessageMiddleware.process_response"), None), + (("Function/django.middleware.csrf:" "CsrfViewMiddleware.process_response"), None), + (("Function/django.contrib.sessions.middleware:" "SessionMiddleware.process_response"), 1), + (("Function/django.middleware.common:" "CommonMiddleware.process_response"), None), + (("Function/django.middleware.gzip:" "GZipMiddleware.process_response"), 1), + (("Function/newrelic.hooks.framework_django:" "browser_timing_insertion"), 1), ] _test_django_post_1_10_middleware_scoped_metrics = [ - ('Function/django.middleware.security:SecurityMiddleware', 1), - ('Function/django.contrib.sessions.middleware:SessionMiddleware', 1), - ('Function/django.middleware.common:CommonMiddleware', 1), - ('Function/django.middleware.csrf:CsrfViewMiddleware', 1), - ('Function/django.contrib.auth.middleware:AuthenticationMiddleware', 1), - ('Function/django.contrib.messages.middleware:MessageMiddleware', 1), - ('Function/django.middleware.clickjacking:XFrameOptionsMiddleware', 1), - ('Function/django.middleware.gzip:GZipMiddleware', 1), + ("Function/django.middleware.security:SecurityMiddleware", None), + ("Function/django.contrib.sessions.middleware:SessionMiddleware", 1), + ("Function/django.middleware.common:CommonMiddleware", None), + ("Function/django.middleware.csrf:CsrfViewMiddleware", None), + ("Function/django.contrib.auth.middleware:AuthenticationMiddleware", 1), + ("Function/django.contrib.messages.middleware:MessageMiddleware", None), + ("Function/django.middleware.clickjacking:XFrameOptionsMiddleware", None), + ("Function/django.middleware.gzip:GZipMiddleware", 1), ] _test_django_pre_1_10_url_resolver_scoped_metrics = [ - ('Function/django.core.urlresolvers:RegexURLResolver.resolve', 'present'), + ("Function/django.core.urlresolvers:RegexURLResolver.resolve", "present"), ] _test_django_post_1_10_url_resolver_scoped_metrics = [ - ('Function/django.urls.resolvers:RegexURLResolver.resolve', 'present'), + ("Function/django.urls.resolvers:RegexURLResolver.resolve", "present"), ] _test_django_post_2_0_url_resolver_scoped_metrics = [ - ('Function/django.urls.resolvers:URLResolver.resolve', 'present'), + ("Function/django.urls.resolvers:URLResolver.resolve", "present"), ] _test_application_index_scoped_metrics = [ - ('Function/django.core.handlers.wsgi:WSGIHandler.__call__', 1), - ('Python/WSGI/Application', 1), - ('Python/WSGI/Response', 1), - ('Python/WSGI/Finalize', 1), - ('Function/views:index', 1), + ("Function/django.core.handlers.wsgi:WSGIHandler.__call__", 1), + ("Python/WSGI/Application", 1), + ("Python/WSGI/Response", 1), + ("Python/WSGI/Finalize", 1), + ("Function/views:index", 1), ] if DJANGO_VERSION >= (1, 5): - _test_application_index_scoped_metrics.extend([ - ('Function/django.http.response:HttpResponse.close', 1)]) + _test_application_index_scoped_metrics.extend([("Function/django.http.response:HttpResponse.close", 1)]) if DJANGO_VERSION < (1, 10): - _test_application_index_scoped_metrics.extend( - _test_django_pre_1_10_url_resolver_scoped_metrics) + _test_application_index_scoped_metrics.extend(_test_django_pre_1_10_url_resolver_scoped_metrics) elif DJANGO_VERSION >= (2, 0): - _test_application_index_scoped_metrics.extend( - _test_django_post_2_0_url_resolver_scoped_metrics) + _test_application_index_scoped_metrics.extend(_test_django_post_2_0_url_resolver_scoped_metrics) else: - _test_application_index_scoped_metrics.extend( - _test_django_post_1_10_url_resolver_scoped_metrics) - -if DJANGO_SETTINGS_MODULE == 'settings_0110_old': - _test_application_index_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) -elif DJANGO_SETTINGS_MODULE == 'settings_0110_new': - _test_application_index_scoped_metrics.extend( - _test_django_post_1_10_middleware_scoped_metrics) + _test_application_index_scoped_metrics.extend(_test_django_post_1_10_url_resolver_scoped_metrics) + +if DJANGO_SETTINGS_MODULE == "settings_0110_old": + _test_application_index_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) +elif DJANGO_SETTINGS_MODULE == "settings_0110_new": + _test_application_index_scoped_metrics.extend(_test_django_post_1_10_middleware_scoped_metrics) elif DJANGO_VERSION < (1, 10): - _test_application_index_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) + _test_application_index_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('views:index', - scoped_metrics=_test_application_index_scoped_metrics) +@validate_transaction_metrics("views:index", scoped_metrics=_test_application_index_scoped_metrics) @validate_code_level_metrics("views", "index") def test_application_index(): test_application = target_application() - response = test_application.get('') - response.mustcontain('INDEX RESPONSE') + response = test_application.get("") + response.mustcontain("INDEX RESPONSE") -@validate_transaction_metrics('views:exception') +@validate_transaction_metrics("views:exception") @validate_code_level_metrics("views", "exception") def test_application_exception(): test_application = target_application() - test_application.get('/exception', status=500) + test_application.get("/exception", status=500) _test_application_not_found_scoped_metrics = [ - ('Function/django.core.handlers.wsgi:WSGIHandler.__call__', 1), - ('Python/WSGI/Application', 1), - ('Python/WSGI/Response', 1), - ('Python/WSGI/Finalize', 1), + ("Function/django.core.handlers.wsgi:WSGIHandler.__call__", 1), + ("Python/WSGI/Application", 1), + ("Python/WSGI/Response", 1), + ("Python/WSGI/Finalize", 1), ] if DJANGO_VERSION >= (1, 5): - _test_application_not_found_scoped_metrics.extend([ - ('Function/django.http.response:HttpResponseNotFound.close', 1)]) + _test_application_not_found_scoped_metrics.extend([("Function/django.http.response:HttpResponseNotFound.close", 1)]) if DJANGO_VERSION < (1, 10): - _test_application_not_found_scoped_metrics.extend( - _test_django_pre_1_10_url_resolver_scoped_metrics) + _test_application_not_found_scoped_metrics.extend(_test_django_pre_1_10_url_resolver_scoped_metrics) elif DJANGO_VERSION >= (2, 0): - _test_application_not_found_scoped_metrics.extend( - _test_django_post_2_0_url_resolver_scoped_metrics) + _test_application_not_found_scoped_metrics.extend(_test_django_post_2_0_url_resolver_scoped_metrics) else: - _test_application_not_found_scoped_metrics.extend( - _test_django_post_1_10_url_resolver_scoped_metrics) - -if DJANGO_SETTINGS_MODULE == 'settings_0110_old': - _test_application_not_found_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) - # The `CsrfViewMiddleware.process_view` isn't called for 404 Not Found. - _test_application_not_found_scoped_metrics.remove( - ('Function/django.middleware.csrf:CsrfViewMiddleware.process_view', 1)) -elif DJANGO_SETTINGS_MODULE == 'settings_0110_new': - _test_application_not_found_scoped_metrics.extend( - _test_django_post_1_10_middleware_scoped_metrics) + _test_application_not_found_scoped_metrics.extend(_test_django_post_1_10_url_resolver_scoped_metrics) + +if DJANGO_SETTINGS_MODULE == "settings_0110_old": + _test_application_not_found_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) +elif DJANGO_SETTINGS_MODULE == "settings_0110_new": + _test_application_not_found_scoped_metrics.extend(_test_django_post_1_10_middleware_scoped_metrics) elif DJANGO_VERSION < (1, 10): - _test_application_not_found_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) - # The `CsrfViewMiddleware.process_view` isn't called for 404 Not Found. - _test_application_not_found_scoped_metrics.remove( - ('Function/django.middleware.csrf:CsrfViewMiddleware.process_view', 1)) + _test_application_not_found_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('django.views.debug:technical_404_response', - scoped_metrics=_test_application_not_found_scoped_metrics) +@validate_transaction_metrics( + "django.views.debug:technical_404_response", scoped_metrics=_test_application_not_found_scoped_metrics +) def test_application_not_found(): test_application = target_application() - test_application.get('/not_found', status=404) + test_application.get("/not_found", status=404) @override_ignore_status_codes([403]) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('views:permission_denied') +@validate_transaction_metrics("views:permission_denied") @validate_code_level_metrics("views", "permission_denied") def test_ignored_status_code(): test_application = target_application() - test_application.get('/permission_denied', status=403) + test_application.get("/permission_denied", status=403) @override_ignore_status_codes([410]) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('views:middleware_410') +@validate_transaction_metrics("views:middleware_410") @validate_code_level_metrics("views", "middleware_410") def test_middleware_ignore_status_codes(): test_application = target_application() - test_application.get('/middleware_410', status=410) + test_application.get("/middleware_410", status=410) _test_application_cbv_scoped_metrics = [ - ('Function/django.core.handlers.wsgi:WSGIHandler.__call__', 1), - ('Python/WSGI/Application', 1), - ('Python/WSGI/Response', 1), - ('Python/WSGI/Finalize', 1), - ('Function/views:MyView', 1), - ('Function/views:MyView.get', 1), + ("Function/django.core.handlers.wsgi:WSGIHandler.__call__", 1), + ("Python/WSGI/Application", 1), + ("Python/WSGI/Response", 1), + ("Python/WSGI/Finalize", 1), + ("Function/views:MyView", 1), + ("Function/views:MyView.get", 1), ] if DJANGO_VERSION >= (1, 5): - _test_application_cbv_scoped_metrics.extend([ - ('Function/django.http.response:HttpResponse.close', 1)]) + _test_application_cbv_scoped_metrics.extend([("Function/django.http.response:HttpResponse.close", 1)]) if DJANGO_VERSION < (1, 10): - _test_application_cbv_scoped_metrics.extend( - _test_django_pre_1_10_url_resolver_scoped_metrics) + _test_application_cbv_scoped_metrics.extend(_test_django_pre_1_10_url_resolver_scoped_metrics) elif DJANGO_VERSION >= (2, 0): - _test_application_cbv_scoped_metrics.extend( - _test_django_post_2_0_url_resolver_scoped_metrics) + _test_application_cbv_scoped_metrics.extend(_test_django_post_2_0_url_resolver_scoped_metrics) else: - _test_application_cbv_scoped_metrics.extend( - _test_django_post_1_10_url_resolver_scoped_metrics) - -if DJANGO_SETTINGS_MODULE == 'settings_0110_old': - _test_application_cbv_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) -elif DJANGO_SETTINGS_MODULE == 'settings_0110_new': - _test_application_cbv_scoped_metrics.extend( - _test_django_post_1_10_middleware_scoped_metrics) + _test_application_cbv_scoped_metrics.extend(_test_django_post_1_10_url_resolver_scoped_metrics) + +if DJANGO_SETTINGS_MODULE == "settings_0110_old": + _test_application_cbv_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) +elif DJANGO_SETTINGS_MODULE == "settings_0110_new": + _test_application_cbv_scoped_metrics.extend(_test_django_post_1_10_middleware_scoped_metrics) elif DJANGO_VERSION < (1, 10): - _test_application_cbv_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) + _test_application_cbv_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('views:MyView.get', - scoped_metrics=_test_application_cbv_scoped_metrics) +@validate_transaction_metrics("views:MyView.get", scoped_metrics=_test_application_cbv_scoped_metrics) @validate_code_level_metrics("views.MyView", "get") def test_application_cbv(): test_application = target_application() - response = test_application.get('/cbv') - response.mustcontain('CBV RESPONSE') + response = test_application.get("/cbv") + response.mustcontain("CBV RESPONSE") _test_application_deferred_cbv_scoped_metrics = [ - ('Function/django.core.handlers.wsgi:WSGIHandler.__call__', 1), - ('Python/WSGI/Application', 1), - ('Python/WSGI/Response', 1), - ('Python/WSGI/Finalize', 1), - ('Function/views:deferred_cbv', 1), - ('Function/views:MyView.get', 1), + ("Function/django.core.handlers.wsgi:WSGIHandler.__call__", 1), + ("Python/WSGI/Application", 1), + ("Python/WSGI/Response", 1), + ("Python/WSGI/Finalize", 1), + ("Function/views:deferred_cbv", 1), + ("Function/views:MyView.get", 1), ] if DJANGO_VERSION >= (1, 5): - _test_application_deferred_cbv_scoped_metrics.extend([ - ('Function/django.http.response:HttpResponse.close', 1)]) + _test_application_deferred_cbv_scoped_metrics.extend([("Function/django.http.response:HttpResponse.close", 1)]) if DJANGO_VERSION < (1, 10): - _test_application_deferred_cbv_scoped_metrics.extend( - _test_django_pre_1_10_url_resolver_scoped_metrics) + _test_application_deferred_cbv_scoped_metrics.extend(_test_django_pre_1_10_url_resolver_scoped_metrics) elif DJANGO_VERSION >= (2, 0): - _test_application_deferred_cbv_scoped_metrics.extend( - _test_django_post_2_0_url_resolver_scoped_metrics) + _test_application_deferred_cbv_scoped_metrics.extend(_test_django_post_2_0_url_resolver_scoped_metrics) else: - _test_application_deferred_cbv_scoped_metrics.extend( - _test_django_post_1_10_url_resolver_scoped_metrics) - -if DJANGO_SETTINGS_MODULE == 'settings_0110_old': - _test_application_deferred_cbv_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) -elif DJANGO_SETTINGS_MODULE == 'settings_0110_new': - _test_application_deferred_cbv_scoped_metrics.extend( - _test_django_post_1_10_middleware_scoped_metrics) + _test_application_deferred_cbv_scoped_metrics.extend(_test_django_post_1_10_url_resolver_scoped_metrics) + +if DJANGO_SETTINGS_MODULE == "settings_0110_old": + _test_application_deferred_cbv_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) +elif DJANGO_SETTINGS_MODULE == "settings_0110_new": + _test_application_deferred_cbv_scoped_metrics.extend(_test_django_post_1_10_middleware_scoped_metrics) elif DJANGO_VERSION < (1, 10): - _test_application_deferred_cbv_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) + _test_application_deferred_cbv_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('views:deferred_cbv', - scoped_metrics=_test_application_deferred_cbv_scoped_metrics) +@validate_transaction_metrics("views:deferred_cbv", scoped_metrics=_test_application_deferred_cbv_scoped_metrics) @validate_code_level_metrics("views", "deferred_cbv") def test_application_deferred_cbv(): test_application = target_application() - response = test_application.get('/deferred_cbv') - response.mustcontain('CBV RESPONSE') + response = test_application.get("/deferred_cbv") + response.mustcontain("CBV RESPONSE") _test_html_insertion_settings = { - 'browser_monitoring.enabled': True, - 'browser_monitoring.auto_instrument': True, - 'js_agent_loader': u'', + "browser_monitoring.enabled": True, + "browser_monitoring.auto_instrument": True, + "js_agent_loader": "", } @override_application_settings(_test_html_insertion_settings) def test_html_insertion_django_middleware(): test_application = target_application() - response = test_application.get('/html_insertion', status=200) + response = test_application.get("/html_insertion", status=200) # The 'NREUM HEADER' value comes from our override for the header. # The 'NREUM.info' value comes from the programmatically generated # footer added by the agent. - response.mustcontain('NREUM HEADER', 'NREUM.info') + response.mustcontain("NREUM HEADER", "NREUM.info") @override_application_settings(_test_html_insertion_settings) @@ -311,9 +273,8 @@ def test_html_insertion_django_gzip_middleware_enabled(): # GZipMiddleware only fires if given the following header. - gzip_header = {'Accept-Encoding': 'gzip'} - response = test_application.get('/gzip_html_insertion', status=200, - headers=gzip_header) + gzip_header = {"Accept-Encoding": "gzip"} + response = test_application.get("/gzip_html_insertion", status=200, headers=gzip_header) # The 'NREUM HEADER' value comes from our override for the header. # The 'NREUM.info' value comes from the programmatically generated @@ -321,13 +282,13 @@ def test_html_insertion_django_gzip_middleware_enabled(): # The response.text will already be gunzipped - response.mustcontain('NREUM HEADER', 'NREUM.info') + response.mustcontain("NREUM HEADER", "NREUM.info") _test_html_insertion_settings_disabled = { - 'browser_monitoring.enabled': False, - 'browser_monitoring.auto_instrument': False, - 'js_agent_loader': u'', + "browser_monitoring.enabled": False, + "browser_monitoring.auto_instrument": False, + "js_agent_loader": "", } @@ -337,9 +298,8 @@ def test_html_insertion_django_gzip_middleware_disabled(): # GZipMiddleware only fires if given the following header. - gzip_header = {'Accept-Encoding': 'gzip'} - response = test_application.get('/gzip_html_insertion', status=200, - headers=gzip_header) + gzip_header = {"Accept-Encoding": "gzip"} + response = test_application.get("/gzip_html_insertion", status=200, headers=gzip_header) # The 'NREUM HEADER' value comes from our override for the header. # The 'NREUM.info' value comes from the programmatically generated @@ -347,254 +307,229 @@ def test_html_insertion_django_gzip_middleware_disabled(): # The response.text will already be gunzipped - response.mustcontain(no=['NREUM HEADER', 'NREUM.info']) + response.mustcontain(no=["NREUM HEADER", "NREUM.info"]) _test_html_insertion_manual_settings = { - 'browser_monitoring.enabled': True, - 'browser_monitoring.auto_instrument': True, - 'js_agent_loader': u'', + "browser_monitoring.enabled": True, + "browser_monitoring.auto_instrument": True, + "js_agent_loader": "", } @override_application_settings(_test_html_insertion_manual_settings) def test_html_insertion_manual_django_middleware(): test_application = target_application() - response = test_application.get('/html_insertion_manual', status=200) + response = test_application.get("/html_insertion_manual", status=200) # The 'NREUM HEADER' value comes from our override for the header. # The 'NREUM.info' value comes from the programmatically generated # footer added by the agent. - response.mustcontain(no=['NREUM HEADER', 'NREUM.info']) + response.mustcontain(no=["NREUM HEADER", "NREUM.info"]) @override_application_settings(_test_html_insertion_settings) def test_html_insertion_unnamed_attachment_header_django_middleware(): test_application = target_application() - response = test_application.get( - '/html_insertion_unnamed_attachment_header', status=200) + response = test_application.get("/html_insertion_unnamed_attachment_header", status=200) # The 'NREUM HEADER' value comes from our override for the header. # The 'NREUM.info' value comes from the programmatically generated # footer added by the agent. - response.mustcontain(no=['NREUM HEADER', 'NREUM.info']) + response.mustcontain(no=["NREUM HEADER", "NREUM.info"]) @override_application_settings(_test_html_insertion_settings) def test_html_insertion_named_attachment_header_django_middleware(): test_application = target_application() - response = test_application.get( - '/html_insertion_named_attachment_header', status=200) + response = test_application.get("/html_insertion_named_attachment_header", status=200) # The 'NREUM HEADER' value comes from our override for the header. # The 'NREUM.info' value comes from the programmatically generated # footer added by the agent. - response.mustcontain(no=['NREUM HEADER', 'NREUM.info']) + response.mustcontain(no=["NREUM HEADER", "NREUM.info"]) _test_html_insertion_settings = { - 'browser_monitoring.enabled': True, - 'browser_monitoring.auto_instrument': False, - 'js_agent_loader': u'', + "browser_monitoring.enabled": True, + "browser_monitoring.auto_instrument": False, + "js_agent_loader": "", } @override_application_settings(_test_html_insertion_settings) def test_html_insertion_manual_tag_instrumentation(): test_application = target_application() - response = test_application.get('/template_tags') + response = test_application.get("/template_tags") # Assert that the instrumentation is not inappropriately escaped - response.mustcontain('', - no=['<!-- NREUM HEADER -->']) + response.mustcontain("", no=["<!-- NREUM HEADER -->"]) _test_application_inclusion_tag_scoped_metrics = [ - ('Function/django.core.handlers.wsgi:WSGIHandler.__call__', 1), - ('Python/WSGI/Application', 1), - ('Python/WSGI/Response', 1), - ('Python/WSGI/Finalize', 1), - ('Function/views:inclusion_tag', 1), - ('Template/Render/main.html', 1), + ("Function/django.core.handlers.wsgi:WSGIHandler.__call__", 1), + ("Python/WSGI/Application", 1), + ("Python/WSGI/Response", 1), + ("Python/WSGI/Finalize", 1), + ("Function/views:inclusion_tag", 1), + ("Template/Render/main.html", 1), ] if DJANGO_VERSION < (1, 9): - _test_application_inclusion_tag_scoped_metrics.extend([ - ('Template/Include/results.html', 1)]) + _test_application_inclusion_tag_scoped_metrics.extend([("Template/Include/results.html", 1)]) if DJANGO_VERSION < (1, 10): - _test_application_inclusion_tag_scoped_metrics.extend( - _test_django_pre_1_10_url_resolver_scoped_metrics) + _test_application_inclusion_tag_scoped_metrics.extend(_test_django_pre_1_10_url_resolver_scoped_metrics) elif DJANGO_VERSION >= (2, 0): - _test_application_inclusion_tag_scoped_metrics.extend( - _test_django_post_2_0_url_resolver_scoped_metrics) + _test_application_inclusion_tag_scoped_metrics.extend(_test_django_post_2_0_url_resolver_scoped_metrics) else: - _test_application_inclusion_tag_scoped_metrics.extend( - _test_django_post_1_10_url_resolver_scoped_metrics) - -if DJANGO_SETTINGS_MODULE == 'settings_0110_old': - _test_application_inclusion_tag_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) -elif DJANGO_SETTINGS_MODULE == 'settings_0110_new': - _test_application_inclusion_tag_scoped_metrics.extend( - _test_django_post_1_10_middleware_scoped_metrics) + _test_application_inclusion_tag_scoped_metrics.extend(_test_django_post_1_10_url_resolver_scoped_metrics) + +if DJANGO_SETTINGS_MODULE == "settings_0110_old": + _test_application_inclusion_tag_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) +elif DJANGO_SETTINGS_MODULE == "settings_0110_new": + _test_application_inclusion_tag_scoped_metrics.extend(_test_django_post_1_10_middleware_scoped_metrics) elif DJANGO_VERSION < (1, 10): - _test_application_inclusion_tag_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) + _test_application_inclusion_tag_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) try: _test_application_inclusion_tag_scoped_metrics.remove( - (('Function/newrelic.hooks.framework_django:' - 'browser_timing_insertion'), 1) + (("Function/newrelic.hooks.framework_django:" "browser_timing_insertion"), 1) ) except ValueError: pass @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('views:inclusion_tag', - scoped_metrics=_test_application_inclusion_tag_scoped_metrics) +@validate_transaction_metrics("views:inclusion_tag", scoped_metrics=_test_application_inclusion_tag_scoped_metrics) @validate_code_level_metrics("views", "inclusion_tag") def test_application_inclusion_tag(): test_application = target_application() - response = test_application.get('/inclusion_tag') - response.mustcontain('Inclusion tag') + response = test_application.get("/inclusion_tag") + response.mustcontain("Inclusion tag") _test_inclusion_tag_template_tags_scoped_metrics = [ - ('Function/django.core.handlers.wsgi:WSGIHandler.__call__', 1), - ('Python/WSGI/Application', 1), - ('Python/WSGI/Response', 1), - ('Python/WSGI/Finalize', 1), - ('Function/views:inclusion_tag', 1), - ('Template/Render/main.html', 1), + ("Function/django.core.handlers.wsgi:WSGIHandler.__call__", 1), + ("Python/WSGI/Application", 1), + ("Python/WSGI/Response", 1), + ("Python/WSGI/Finalize", 1), + ("Function/views:inclusion_tag", 1), + ("Template/Render/main.html", 1), ] if DJANGO_VERSION < (1, 9): - _test_inclusion_tag_template_tags_scoped_metrics.extend([ - ('Template/Include/results.html', 1), - ('Template/Tag/show_results', 1)]) + _test_inclusion_tag_template_tags_scoped_metrics.extend( + [("Template/Include/results.html", 1), ("Template/Tag/show_results", 1)] + ) -_test_inclusion_tag_settings = { - 'instrumentation.templates.inclusion_tag': '*' -} +_test_inclusion_tag_settings = {"instrumentation.templates.inclusion_tag": "*"} if DJANGO_VERSION < (1, 10): - _test_inclusion_tag_template_tags_scoped_metrics.extend( - _test_django_pre_1_10_url_resolver_scoped_metrics) + _test_inclusion_tag_template_tags_scoped_metrics.extend(_test_django_pre_1_10_url_resolver_scoped_metrics) elif DJANGO_VERSION >= (2, 0): - _test_inclusion_tag_template_tags_scoped_metrics.extend( - _test_django_post_2_0_url_resolver_scoped_metrics) + _test_inclusion_tag_template_tags_scoped_metrics.extend(_test_django_post_2_0_url_resolver_scoped_metrics) else: - _test_inclusion_tag_template_tags_scoped_metrics.extend( - _test_django_post_1_10_url_resolver_scoped_metrics) + _test_inclusion_tag_template_tags_scoped_metrics.extend(_test_django_post_1_10_url_resolver_scoped_metrics) -if DJANGO_SETTINGS_MODULE == 'settings_0110_old': - _test_inclusion_tag_template_tags_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) -elif DJANGO_SETTINGS_MODULE == 'settings_0110_new': - _test_inclusion_tag_template_tags_scoped_metrics.extend( - _test_django_post_1_10_middleware_scoped_metrics) +if DJANGO_SETTINGS_MODULE == "settings_0110_old": + _test_inclusion_tag_template_tags_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) +elif DJANGO_SETTINGS_MODULE == "settings_0110_new": + _test_inclusion_tag_template_tags_scoped_metrics.extend(_test_django_post_1_10_middleware_scoped_metrics) elif DJANGO_VERSION < (1, 10): - _test_inclusion_tag_template_tags_scoped_metrics.extend( - _test_django_pre_1_10_middleware_scoped_metrics) + _test_inclusion_tag_template_tags_scoped_metrics.extend(_test_django_pre_1_10_middleware_scoped_metrics) try: _test_inclusion_tag_template_tags_scoped_metrics.remove( - (('Function/newrelic.hooks.framework_django:' - 'browser_timing_insertion'), 1) + (("Function/newrelic.hooks.framework_django:" "browser_timing_insertion"), 1) ) except ValueError: pass @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('views:inclusion_tag', - scoped_metrics=_test_inclusion_tag_template_tags_scoped_metrics) +@validate_transaction_metrics("views:inclusion_tag", scoped_metrics=_test_inclusion_tag_template_tags_scoped_metrics) @override_generic_settings(django_settings, _test_inclusion_tag_settings) @validate_code_level_metrics("views", "inclusion_tag") def test_inclusion_tag_template_tag_metric(): test_application = target_application() - response = test_application.get('/inclusion_tag') - response.mustcontain('Inclusion tag') + response = test_application.get("/inclusion_tag") + response.mustcontain("Inclusion tag") _test_template_render_exception_scoped_metrics_base = [ - ('Function/django.core.handlers.wsgi:WSGIHandler.__call__', 1), - ('Python/WSGI/Application', 1), - ('Python/WSGI/Response', 1), - ('Python/WSGI/Finalize', 1), + ("Function/django.core.handlers.wsgi:WSGIHandler.__call__", 1), + ("Python/WSGI/Application", 1), + ("Python/WSGI/Response", 1), + ("Python/WSGI/Finalize", 1), ] if DJANGO_VERSION < (1, 5): _test_template_render_exception_scoped_metrics_base.append( - ('Function/django.http:HttpResponseServerError.close', 1)) + ("Function/django.http:HttpResponseServerError.close", 1) + ) elif DJANGO_VERSION < (1, 8): _test_template_render_exception_scoped_metrics_base.append( - ('Function/django.http.response:HttpResponseServerError.close', 1)) + ("Function/django.http.response:HttpResponseServerError.close", 1) + ) else: - _test_template_render_exception_scoped_metrics_base.append( - ('Function/django.http.response:HttpResponse.close', 1)) + _test_template_render_exception_scoped_metrics_base.append(("Function/django.http.response:HttpResponse.close", 1)) if DJANGO_VERSION < (1, 10): - _test_template_render_exception_scoped_metrics_base.extend( - _test_django_pre_1_10_url_resolver_scoped_metrics) + _test_template_render_exception_scoped_metrics_base.extend(_test_django_pre_1_10_url_resolver_scoped_metrics) elif DJANGO_VERSION >= (2, 0): - _test_template_render_exception_scoped_metrics_base.extend( - _test_django_post_2_0_url_resolver_scoped_metrics) + _test_template_render_exception_scoped_metrics_base.extend(_test_django_post_2_0_url_resolver_scoped_metrics) else: - _test_template_render_exception_scoped_metrics_base.extend( - _test_django_post_1_10_url_resolver_scoped_metrics) - -if DJANGO_SETTINGS_MODULE == 'settings_0110_old': - _test_template_render_exception_scoped_metrics_base.extend( - _test_django_pre_1_10_middleware_scoped_metrics) -elif DJANGO_SETTINGS_MODULE == 'settings_0110_new': - _test_template_render_exception_scoped_metrics_base.extend( - _test_django_post_1_10_middleware_scoped_metrics) + _test_template_render_exception_scoped_metrics_base.extend(_test_django_post_1_10_url_resolver_scoped_metrics) + +if DJANGO_SETTINGS_MODULE == "settings_0110_old": + _test_template_render_exception_scoped_metrics_base.extend(_test_django_pre_1_10_middleware_scoped_metrics) +elif DJANGO_SETTINGS_MODULE == "settings_0110_new": + _test_template_render_exception_scoped_metrics_base.extend(_test_django_post_1_10_middleware_scoped_metrics) elif DJANGO_VERSION < (1, 10): - _test_template_render_exception_scoped_metrics_base.extend( - _test_django_pre_1_10_middleware_scoped_metrics) + _test_template_render_exception_scoped_metrics_base.extend(_test_django_pre_1_10_middleware_scoped_metrics) if DJANGO_VERSION < (1, 9): - _test_template_render_exception_errors = [ - 'django.template.base:TemplateSyntaxError'] + _test_template_render_exception_errors = ["django.template.base:TemplateSyntaxError"] else: - _test_template_render_exception_errors = [ - 'django.template.exceptions:TemplateSyntaxError'] + _test_template_render_exception_errors = ["django.template.exceptions:TemplateSyntaxError"] -_test_template_render_exception_function_scoped_metrics = list( - _test_template_render_exception_scoped_metrics_base) -_test_template_render_exception_function_scoped_metrics.extend([ - ('Function/views:render_exception_function', 1), -]) +_test_template_render_exception_function_scoped_metrics = list(_test_template_render_exception_scoped_metrics_base) +_test_template_render_exception_function_scoped_metrics.extend( + [ + ("Function/views:render_exception_function", 1), + ] +) @validate_transaction_errors(errors=_test_template_render_exception_errors) -@validate_transaction_metrics('views:render_exception_function', - scoped_metrics=_test_template_render_exception_function_scoped_metrics) +@validate_transaction_metrics( + "views:render_exception_function", scoped_metrics=_test_template_render_exception_function_scoped_metrics +) @validate_code_level_metrics("views", "render_exception_function") def test_template_render_exception_function(): test_application = target_application() - test_application.get('/render_exception_function', status=500) + test_application.get("/render_exception_function", status=500) -_test_template_render_exception_class_scoped_metrics = list( - _test_template_render_exception_scoped_metrics_base) -_test_template_render_exception_class_scoped_metrics.extend([ - ('Function/views:RenderExceptionClass', 1), - ('Function/views:RenderExceptionClass.get', 1), -]) +_test_template_render_exception_class_scoped_metrics = list(_test_template_render_exception_scoped_metrics_base) +_test_template_render_exception_class_scoped_metrics.extend( + [ + ("Function/views:RenderExceptionClass", 1), + ("Function/views:RenderExceptionClass.get", 1), + ] +) @validate_transaction_errors(errors=_test_template_render_exception_errors) -@validate_transaction_metrics('views:RenderExceptionClass.get', - scoped_metrics=_test_template_render_exception_class_scoped_metrics) +@validate_transaction_metrics( + "views:RenderExceptionClass.get", scoped_metrics=_test_template_render_exception_class_scoped_metrics +) @validate_code_level_metrics("views.RenderExceptionClass", "get") def test_template_render_exception_class(): test_application = target_application() - test_application.get('/render_exception_class', status=500) + test_application.get("/render_exception_class", status=500) diff --git a/tests/framework_django/test_asgi_application.py b/tests/framework_django/test_asgi_application.py index 4570427662..a0cebaa012 100644 --- a/tests/framework_django/test_asgi_application.py +++ b/tests/framework_django/test_asgi_application.py @@ -13,39 +13,48 @@ # limitations under the License. import os -import pytest -import django -from newrelic.core.config import global_settings -from newrelic.common.encoding_utils import gzip_decompress +import django +import pytest from testing_support.fixtures import ( override_application_settings, - override_generic_settings, override_ignore_status_codes) -from testing_support.validators.validate_code_level_metrics import validate_code_level_metrics -from testing_support.validators.validate_transaction_metrics import validate_transaction_metrics -from testing_support.validators.validate_transaction_errors import validate_transaction_errors + override_generic_settings, + override_ignore_status_codes, +) +from testing_support.validators.validate_code_level_metrics import ( + validate_code_level_metrics, +) +from testing_support.validators.validate_transaction_errors import ( + validate_transaction_errors, +) +from testing_support.validators.validate_transaction_metrics import ( + validate_transaction_metrics, +) -DJANGO_VERSION = tuple(map(int, django.get_version().split('.')[:2])) +from newrelic.common.encoding_utils import gzip_decompress +from newrelic.core.config import global_settings + +DJANGO_VERSION = tuple(map(int, django.get_version().split(".")[:2])) if DJANGO_VERSION[0] < 3: pytest.skip("support for asgi added in django 3", allow_module_level=True) -from testing_support.asgi_testing import AsgiTest - +# Import this here so it is not run if Django is less than 3.0. +from testing_support.asgi_testing import AsgiTest # noqa: E402 scoped_metrics = [ - ('Function/django.contrib.sessions.middleware:SessionMiddleware', 1), - ('Function/django.middleware.common:CommonMiddleware', 1), - ('Function/django.middleware.csrf:CsrfViewMiddleware', 1), - ('Function/django.contrib.auth.middleware:AuthenticationMiddleware', 1), - ('Function/django.contrib.messages.middleware:MessageMiddleware', 1), - ('Function/django.middleware.gzip:GZipMiddleware', 1), - ('Function/middleware:ExceptionTo410Middleware', 1), - ('Function/django.urls.resolvers:URLResolver.resolve', 'present'), + ("Function/django.contrib.sessions.middleware:SessionMiddleware", 1), + ("Function/django.middleware.common:CommonMiddleware", None), + ("Function/django.middleware.csrf:CsrfViewMiddleware", None), + ("Function/django.contrib.auth.middleware:AuthenticationMiddleware", 1), + ("Function/django.contrib.messages.middleware:MessageMiddleware", None), + ("Function/django.middleware.gzip:GZipMiddleware", 1), + ("Function/middleware:ExceptionTo410Middleware", 1), + ("Function/django.urls.resolvers:URLResolver.resolve", "present"), ] rollup_metrics = scoped_metrics + [ - ('Python/Framework/Django/%s' % django.get_version(), 1), + ("Python/Framework/Django/%s" % django.get_version(), 1), ] @@ -57,58 +66,65 @@ def application(): return AsgiTest(get_asgi_application()) -@validate_transaction_metrics('views:index', - scoped_metrics=[('Function/views:index', 1)] + scoped_metrics, - rollup_metrics=rollup_metrics) +@validate_transaction_metrics( + "views:index", scoped_metrics=[("Function/views:index", 1)] + scoped_metrics, rollup_metrics=rollup_metrics +) @validate_code_level_metrics("views", "index") def test_asgi_index(application): - response = application.get('/') + response = application.get("/") assert response.status == 200 -@validate_transaction_metrics('views:exception', - scoped_metrics=[('Function/views:exception', 1)] + scoped_metrics, - rollup_metrics=rollup_metrics) +@validate_transaction_metrics( + "views:exception", scoped_metrics=[("Function/views:exception", 1)] + scoped_metrics, rollup_metrics=rollup_metrics +) @validate_code_level_metrics("views", "exception") def test_asgi_exception(application): - response = application.get('/exception') + response = application.get("/exception") assert response.status == 500 @override_ignore_status_codes([410]) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('views:middleware_410', - scoped_metrics=[('Function/views:middleware_410', 1)] + scoped_metrics, - rollup_metrics=rollup_metrics) +@validate_transaction_metrics( + "views:middleware_410", + scoped_metrics=[("Function/views:middleware_410", 1)] + scoped_metrics, + rollup_metrics=rollup_metrics, +) @validate_code_level_metrics("views", "middleware_410") def test_asgi_middleware_ignore_status_codes(application): - response = application.get('/middleware_410') + response = application.get("/middleware_410") assert response.status == 410 @override_ignore_status_codes([403]) @validate_transaction_errors(errors=[]) -@validate_transaction_metrics('views:permission_denied', - scoped_metrics=[('Function/views:permission_denied', 1)] + scoped_metrics, - rollup_metrics=rollup_metrics) +@validate_transaction_metrics( + "views:permission_denied", + scoped_metrics=[("Function/views:permission_denied", 1)] + scoped_metrics, + rollup_metrics=rollup_metrics, +) @validate_code_level_metrics("views", "permission_denied") def test_asgi_ignored_status_code(application): - response = application.get('/permission_denied') + response = application.get("/permission_denied") assert response.status == 403 -@pytest.mark.parametrize('url,view_name', ( - ('/cbv', 'views:MyView.get'), - ('/deferred_cbv', 'views:deferred_cbv'), -)) +@pytest.mark.parametrize( + "url,view_name", + ( + ("/cbv", "views:MyView.get"), + ("/deferred_cbv", "views:deferred_cbv"), + ), +) def test_asgi_class_based_view(application, url, view_name): - func = 'get' if url == '/cbv' else 'deferred_cbv' - namespace = 'views.MyView' if func == 'get' else 'views' - + func = "get" if url == "/cbv" else "deferred_cbv" + namespace = "views.MyView" if func == "get" else "views" + @validate_transaction_errors(errors=[]) - @validate_transaction_metrics(view_name, - scoped_metrics=[('Function/' + view_name, 1)] + scoped_metrics, - rollup_metrics=rollup_metrics) + @validate_transaction_metrics( + view_name, scoped_metrics=[("Function/" + view_name, 1)] + scoped_metrics, rollup_metrics=rollup_metrics + ) @validate_code_level_metrics(namespace, func) def _test(): response = application.get(url) @@ -117,66 +133,80 @@ def _test(): _test() -@pytest.mark.parametrize('url', ( - '/html_insertion', - '/html_insertion_content_length', - '/template_tags', - '/gzip_html_insertion', -)) -@override_application_settings({ - 'browser_monitoring.enabled': True, - 'browser_monitoring.auto_instrument': True, - 'js_agent_loader': u'', -}) +@pytest.mark.parametrize( + "url", + ( + "/html_insertion", + "/html_insertion_content_length", + "/template_tags", + "/gzip_html_insertion", + ), +) +@override_application_settings( + { + "browser_monitoring.enabled": True, + "browser_monitoring.auto_instrument": True, + "js_agent_loader": "", + } +) def test_asgi_html_insertion_success(application, url): - if 'gzip' in url: - headers = {'Accept-Encoding': 'gzip'} + if "gzip" in url: + headers = {"Accept-Encoding": "gzip"} else: headers = None response = application.get(url, headers=headers) assert response.status == 200 - if 'gzip' in url: - body = gzip_decompress(response.body).encode('utf-8') + if "gzip" in url: + body = gzip_decompress(response.body).encode("utf-8") else: body = response.body - assert b'NREUM HEADER' in body - assert b'NREUM.info' in body - assert b'<!-- NREUM HEADER -->' not in body - - -@pytest.mark.parametrize('url', ( - '/html_insertion_manual', - '/html_insertion_unnamed_attachment_header', - '/html_insertion_named_attachment_header', -)) -@override_application_settings({ - 'browser_monitoring.enabled': True, - 'browser_monitoring.auto_instrument': True, - 'js_agent_loader': u'', -}) + assert b"NREUM HEADER" in body + assert b"NREUM.info" in body + assert b"<!-- NREUM HEADER -->" not in body + + +@pytest.mark.parametrize( + "url", + ( + "/html_insertion_manual", + "/html_insertion_unnamed_attachment_header", + "/html_insertion_named_attachment_header", + ), +) +@override_application_settings( + { + "browser_monitoring.enabled": True, + "browser_monitoring.auto_instrument": True, + "js_agent_loader": "", + } +) def test_asgi_html_insertion_failed(application, url): response = application.get(url) assert response.status == 200 - assert b'NREUM HEADER' not in response.body - assert b'NREUM.info' not in response.body - - -@validate_transaction_metrics('views:template_tags', - scoped_metrics=[ - ('Function/views:template_tags', 1), - ('Template/Render/main.html', 1), - ('Template/Render/results.html', 1)] + scoped_metrics, - rollup_metrics=rollup_metrics) -@validate_code_level_metrics('views', 'template_tags') + assert b"NREUM HEADER" not in response.body + assert b"NREUM.info" not in response.body + + +@validate_transaction_metrics( + "views:template_tags", + scoped_metrics=[ + ("Function/views:template_tags", 1), + ("Template/Render/main.html", 1), + ("Template/Render/results.html", 1), + ] + + scoped_metrics, + rollup_metrics=rollup_metrics, +) +@validate_code_level_metrics("views", "template_tags") def test_asgi_template_render(application): - response = application.get('/template_tags') + response = application.get("/template_tags") assert response.status == 200 -@override_generic_settings(global_settings(), {'enabled': False}) +@override_generic_settings(global_settings(), {"enabled": False}) def test_asgi_nr_disabled(application): - response = application.get('/') + response = application.get("/") assert response.status == 200