def get_response(request): # Up-call to Django's get_response() in a transaction. This # transaction may fail because of a retryable conflict, so # pass errors to handle_uncaught_exception(). try: with post_commit_hooks: with transaction.atomic(): response = django_get_response(request) if response.status_code == 500: raise InternalErrorResponse(response) return response except SystemExit: # Allow sys.exit() to actually exit, reproducing behaviour # found in Django's BaseHandler. raise except InternalErrorResponse as exc: # Response is good, but the transaction needed to be rolled # back because the response was a 500 error. return exc.response except: # Catch *everything* else, also reproducing behaviour found in # Django's BaseHandler. In practice, we should only really see # transaction failures here from the outermost atomic block as # all other exceptions are handled by django_get_response. The # setting DEBUG_PROPAGATE_EXCEPTIONS upsets this, so be on # your guard when tempted to use it. signals.got_request_exception.send(sender=self.__class__, request=request) return self.handle_uncaught_exception(request, get_resolver(None), sys.exc_info(), reraise=False)
def test__handle_uncaught_exception_logs_other_failure(self): handler = views.WebApplicationHandler() request = make_request() request.path = factory.make_name("path") # Capture an exc_info tuple with traceback. exc_type = factory.make_exception_type() exc_msg = factory.make_name("message") try: raise exc_type(exc_msg) except exc_type: exc_info = sys.exc_info() with FakeLogger(views.__name__, logging.ERROR) as logger: handler.handle_uncaught_exception(request=request, resolver=get_resolver(None), exc_info=exc_info) self.assertThat( logger.output, DocTestMatches("""\ 500 Internal Server Error @ %s Traceback (most recent call last): ... maastesting.factory.TestException#...: %s """ % (request.path, exc_msg)))
def test__handle_uncaught_exception_notes_serialization_failure(self): handler = views.WebApplicationHandler() request = make_request() request.path = factory.make_name("path") failure = self.capture_serialization_failure() response = handler.handle_uncaught_exception( request=request, resolver=get_resolver(None), exc_info=failure) # HTTP 500 is returned... self.expectThat(response.status_code, Equals(http.client.INTERNAL_SERVER_ERROR)) # ... but the response is recorded as needing a retry. self.expectThat(handler._WebApplicationHandler__retry, Contains(response))
def test__handle_uncaught_exception_raises_error_on_api_exception(self): handler = views.WebApplicationHandler() request = make_request() request.path = factory.make_name("path") # Capture an exc_info tuple with traceback. exc_type = MAASAPIException exc_msg = factory.make_name("message") try: raise exc_type(exc_msg) except exc_type: exc_info = sys.exc_info() response = handler.handle_uncaught_exception( request=request, resolver=get_resolver(None), exc_info=exc_info) self.assertThat(response.status_code, Equals(http.client.INTERNAL_SERVER_ERROR))
def get_resource_uri_template(self): """ URI template processor. See http://bitworking.org/projects/URI-Templates/ """ def _convert(template, params=[]): """URI template converter""" paths = template % dict([p, "{%s}" % p] for p in params) return '%s%s' % (get_script_prefix(), paths) try: resource_uri = self.handler.resource_uri() components = [None, [], {}] for i, value in enumerate(resource_uri): components[i] = value lookup_view, args, kwargs = components try: lookup_view = get_callable(lookup_view) except (ImportError, ViewDoesNotExist): # Emulate can_fail=True from earlier django versions. pass possibilities = get_resolver(None).reverse_dict.getlist(lookup_view) # The monkey patch is right here: we need to cope with 'possibilities' # being a list of tuples with 2 or 3 elements. for possibility_data in possibilities: possibility = possibility_data[0] for result, params in possibility: if args: if len(args) != len(params): continue return _convert(result, params) else: if set(kwargs.keys()) != set(params): continue return _convert(result, params) except: return None