Beispiel #1
0
    def test__get_response_deleted_nonces_across_requests(self):
        handler = views.WebApplicationHandler(3)
        user = factory.make_User()
        token = user.userprofile.get_authorisation_tokens()[0]

        recorder = []

        def get_response_check_nonce(self, request):
            _, oauth_req = initialize_server_request(request)
            # get_or _create the Nonce object like the authentication
            # mechanism does.
            nonce_obj, created = Nonce.objects.get_or_create(
                consumer_key=token.consumer.key,
                token_key=token.key,
                key=oauth_req.get_parameter('oauth_nonce'))

            # Record calls.
            recorder.append(created)
            response = HttpResponse(content='',
                                    status=200,
                                    content_type=b"text/plain; charset=utf-8")
            handler._WebApplicationHandler__retry.add(response)
            return response

        self.patch(WSGIHandler, "get_response", get_response_check_nonce)

        oauth_env = {
            'oauth_consumer_key': token.consumer.key,
            'oauth_token': token.key,
        }
        request = make_request(oauth_env=oauth_env)

        handler.get_response(request)
        self.assertEqual(recorder, [True] * 3, "Nonce hasn't been cleaned up!")
Beispiel #2
0
    def test__get_response_restores_files_across_requests(self):
        handler = views.WebApplicationHandler(3)
        file_content = sample_binary_data
        file_name = 'content'

        recorder = []

        def get_response_read_content_files(self, request):
            # Simple get_response method which returns the 'file_name' file
            # from the request in the response.
            content = request.FILES[file_name].read()
            # Record calls.
            recorder.append(content)
            response = HttpResponse(content=content,
                                    content_type=b"text/plain; charset=utf-8")
            handler._WebApplicationHandler__retry.add(response)
            return response

        self.patch(WSGIHandler, "get_response",
                   get_response_read_content_files)

        body, headers = encode_multipart_data(
            [], [[file_name, io.BytesIO(file_content)]])
        env = {
            'REQUEST_METHOD': 'POST',
            'wsgi.input': wsgi._InputStream(io.BytesIO(body.encode("utf-8"))),
            'CONTENT_TYPE': headers['Content-Type'],
            'CONTENT_LENGTH': headers['Content-Length'],
            'HTTP_MIME_VERSION': headers['MIME-Version'],
        }
        request = make_request(env)

        response = handler.get_response(request)
        self.assertEqual(file_content, response.content)
        self.assertEqual(recorder, [file_content] * 3)
Beispiel #3
0
    def test__get_response_tries_multiple_times(self):
        handler = views.WebApplicationHandler(3)
        # An iterable of responses, the last of which will be
        # an HttpResponseConflict (HTTP 409 - Conflict) error
        # indicating that the request reached its maximum
        # number of retry attempts.
        responses = iter((HttpResponse(status=200), HttpResponse(status=200),
                          HttpResponse(status=200)))

        def set_retry(request):
            response = next(responses)
            handler._WebApplicationHandler__retry.add(response)
            return response

        get_response = self.patch(WSGIHandler, "get_response")
        get_response.side_effect = set_retry

        reset_request = self.patch_autospec(views, "reset_request")
        reset_request.side_effect = lambda request: request

        request = make_request()
        request.path = factory.make_name("path")
        response = handler.get_response(request)

        self.assertThat(
            get_response,
            MockCallsMatch(call(request), call(request), call(request)))
        self.assertThat(response, IsInstance(HttpResponseConflict))
        self.expectThat(response.status_code, Equals(http.client.CONFLICT))
        self.expectThat(response.reason_phrase,
                        Equals(http.client.responses[http.client.CONFLICT]))
Beispiel #4
0
    def test_get_response_logs_retry_and_resets_request(self):
        timeout = 1.0 + (random() * 99)
        handler = views.WebApplicationHandler(2, timeout)

        def set_retry(request):
            response = HttpResponse(status=200)
            handler._WebApplicationHandler__retry.add(response)
            return response

        get_response = self.patch(WSGIHandler, "get_response")
        get_response.side_effect = set_retry

        self.patch_autospec(views, "log_failed_attempt")
        self.patch_autospec(views, "log_final_failed_attempt")
        reset_request = self.patch_autospec(views, "reset_request")
        reset_request.side_effect = lambda request: request

        request = make_request()
        request.path = factory.make_name("path")
        handler.get_response(request)

        self.expectThat(
            views.log_failed_attempt,
            MockCalledOnceWith(request, 1, ANY, ANY, ANY),
        )
        self.expectThat(views.log_final_failed_attempt,
                        MockCalledOnceWith(request, 2, ANY))
        self.expectThat(reset_request, MockCalledOnceWith(request))
Beispiel #5
0
    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)))
Beispiel #6
0
 def test_init_defaults(self):
     handler = views.WebApplicationHandler()
     self.expectThat(handler._WebApplicationHandler__retry_attempts,
                     Equals(10))
     self.expectThat(handler._WebApplicationHandler__retry_timeout,
                     Equals(90))
     self.expectThat(handler._WebApplicationHandler__retry,
                     IsInstance(WeakSet))
     self.expectThat(handler._WebApplicationHandler__retry, HasLength(0))
Beispiel #7
0
    def test_get_response_catches_deadlock_failures(self):
        get_response = self.patch(WSGIHandler, "get_response")
        get_response.side_effect = make_deadlock_failure()

        handler = views.WebApplicationHandler(1)
        request = make_request()
        request.path = factory.make_name("path")
        response = handler.get_response(request)

        self.assertThat(get_response, MockCalledOnceWith(request))
        self.assertThat(response, IsInstance(HttpResponseConflict))
Beispiel #8
0
    def test__get_response_tries_only_once(self):
        get_response = self.patch(WSGIHandler, "get_response")
        get_response.return_value = sentinel.response

        handler = views.WebApplicationHandler()
        request = make_request()
        request.path = factory.make_name("path")
        response = handler.get_response(request)

        self.assertThat(get_response, MockCalledOnceWith(request))
        self.assertThat(response, Is(sentinel.response))
Beispiel #9
0
 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))
Beispiel #10
0
    def test_get_response_up_calls_in_transaction(self):
        handler = views.WebApplicationHandler(2)

        def check_in_transaction(request):
            validate_in_transaction(connection)

        get_response = self.patch(WSGIHandler, "get_response")
        get_response.side_effect = check_in_transaction

        request = make_request()
        request.path = factory.make_name("path")
        handler.get_response(request)

        self.assertThat(get_response, MockCalledOnceWith(request))
Beispiel #11
0
    def test_get_response_is_in_retry_context_in_transaction(self):
        handler = views.WebApplicationHandler(2)

        def check_retry_context_active(request):
            self.assertThat(retry_context.active, Is(True))

        get_response = self.patch(WSGIHandler, "get_response")
        get_response.side_effect = check_retry_context_active

        request = make_request()
        request.path = factory.make_name("path")

        self.assertThat(retry_context.active, Is(False))
        handler.get_response(request)
        self.assertThat(retry_context.active, Is(False))
        self.assertThat(get_response, MockCalledOnceWith(request))
Beispiel #12
0
    def test__get_response_sends_signal_on_deadlock_failures(self):
        get_response = self.patch(WSGIHandler, "get_response")
        get_response.side_effect = make_deadlock_failure()

        send_request_exception = self.patch_autospec(
            signals.got_request_exception, "send")

        handler = views.WebApplicationHandler(1)
        request = make_request()
        request.path = factory.make_name("path")
        handler.get_response(request)

        self.assertThat(
            send_request_exception,
            MockCalledOnceWith(sender=views.WebApplicationHandler,
                               request=request))
Beispiel #13
0
    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))
Beispiel #14
0
 def test_handle_uncaught_exception_does_not_note_other_failure(self):
     handler = views.WebApplicationHandler()
     request = make_request()
     request.path = factory.make_name("path")
     failure_type = factory.make_exception_type()
     failure = failure_type, failure_type(), None
     response = handler.handle_uncaught_exception(
         request=request,
         resolver=get_resolver(None),
         exc_info=failure,
         reraise=False,
     )
     # HTTP 500 is returned...
     self.expectThat(response.status_code,
                     Equals(http.client.INTERNAL_SERVER_ERROR))
     # ... but the response is NOT recorded as needing a retry.
     self.expectThat(handler._WebApplicationHandler__retry,
                     Not(Contains(response)))
Beispiel #15
0
    def test_get_response_prepare_retry_context_before_each_try(self):
        class ObserveContext:
            def __init__(self, callback, name):
                self.callback = callback
                self.name = name

            def __enter__(self):
                self.callback("%s:enter" % self.name)

            def __exit__(self, *exc_info):
                self.callback("%s:exit" % self.name)

        counter = count(1)
        calls = []

        def get_response_and_retry(request):
            calls.append("get_response")
            request_transaction_retry(
                ObserveContext(calls.append, "context#%d" % next(counter)))

        get_response = self.patch(WSGIHandler, "get_response")
        get_response.side_effect = get_response_and_retry

        reset_request = self.patch_autospec(views, "reset_request")
        reset_request.side_effect = lambda request: request

        request = make_request()
        request.path = factory.make_name("path")
        handler = views.WebApplicationHandler(3)
        handler.get_response(request)

        self.assertThat(
            calls,
            Equals([
                "get_response",  # 1st attempt.
                "context#1:enter",  # Retry requested, enter 1st new context.
                "get_response",  # 2nd attempt.
                "context#2:enter",  # Retry requested, enter 2nd new context.
                "get_response",  # 3rd attempt, and last.
                "context#2:exit",  # Exit 2nd context.
                "context#1:exit",  # Exit 1st context.
            ]),
        )
Beispiel #16
0
    def test__make_view_atomic_wraps_view_with_post_commit_savepoint(self):
        hooks = post_commit_hooks.hooks
        savepoint_level = len(connection.savepoint_ids)

        def view(*args, **kwargs):
            # We're one more savepoint in.
            self.assertThat(connection.savepoint_ids,
                            HasLength(savepoint_level + 1))
            # Post-commit hooks have been saved.
            self.assertThat(post_commit_hooks.hooks, Not(Is(hooks)))
            # Return the args we were given.
            return args, kwargs

        handler = views.WebApplicationHandler()
        view_atomic = handler.make_view_atomic(view)

        self.assertThat(post_commit_hooks.hooks, Is(hooks))
        self.assertThat(view_atomic(sentinel.arg, kwarg=sentinel.kwarg),
                        Equals(((sentinel.arg, ), {
                            "kwarg": sentinel.kwarg
                        })))
        self.assertThat(post_commit_hooks.hooks, Is(hooks))
Beispiel #17
0
 def test_init_timeout_can_be_set(self):
     handler = views.WebApplicationHandler(timeout=sentinel.timeout)
     self.expectThat(handler._WebApplicationHandler__retry_timeout,
                     Is(sentinel.timeout))
Beispiel #18
0
 def test_init_attempts_can_be_set(self):
     attempts = randint(1, 100)
     handler = views.WebApplicationHandler(attempts)
     self.expectThat(handler._WebApplicationHandler__retry_attempts,
                     Equals(attempts))