Example #1
0
 def test_not_supported(self):
     """Test sending an unsupported request method."""
     #request = mock.Mock(method='FOO')
     factory_request = RequestFactory()
     request = factory_request.head('/mobiles')
     mobiles_view = MobileView.as_view()
     response = mobiles_view(request)
     self.assertEqual(response.status_code, 405,
                      'Should return a 405 NOT ALLOWED.')
     self.assertIn('GET', response['Allow'], 'Should allow GET.')
     self.assertIn('POST', response['Allow'], 'Should allow POST.')
     self.assertIn('PUT', response['Allow'], 'Should allow PUT.')
     self.assertIn('DELETE', response['Allow'], 'Should allow DELETE.')
Example #2
0
class ViewFunctionTests(TestCase):
    """Tests for the inbound view function receive_inbound_email.

    The view function is responsible for loading the correct backend, and
    firing the signal once the email is parsed. This test suite contains no
    parsing tests - these are covered in the relevant backend tests - just tests
    for the signals.

    """
    def setUp(self):
        # Every test needs access to the request factory.
        self.factory = RequestFactory()
        self.url = reverse('receive_inbound_email')
        self.test_upload_txt = path.join(path.dirname(__file__), 'test_files/test_upload_file.txt')

    def _get_payloads_and_parsers(self, with_attachments=False):
        mpwa = mandrill_payload_with_attachments
        mp = mandrill_payload
        return [
            (MANDRILL_REQUEST_PARSER, mpwa if with_attachments else mp),
            (SENDGRID_REQUEST_PARSER, sendgrid_payload),
            (MAILGUN_REQUEST_PARSER, mailgun_payload),
        ]

    def test_log_inbound_requests(self):
        """Test the internal log function."""
        # just to exercise the function - it doesn't 'do' anything other than
        # log to the console, but is good to know that it doesn't break.

        for klass, payload in self._get_payloads_and_parsers():
            settings.INBOUND_EMAIL_PARSER = klass
            request = self.factory.post(self.url, data=payload)
            _log_request(request)

    def test_inbound_request_HEAD_200(self):
        """Return 200 OK to a HEAD request."""
        request = self.factory.head(self.url)
        response = receive_inbound_email(request)
        self.assertEqual(response.status_code, 200)

    def test_valid_request(self):
        """Test the RequestParseErrors are handled correctly, and return HTTP 200."""
        for klass, payload in self._get_payloads_and_parsers():
            settings.INBOUND_EMAIL_PARSER = klass
            request = self.factory.post(self.url, data=payload)
            response = receive_inbound_email(request)
            self.assertContains(response, u"Successfully parsed", status_code=200)

    def test_parse_error_response_200(self):
        """Test the RequestParseErrors are handled correctly, and return HTTP 200."""
        settings.INBOUND_EMAIL_RESPONSE_200 = True
        for klass, payload in self._get_payloads_and_parsers():
            settings.INBOUND_EMAIL_PARSER = klass
            request = self.factory.post(self.url, data={})
            response = receive_inbound_email(request)
            self.assertContains(response, u"Unable to parse", status_code=200)

    def test_parse_error_response_400(self):
        """Test the RequestParseErrors are handled correctly, and return HTTP 400."""
        settings.INBOUND_EMAIL_RESPONSE_200 = False
        request = self.factory.post(self.url, data={})
        response = receive_inbound_email(request)
        self.assertContains(response, u"Unable to parse", status_code=400)

    def test_email_received_signal(self):
        """Test that a valid POST fires the email_received signal."""
        # define handler
        for klass, payload in self._get_payloads_and_parsers():

            def on_email_received(sender, **kwargs):
                self.on_email_received_fired = True
                self.assertEqual(sender.__name__, klass.split('.')[-1])
                request = kwargs.pop('request', None)
                email = kwargs.pop('email', None)
                self.assertIsNotNone(email)
                self.assertIsInstance(email, EmailMultiAlternatives)
                self.assertIsNotNone(request)
            email_received.connect(on_email_received)

            settings.INBOUND_EMAIL_PARSER = klass
            request = self.factory.post(self.url, data=payload)

            # connect handler
            self.on_email_received_fired = False

            # fire a request in to force the signal to fire
            receive_inbound_email(request)
            self.assertTrue(self.on_email_received_fired)

            email_received.disconnect(on_email_received)

    def test_email_received_unacceptable_signal_fired_for_too_large_attachment(self):
        # set a zero allowed max attachment size
        settings.INBOUND_EMAIL_ATTACHMENT_SIZE_MAX = 0

        for klass, payload in self._get_payloads_and_parsers(with_attachments=True):
            settings.INBOUND_EMAIL_PARSER = klass
            _payload = payload.copy()

            if klass == SENDGRID_REQUEST_PARSER:
                _payload['attachment'] = open(self.test_upload_txt, 'r')
            if klass == MAILGUN_REQUEST_PARSER:
                _payload['attachment-1'] = open(self.test_upload_txt, 'r')

            # define handler
            def on_email_received(sender, **kwargs):
                self.on_email_received_fired = True
                request = kwargs.pop('request', None)
                email = kwargs.pop('email', None)
                exception = kwargs.pop('exception', None)
                self.assertEqual(sender.__name__, klass.split('.')[-1])
                self.assertIsNotNone(request)
                self.assertIsInstance(email, EmailMultiAlternatives)
                self.assertIsInstance(exception, AttachmentTooLargeError)
            email_received_unacceptable.connect(on_email_received)

            self.on_email_received_fired = False

            request = self.factory.post(self.url, data=_payload)
            receive_inbound_email(request)
            self.assertTrue(self.on_email_received_fired, klass)
            email_received_unacceptable.disconnect(on_email_received)
Example #3
0
class ResourceTestCase(TestCase):
    def setUp(self):
        self.factory = RequestFactory()

    def test_default(self):
        "Tests for the default Resource which is very limited."
        # Default resource
        resource = Resource()

        # Populated implicitly via the metaclass..
        self.assertEqual(resource.allowed_methods, ("OPTIONS",))

        # OPTIONS is successful, default response with no content is a 204
        request = self.factory.options("/")
        response = resource(request)
        self.assertEqual(response.status_code, codes.no_content)

        # Try another non-default method
        request = self.factory.get("/")
        response = resource(request)
        self.assertEqual(response.status_code, codes.method_not_allowed)
        self.assertEqual(response["Allow"], "OPTIONS")

    def test_default_head(self):
        class GetResource(Resource):
            def get(self, request):
                return {}

        resource = GetResource()

        request = self.factory.head("/")
        response = resource(request)
        self.assertEqual(response.status_code, codes.ok)
        self.assertEqual(response["Content-Type"], "application/json")
        self.assertEqual(response.content, b"")

    def test_default_patch(self):
        # Resources supporting PATCH requests should have an additional
        # header in the response from an OPTIONS request
        class PatchResource(Resource):
            def patch(self, request):
                pass

        resource = PatchResource()
        request = self.factory.options("/")
        response = resource(request)
        self.assertEqual(response.status_code, codes.no_content)
        self.assertEqual(response["Accept-Patch"], "application/json")
        self.assertEqual(response["Content-Type"], "application/json")

    def test_service_unavailable(self):
        "Test service unavailability."

        class IndefiniteUnavailableResource(Resource):
            unavailable = True

        resource = IndefiniteUnavailableResource()

        # Simply setting `unavailable` to True will provide a 'Retry-After'
        # header
        request = self.factory.request()
        response = resource(request)
        self.assertEqual(response.status_code, codes.service_unavailable)
        self.assertTrue("Retry-After" not in response)
        self.assertEqual(response["Content-Type"], "application/json")

    def test_service_unavailable_retry_seconds(self):
        "Test service unavailability with seconds."

        class DeltaUnavailableResource(Resource):
            unavailable = 20

        resource = DeltaUnavailableResource()

        # Set unavailable, but with a specific number of seconds to retry
        # after
        request = self.factory.request()
        response = resource(request)
        self.assertEqual(response.status_code, codes.service_unavailable)
        self.assertEqual(response["Retry-After"], "20")
        self.assertEqual(response["Content-Type"], "application/json")

    def test_service_unavailable_retry_date(self):
        "Test service unavailability with date."
        from datetime import datetime, timedelta
        from django.utils.http import http_date

        future = datetime.now() + timedelta(seconds=20)

        class DatetimeUnavailableResource(Resource):
            unavailable = future

        resource = DatetimeUnavailableResource()

        request = self.factory.request()
        response = resource(request)
        self.assertEqual(response.status_code, codes.service_unavailable)
        self.assertEqual(response["Retry-After"], http_date(timegm(future.utctimetuple())))
        self.assertEqual(response["Content-Type"], "application/json")

    def test_unsupported_media_type(self):
        "Test various Content-* combinations."

        class NoOpResource(Resource):
            def post(self, request, *args, **kwargs):
                pass

        resource = NoOpResource()

        # Works.. default accept-type is application/json
        request = self.factory.post("/", data=b'{"message": "hello w\xc3\xb6"}', content_type="application/json")
        response = resource(request)
        self.assertEqual(response.status_code, codes.no_content)
        self.assertEqual(response["Content-Type"], "application/json")

        # Does not work.. XML not accepted by default
        request = self.factory.post("/", data="<message>hello world</message>", content_type="application/xml")
        response = resource(request)
        self.assertEqual(response.status_code, codes.unsupported_media_type)
        self.assertEqual(response["Content-Type"], "application/json")

    def test_not_acceptable(self):
        "Test Accept header."

        class ReadOnlyResource(Resource):
            def get(self, request, *args, **kwargs):
                return {}

        resource = ReadOnlyResource()

        # No accept-type is specified, defaults to highest priority one
        # for resource
        request = self.factory.request()
        response = resource(request)
        self.assertEqual(response.status_code, codes.ok)
        self.assertEqual(response["Content-Type"], "application/json")

        # Explicit accept header, application/json wins since it's equal
        # priority and supported
        request = self.factory.request(HTTP_ACCEPT="application/json,application/xml;q=0.9,*/*;q=0.8")
        response = resource(request)
        self.assertEqual(response.status_code, codes.ok)
        self.assertEqual(response["Content-Type"], "application/json")

        # No acceptable type list, */* has an explicit quality of 0 which
        # does not allow the server to use an alternate content-type
        request = self.factory.request(HTTP_ACCEPT="text/html,application/xhtml+xml," "application/xml;q=0.9,*/*;q=0")
        response = resource(request)
        self.assertEqual(response.status_code, codes.not_acceptable)
        self.assertEqual(response["Content-Type"], "application/json")

        # Like the first one, but an explicit "anything goes"
        request = self.factory.request(HTTP_ACCEPT="*/*")
        response = resource(request)
        self.assertEqual(response.status_code, codes.ok)
        self.assertEqual(response["Content-Type"], "application/json")

    def test_request_entity_too_large(self):
        "Test request entity too large."

        class TinyResource(Resource):
            max_request_entity_length = 20

            def post(self, request, *args, **kwargs):
                pass

        resource = TinyResource()

        # No problem..
        request = self.factory.post("/", data='{"message": "hello"}', content_type="application/json")
        response = resource(request)
        self.assertEqual(response.status_code, codes.no_content)
        self.assertEqual(response["Content-Type"], "application/json")

        # Too large
        request = self.factory.post("/", data='{"message": "hello world"}', content_type="application/json")
        response = resource(request)
        self.assertEqual(response.status_code, codes.request_entity_too_large)
        self.assertEqual(response["Content-Type"], "application/json")

    def test_too_many_requests(self):
        """Test a global rate limiting implementation.

        This test will take 3 seconds to run to mimic request handling over
        time.
        """
        import time
        from datetime import datetime

        class RateLimitResource(Resource):
            # Maximum of 10 requests within a 2 second window
            rate_limit_count = 10
            rate_limit_seconds = 2

            # Keep track of requests globally for the resource.. only for test
            # purposes, not thread-safe
            request_frame_start = datetime.now()
            request_count = 0

            # Implement rate-limiting logic
            def is_too_many_requests(self, request, *args, **kwargs):
                # Since the start of the frame, calculate the amount of time
                # that has passed
                interval = (datetime.now() - self.request_frame_start).seconds
                # Increment the request count
                self.request_count += 1

                # Reset frame if the interval is greater than the rate limit
                # seconds, i.e on the 3rd second in this test
                if interval > self.rate_limit_seconds:
                    self.request_frame_start = datetime.now()
                    self.request_count = 1
                # ..otherwise throttle if the count is greater than the limit
                elif self.request_count > self.rate_limit_count:
                    return True
                return False

        resource = RateLimitResource()

        request = self.factory.request(REQUEST_METHOD="OPTIONS")

        # First ten requests are ok
        for _ in range(0, 10):
            response = resource(request)
            self.assertEqual(response.status_code, codes.no_content)
            self.assertEqual(response["Content-Type"], "application/json")

        # Mimic a slight delay
        time.sleep(1)

        # Another 10 all get throttled..
        for _ in range(0, 10):
            response = resource(request)
            self.assertEqual(response.status_code, codes.too_many_requests)
            self.assertEqual(response["Content-Type"], "application/json")

        # Another two seconds exceeds the frame, should be good to go
        time.sleep(2)

        for _ in range(0, 10):
            response = resource(request)
            self.assertEqual(response.status_code, codes.no_content)
            self.assertEqual(response["Content-Type"], "application/json")

    def test_precondition_required(self):
        """"Reject non-idempotent requests without the use of a conditional
        header."""

        class PreconditionResource(Resource):
            # Either etags or last-modified must be used otherwise it
            # is not enforced
            use_etags = True
            require_conditional_request = True

            def patch(self, request):
                pass

            def put(self, request):
                pass

            def delete(self, request):
                pass

            def get_etag(self, request, *args, **kwargs):
                return "abc123"

        resource = PreconditionResource()

        # Non-idempotent requests fail without a conditional header, these
        # responses should not be cached
        request = self.factory.put("/", data='{"message": "hello world"}', content_type="application/json")
        response = resource(request)
        self.assertEqual(response.status_code, codes.precondition_required)
        self.assertEqual(response["Content-Type"], "application/json")
        self.assertTrue("no-cache" in response["Cache-Control"])
        self.assertTrue("must-revalidate" in response["Cache-Control"])
        self.assertTrue("max-age=0" in response["Cache-Control"])

        # Add the correct header for testing the Etag
        request = self.factory.put(
            "/", data='{"message": "hello world"}', content_type="application/json", HTTP_IF_MATCH="abc123"
        )
        response = resource(request)
        self.assertEqual(response.status_code, codes.no_content)
        self.assertEqual(response["Content-Type"], "application/json")

        # Idempotent requests, such as DELETE, succeed..
        request = self.factory.delete("/")
        response = resource(request)
        self.assertEqual(response.status_code, codes.no_content)
        self.assertEqual(response["Content-Type"], "application/json")

    def test_precondition_failed_etag(self):
        "Test precondition using etags."

        class PreconditionResource(Resource):
            use_etags = True

            def put(self, request):
                pass

            def get(self, request):
                return {}

            def get_etag(self, request, *args, **kwargs):
                return "abc123"

        resource = PreconditionResource()

        # Send a non-safe request with an incorrect Etag.. fail
        request = self.factory.put(
            "/", data='{"message": "hello world"}', content_type="application/json", HTTP_IF_MATCH='"def456"'
        )
        response = resource(request)
        self.assertEqual(response.status_code, codes.precondition_failed)
        self.assertEqual(response["Content-Type"], "application/json")
        self.assertTrue("no-cache" in response["Cache-Control"])
        self.assertTrue("must-revalidate" in response["Cache-Control"])
        self.assertTrue("max-age=0" in response["Cache-Control"])

        # Incorrect Etag match on GET, updated content is returned
        request = self.factory.get("/", HTTP_IF_NONE_MATCH='"def456"')
        response = resource(request)
        self.assertEqual(response.status_code, codes.ok)
        self.assertEqual(response["Content-Type"], "application/json")

        # Successful Etag match on GET, resource not modified
        request = self.factory.get("/", HTTP_IF_NONE_MATCH='"abc123"')
        response = resource(request)
        self.assertEqual(response.status_code, codes.not_modified)
        self.assertEqual(response["Content-Type"], "application/json")

    def test_precondition_failed_last_modified(self):
        "Test precondition using last-modified dates."
        from datetime import datetime, timedelta
        from django.utils.http import http_date

        last_modified_date = datetime.now()

        class PreconditionResource(Resource):
            use_etags = False
            use_last_modified = True

            def put(self, request):
                pass

            def get(self, request):
                return {}

            def get_last_modified(self, request, *args, **kwargs):
                return last_modified_date

        resource = PreconditionResource()

        # Send non-safe request with a old last-modified date.. fail
        if_modified_since = http_date(timegm((last_modified_date - timedelta(seconds=10)).utctimetuple()))
        request = self.factory.put(
            "/",
            data='{"message": "hello world"}',
            content_type="application/json",
            HTTP_IF_UNMODIFIED_SINCE=if_modified_since,
        )
        response = resource(request)
        self.assertEqual(response.status_code, codes.precondition_failed)
        self.assertEqual(response["Content-Type"], "application/json")
        self.assertTrue("no-cache" in response["Cache-Control"])
        self.assertTrue("must-revalidate" in response["Cache-Control"])
        self.assertTrue("max-age=0" in response["Cache-Control"])

        # Old last-modified on GET, updated content is returned
        if_modified_since = http_date(timegm((last_modified_date - timedelta(seconds=10)).utctimetuple()))
        request = self.factory.get("/", HTTP_IF_MODIFIED_SINCE=if_modified_since)
        response = resource(request)
        self.assertEqual(response.status_code, codes.ok)
        self.assertEqual(response["Content-Type"], "application/json")

        # Mimic future request on GET, resource not modified
        if_modified_since = http_date(timegm((last_modified_date + timedelta(seconds=20)).utctimetuple()))
        request = self.factory.get("/", HTTP_IF_MODIFIED_SINCE=if_modified_since)
        response = resource(request)
        self.assertEqual(response.status_code, codes.not_modified)
        self.assertEqual(response["Content-Type"], "application/json")

    def test_cache_control_default(self):
        class CacheableResource(Resource):
            def get(self, request):
                return {}

        resource = CacheableResource()

        request = self.factory.get("/")
        response = resource(request)
        self.assertFalse("Cache-Control" in response)
        self.assertEqual(response["Content-Type"], "application/json")

    def test_cache_control_seconds(self):
        class CacheableResource(Resource):
            cache_max_age = 60 * 60  # 1 hour

            def get(self, request):
                return {}

        resource = CacheableResource()

        request = self.factory.get("/")
        response = resource(request)
        self.assertEqual(response["Cache-Control"], "max-age=3600")
        self.assertEqual(response["Content-Type"], "application/json")

    def test_cache_control_date(self):
        from datetime import datetime, timedelta
        from django.utils.http import http_date

        class CacheableResource(Resource):
            cache_type = "private"
            cache_max_age = timedelta(seconds=60 * 60)  # 1 hour

            def get(self, request):
                return {}

        resource = CacheableResource()

        request = self.factory.get("/")
        response = resource(request)
        self.assertEqual(response["Cache-Control"], "private")
        self.assertEqual(response["Expires"], http_date(timegm((datetime.now() + timedelta(hours=1)).utctimetuple())))
        self.assertEqual(response["Content-Type"], "application/json")
Example #4
0
class ViewFunctionTests(TestCase):
    """Tests for the inbound view function receive_inbound_email.

    The view function is responsible for loading the correct backend, and
    firing the signal once the email is parsed. This test suite contains no
    parsing tests - these are covered in the relevant backend tests - just tests
    for the signals.

    """
    def setUp(self):
        # Every test needs access to the request factory.
        self.factory = RequestFactory()
        self.url = reverse('inbound:receive_inbound_email')
        self.test_upload_txt = path.join(path.dirname(__file__),
                                         'test_files/test_upload_file.txt')

    def _get_payloads_and_parsers(self, with_attachments=False):
        mpwa = mandrill_payload_with_attachments
        mp = mandrill_payload
        return [
            (MANDRILL_REQUEST_PARSER, mpwa if with_attachments else mp),
            (SENDGRID_REQUEST_PARSER, sendgrid_payload),
            (MAILGUN_REQUEST_PARSER, mailgun_payload),
        ]

    def test_log_inbound_requests(self):
        """Test the internal log function."""
        # just to exercise the function - it doesn't 'do' anything other than
        # log to the console, but is good to know that it doesn't break.

        for klass, payload in self._get_payloads_and_parsers():
            settings.INBOUND_EMAIL_PARSER = klass
            request = self.factory.post(self.url, data=payload)
            _log_request(request)

    def test_inbound_request_HEAD_200(self):
        """Return 200 OK to a HEAD request."""
        request = self.factory.head(self.url)
        response = receive_inbound_email(request)
        self.assertEqual(response.status_code, 200)

    def test_valid_request(self):
        """Test the RequestParseErrors are handled correctly, and return HTTP 200."""
        for klass, payload in self._get_payloads_and_parsers():
            settings.INBOUND_EMAIL_PARSER = klass
            request = self.factory.post(self.url, data=payload)
            response = receive_inbound_email(request)
            self.assertContains(response,
                                u"Successfully parsed",
                                status_code=200)

    def test_parse_error_response_200(self):
        """Test the RequestParseErrors are handled correctly, and return HTTP 200."""
        settings.INBOUND_EMAIL_RESPONSE_200 = True
        for klass, payload in self._get_payloads_and_parsers():
            settings.INBOUND_EMAIL_PARSER = klass
            request = self.factory.post(self.url, data={})
            response = receive_inbound_email(request)
            self.assertContains(response, u"Unable to parse", status_code=200)

    def test_parse_error_response_400(self):
        """Test the RequestParseErrors are handled correctly, and return HTTP 400."""
        settings.INBOUND_EMAIL_RESPONSE_200 = False
        request = self.factory.post(self.url, data={})
        response = receive_inbound_email(request)
        self.assertContains(response, u"Unable to parse", status_code=400)

    def test_email_received_signal(self):
        """Test that a valid POST fires the email_received signal."""
        # define handler
        for klass, payload in self._get_payloads_and_parsers():

            def on_email_received(sender, **kwargs):
                self.on_email_received_fired = True
                self.assertEqual(sender.__name__, klass.split('.')[-1])
                request = kwargs.pop('request', None)
                email = kwargs.pop('email', None)
                self.assertIsNotNone(email)
                self.assertIsInstance(email, EmailMultiAlternatives)
                self.assertIsNotNone(request)

            email_received.connect(on_email_received)

            settings.INBOUND_EMAIL_PARSER = klass
            request = self.factory.post(self.url, data=payload)

            # connect handler
            self.on_email_received_fired = False

            # fire a request in to force the signal to fire
            receive_inbound_email(request)
            self.assertTrue(self.on_email_received_fired)

            email_received.disconnect(on_email_received)

    def test_email_received_unacceptable_signal_fired_for_too_large_attachment(
            self):
        # set a zero allowed max attachment size
        settings.INBOUND_EMAIL_ATTACHMENT_SIZE_MAX = 0

        for klass, payload in self._get_payloads_and_parsers(
                with_attachments=True):
            settings.INBOUND_EMAIL_PARSER = klass
            _payload = payload.copy()

            if klass == SENDGRID_REQUEST_PARSER:
                _payload['attachment'] = open(self.test_upload_txt, 'r')
            if klass == MAILGUN_REQUEST_PARSER:
                _payload['attachment-1'] = open(self.test_upload_txt, 'r')

            # define handler
            def on_email_received(sender, **kwargs):
                self.on_email_received_fired = True
                request = kwargs.pop('request', None)
                email = kwargs.pop('email', None)
                exception = kwargs.pop('exception', None)
                self.assertEqual(sender.__name__, klass.split('.')[-1])
                self.assertIsNotNone(request)
                self.assertIsInstance(email, EmailMultiAlternatives)
                self.assertIsInstance(exception, AttachmentTooLargeError)

            email_received_unacceptable.connect(on_email_received)

            self.on_email_received_fired = False

            request = self.factory.post(self.url, data=_payload)
            receive_inbound_email(request)
            self.assertTrue(self.on_email_received_fired, klass)
            email_received_unacceptable.disconnect(on_email_received)
Example #5
0
class SimpleWebProxyViewTestCase(SimpleTestCase):

    def setUp(self):
        self.factory = RequestFactory()
        self.test_view = SimpleWebProxyView(service_url='http://www.fake.com/service')

    def test_successful_get(self):
        with mock.patch('common.views.requests.get') as mock_requests_get:
            resp = mock.Mock
            resp.text = 'It was successful'
            resp.status_code = 200
            resp.headers = {'content-type' : 'text/xml', 'content-disposition' : 'attachment;filename="Results.xml"'}

            args = []
            kwargs = {'op' : 'specific_op/'}
            request = self.factory.get('/my_service/specific_op/?param1=1&param2=2')

            response = self.test_view.get(request, *args, **kwargs)

            self.assertEqual(mock_requests_get.call_args[0], ('http://www.fake.com/service/specific_op/?param1=1&param2=2',))
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'It was successful')
            self.assertEqual(response['Content-Type'], 'text/xml')
            self.assertEqual(response['Content-Disposition'], 'attachment;filename="Results.xml"')

    def test_unsuccssful_get(self):
        with mock.patch('common.views.requests.get') as mock_requests_get:
            resp = mock.Mock
            resp.text = 'Failure'
            resp.status_code = 404

            args = []
            kwargs = {'op' : 'specific_op/'}
            request = self.factory.get('/my_service/specific_op/?param1=1&param2=2')

            response = self.test_view.get(request, *args, **kwargs)

            self.assertEqual(mock_requests_get.call_args[0], ('http://www.fake.com/service/specific_op/?param1=1&param2=2',))
            self.assertEqual(response.status_code, 404)

    def test_successful_head(self):
        with mock.patch('common.views.requests.head') as mock_requests_head:
            resp = mock.Mock
            resp.text = 'It was successful'
            resp.status_code = 200
            resp.headers = {'content-type' : 'text/xml',
                            'content-disposition' : 'attachment;filename="Results.xml"',
                            'custom-header' : 'Custom header value'}

            args = []
            kwargs = {'op' : 'specific_op/'}
            request = self.factory.head('/my_service/specific_op/?param1=1&param2=2')

            response = self.test_view.head(request, *args, **kwargs)

            self.assertEqual(mock_requests_head.call_args[0], ('http://www.fake.com/service/specific_op/?param1=1&param2=2',))
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'It was successful')
            self.assertEqual(response['Content-Type'], 'text/xml')
            self.assertEqual(response['Content-Disposition'], 'attachment;filename="Results.xml"')
            self.assertEqual(response['custom-header'], 'Custom header value')

    def test_unsuccssful_head(self):
        with mock.patch('common.views.requests.head') as mock_requests_head:
            resp = mock.Mock
            resp.text = 'Failure'
            resp.status_code = 404

            args = []
            kwargs = {'op' : 'specific_op/'}
            request = self.factory.head('/my_service/specific_op/?param1=1&param2=2')

            response = self.test_view.head(request, *args, **kwargs)

            self.assertEqual(mock_requests_head.call_args[0], ('http://www.fake.com/service/specific_op/?param1=1&param2=2',))
            self.assertEqual(response.status_code, 404)

    def test_invalid_method(self):
        args = []
        kwargs = {'op' : 'specific_op/'}
        request = self.factory.post('/my_service/specific_op/?param1=1&param2=2')

        response = SimpleWebProxyView.as_view()(request, *args, **kwargs)

        self.assertEqual(response.status_code, 405)
class ResponseCacheTest(TestCase):
    def setUp(self):
        self.factory = RequestFactory()
        caches['testcache'].clear()

    def random_get(self):
        return self.factory.get('/%s' % uuid4())

    def test_default_key_function(self):
        cache = ResponseCache(1, key_prefix='p')
        # Plain test with all defaults
        self.assertEqual(cache.key_func(self.factory.get('/url1/?k1=v1')),
                         'p#GET#http#testserver#/url1/?k1=v1')
        # Different method
        self.assertEqual(cache.key_func(self.factory.head('/url2/?k2=v2')),
                         'p#HEAD#http#testserver#/url2/?k2=v2')
        # Try HTTPS (hacky)
        request = self.factory.get('/url3/?k3=v3')
        request.is_secure = lambda: True
        self.assertEqual(cache.key_func(request),
                         'p#GET#https#testserver:80#/url3/?k3=v3')
        # Try different Host: + normalisation
        request = self.factory.get('/url4/?k4=v4', HTTP_HOST='FooBar')
        self.assertEqual(cache.key_func(request),
                         'p#GET#http#foobar#/url4/?k4=v4')

    def test_default_key_function_parts_omission(self):
        request = self.factory.get('/url10/?k10=v10')
        # Empty prefix
        self.assertEqual(
            ResponseCache(1).key_func(request),
            '#GET#http#testserver#/url10/?k10=v10')
        # Do not consider scheme
        self.assertEqual(
            ResponseCache(1, key_prefix='p',
                          include_scheme=False).key_func(request),
            'p#GET##testserver#/url10/?k10=v10')
        # Do not consider host
        self.assertEqual(
            ResponseCache(1, key_prefix='p',
                          include_host=False).key_func(request),
            'p#GET#http##/url10/?k10=v10')

    def test_user_supplied_key_function(self):
        # Test dumb user supplied key function
        cache = ResponseCache(1, key_func=lambda r: "KeyValue")
        request = self.factory.get('/')
        self.assertEqual(cache.key_func(request), 'KeyValue')

    def test_should_fetch(self):
        # test default behavious: GETs only
        cache = ResponseCache(1)
        self.assertTrue(cache.should_fetch(self.factory.get('/')))
        self.assertFalse(cache.should_fetch(self.factory.head('/')))
        # Allow HEAD too
        cache = ResponseCache(1, methods=('GET', 'HEAD'))
        self.assertTrue(cache.should_fetch(self.factory.head('/')))
        # Check authenticated requests (shouldn't cache by default)
        request = self.factory.get('/')
        request.user = User.objects.create_user('u1', '*****@*****.**', 'u1')
        self.assertFalse(cache.should_fetch(request))
        # This instance should ignore authenticated user
        self.assertTrue(
            ResponseCache(1, anonymous_only=False).should_fetch(request))
        # Anonymous' responses should be cached
        request.user = AnonymousUser()
        self.assertTrue(cache.should_fetch(request))

    def test_should_store(self):
        cache = ResponseCache(1)
        # Check normal response (200)
        self.assertTrue(
            cache.should_store(self.factory.get('/'), HttpResponse()))
        # Check some non-200 response codes
        for code in (201, 404, 403, 500, 502, 503, 301, 302):
            self.assertFalse(
                cache.should_store(self.factory.get('/'),
                                   HttpResponse(status=code)))

    @skipUnless(StreamingHttpResponse, "Too old for StreamingHttpResponse?")
    def test_should_store_streaming(self):
        cache = ResponseCache(1)
        # StreamingHttpResponse is never cached
        self.assertFalse(
            cache.should_store(self.factory.get('/'), StreamingHttpResponse()))

    def test_caching_decorator(self):
        decorated_view = rsp_cache(randomView)
        # Confirm that the same URL is cached and returns the same content
        request = self.random_get()
        rsp1 = decorated_view(request)
        time.sleep(0.1)
        # This should be still cached
        rsp2 = decorated_view(request)
        time.sleep(0.3)
        # But this will expire and be refreshed
        rsp3 = decorated_view(request)
        self.assertEqual(rsp1.content, rsp2.content)
        self.assertNotEqual(rsp1.content, rsp3.content)

    def test_caching_template_response(self):
        # Perform the same tests for SimpleTemplateResponse
        decorated_view = rsp_cache(randomTemplateView)
        request = self.random_get()
        rsp1 = decorated_view(request)
        time.sleep(0.1)
        rsp2 = decorated_view(request)
        # Should be already rendered because fetched from the cache
        time.sleep(0.3)
        rsp3 = decorated_view(request)
        # Shouldn't be rendered yet again
        # Compare content
        self.assertEqual(rsp1.content, rsp2.content)
        self.assertNotEqual(rsp1.content, rsp3.content)

    def test_caching_decorator_different_urls(self):
        decorated_view = rsp_cache(randomView)
        # Different URLs are cached under different keys
        request1 = self.random_get()
        request2 = self.random_get()
        self.assertNotEqual(
            decorated_view(request1).content,
            decorated_view(request2).content)

    def test_uncacheable_requests(self):
        # Test authenticated requests (shouldn't cache)
        decorated_view = rsp_cache(randomView)
        request = self.factory.get('/')
        request.user = User.objects.create_user('u1', '*****@*****.**', 'u1')
        self.assertNotEqual(
            decorated_view(request).content,
            decorated_view(request).content)

        # Test HEADs (should not cache)
        request = self.factory.head('/')
        self.assertNotEqual(
            decorated_view(request).content,
            decorated_view(request).content)

    def test_last_modified_default(self):
        decorated_view = rsp_cache(randomView)
        # Last-Modified has to be set to "now"
        request = self.random_get()
        rsp = decorated_view(request)
        self.assertEqual(rsp.get('Last-Modified'), http_date())

    def test_last_modified_from_response(self):
        decorated_view = rsp_cache(randomView)
        # Last-Modified has to be set to whatever was in the original response
        request = self.random_get()
        rsp = decorated_view(request, 123456)
        self.assertEqual(rsp.get('Last-Modified'), http_date(123456))

    def test_cache_arbitrary_header(self):
        decorated_view = rsp_cache(randomView)
        # Response setting some unknown header gets cached
        request = self.random_get()
        rsp1 = decorated_view(request, headers={'h1': 'v1'})
        rsp2 = decorated_view(request, headers={'h2': 'v2'})
        self.assertEqual(rsp1.content, rsp2.content)
        # First request had been cached with its headers
        self.assertEqual(rsp2['h1'], 'v1')
        self.assertFalse(rsp2.has_header('h2'))

    def test_not_caching_set_cookie(self):
        decorated_view = rsp_cache(randomView)
        # First request with Set-Cookie is not cached
        request = self.random_get()
        rsp1 = decorated_view(request, headers={'Set-Cookie': 'foobar'})
        rsp2 = decorated_view(request)
        self.assertNotEqual(rsp1.content, rsp2.content)
        self.assertTrue(rsp1.has_header('Set-Cookie'))
        self.assertFalse(rsp2.has_header('Set-Cookie'))

    def test_not_caching_vary(self):
        decorated_view = rsp_cache(randomView)
        # First request with Set-Cookie is not cached
        request = self.random_get()
        rsp1 = decorated_view(request, headers={'Vary': '*'})
        rsp2 = decorated_view(request)
        self.assertNotEqual(rsp1.content, rsp2.content)
        self.assertTrue(rsp1.has_header('Vary'))
        self.assertFalse(rsp2.has_header('Vary'))

    def test_not_caching_configured_req_hdr(self):
        decorated_view = ResponseCache(0.3,
                                       cache='testcache',
                                       nocache_req={'HTTP_HDR1':
                                                    '.123[abc]'})(randomView)
        request = self.random_get()
        # Should match and pass not cached
        request.META['HTTP_HDR1'] = '0a123b'
        rsp1 = decorated_view(request)
        rsp2 = decorated_view(request)
        self.assertNotEqual(rsp1.content, rsp2.content)
        # Should not match and be cached
        request.META['HTTP_HDR1'] = 'other'
        rsp3 = decorated_view(request)
        rsp4 = decorated_view(request)
        self.assertEqual(rsp3.content, rsp4.content)

    def test_not_caching_configured_rsp_hdr(self):
        decorated_view = ResponseCache(0.3,
                                       cache='testcache',
                                       nocache_rsp=('Hdr1', ))(randomView)
        # First request with Set-Cookie is not cached
        request = self.random_get()
        rsp1 = decorated_view(request, headers={'Hdr1': 'val1'})
        rsp2 = decorated_view(request)
        self.assertNotEqual(rsp1.content, rsp2.content)
        self.assertTrue(rsp1.has_header('Hdr1'))
        self.assertFalse(rsp2.has_header('Hdr1'))

    def test_not_caching_csrf_response(self):
        decorated_view = rsp_cache(csrfView)
        url = "/%s" % uuid4()
        # Responses that have CSRF token used should not be cached
        request1 = self.factory.get(url)
        request2 = self.factory.get(url)
        rsp1 = decorated_view(request1)
        rsp2 = decorated_view(request2)
        self.assertNotEqual(rsp1.content, rsp2.content)

    def test_not_caching_csrf_template_response(self):
        decorated_view = rsp_cache(csrfTemplateView)
        url = "/%s" % uuid4()
        # Responses that have CSRF token used should not be cached
        request1 = self.factory.get(url)
        request2 = self.factory.get(url)
        rsp1 = decorated_view(request1)
        rsp1.render()
        rsp2 = decorated_view(request2)
        rsp2.render()
        self.assertNotEqual(rsp1.content, rsp2.content)

    def test_not_caching_req_cookies(self):
        decorated_view = rsp_cache(randomView)
        # By default, requests with cookies aren't cached
        request = self.random_get()
        request.COOKIES['c1'] = 'v1'
        rsp1 = decorated_view(request)
        rsp2 = decorated_view(request)
        self.assertNotEqual(rsp1.content, rsp2.content)

    def test_whitelisted_req_cookies(self):
        cache = ResponseCache(0.3,
                              cache='testcache',
                              excluded_cookies=('c1', ))
        decorated_view = cache(randomView)
        # This cookie does not prevent request from being cached
        request = self.random_get()
        request.COOKIES['c1'] = 'v1'
        rsp1 = decorated_view(request)
        rsp2 = decorated_view(request)
        self.assertEqual(rsp1.content, rsp2.content)

    def test_caching_req_cookies(self):
        cache = ResponseCache(0.3, cache='testcache', cache_cookies=True)
        decorated_view = cache(randomView)
        # This request should be cached with any cookie set
        request = self.random_get()
        request.COOKIES['c1'] = 'v1'
        rsp1 = decorated_view(request)
        rsp2 = decorated_view(request)
        self.assertEqual(rsp1.content, rsp2.content)

    def test_blacklisted_req_cookies(self):
        cache = ResponseCache(0.3,
                              cache='testcache',
                              cache_cookies=True,
                              excluded_cookies=('c1', ))
        decorated_view = cache(randomView)
        # This cookie prevents this request from being cached,
        # though generally cookies are allowed
        request = self.random_get()
        request.COOKIES['c1'] = 'v1'
        rsp1 = decorated_view(request)
        rsp2 = decorated_view(request)
        self.assertNotEqual(rsp1.content, rsp2.content)

    def test_hitmiss_header(self):
        decorated_view = rsp_cache(randomView)
        request = self.random_get()
        rsp1 = decorated_view(request)
        rsp2 = decorated_view(request)
        self.assertEqual(rsp1['X-Cache'], 'Miss')
        self.assertEqual(rsp2['X-Cache'], 'Hit')

    def test_custom_hitmiss_header(self):
        cache = ResponseCache(0.3,
                              cache='testcache',
                              hitmiss_header=('h', '+', '-'))
        decorated_view = cache(randomView)
        request = self.random_get()
        rsp1 = decorated_view(request)
        rsp2 = decorated_view(request)
        self.assertFalse(rsp1.has_header('X-Cache'))
        self.assertFalse(rsp2.has_header('X-Cache'))
        self.assertEqual(rsp1['h'], '-')
        self.assertEqual(rsp2['h'], '+')

    def test_absent_hitmiss_header(self):
        cache = ResponseCache(0.3, cache='testcache', hitmiss_header=None)
        decorated_view = cache(randomView)
        request = self.random_get()
        rsp1 = decorated_view(request)
        rsp2 = decorated_view(request)
        self.assertFalse(rsp1.has_header('X-Cache'))
        self.assertFalse(rsp2.has_header('X-Cache'))

    def test_custom_hitmiss_header_template_view(self):
        cache = ResponseCache(0.3,
                              cache='testcache',
                              hitmiss_header=('h', '+', '-'))
        decorated_view = cache(randomTemplateView)
        request = self.random_get()
        rsp1 = decorated_view(request)
        rsp2 = decorated_view(request)
        self.assertFalse(rsp1.has_header('X-Cache'))
        self.assertFalse(rsp2.has_header('X-Cache'))
        self.assertEqual(rsp1['h'], '-')
        self.assertEqual(rsp2['h'], '+')

    def test_wrapper_special_properties(self):
        # The wrapper should keep original function's special attributes
        decorated_view = rsp_cache(randomView)
        self.assertEqual(decorated_view.__doc__, randomView.__doc__)
        self.assertEqual(decorated_view.__module__, randomView.__module__)
        self.assertEqual(decorated_view.__name__, randomView.__name__)