예제 #1
0
    async def test_stream_is_cached(self, url, async_client):
        async with async_client.stream("GET", url + "stream") as resp_1:
            content_1 = await resp_1.aread()

        async with async_client.stream("GET", url + "stream") as resp_2:
            content_2 = await resp_2.aread()

        assert not cache_hit(resp_1)
        assert cache_hit(resp_2)
        assert content_1 == content_2
예제 #2
0
    async def test_redirect_response_is_cached(self, url):
        await self.async_client.get(url + "permanent_redirect",
                                    allow_redirects=False)

        resp = await self.async_client.get(url + "permanent_redirect",
                                           allow_redirects=False)
        assert cache_hit(resp)
예제 #3
0
    async def test_multiple_choices_is_cacheable(self, url):
        await self.async_client.get(url + "multiple_choices_redirect",
                                    allow_redirects=False)

        resp = await self.async_client.get(url + "multiple_choices_redirect",
                                           allow_redirects=False)

        assert cache_hit(resp)
예제 #4
0
    async def test_etags_get_example(self, async_client, url):
        """RFC 2616 14.26

        The If-None-Match request-header field is used with a method to make
        it conditional. A client that has one or more entities previously
        obtained from the resource can verify that none of those entities
        is current by including a list of their associated entity tags in
        the If-None-Match header field. The purpose of this feature is to
        allow efficient updates of cached information with a minimum amount
        of transaction overhead

        If any of the entity tags match the entity tag of the entity that
        would have been returned in the response to a similar GET request
        (without the If-None-Match header) on that resource, [...] then
        the server MUST NOT perform the requested method, [...]. Instead, if
        the request method was GET or HEAD, the server SHOULD respond with
        a 304 (Not Modified) response, including the cache-related header
        fields (particularly ETag) of one of the entities that matched.

        (Paraphrased) A server may provide an ETag header on a response. On
        subsequent queries, the client may reference the value of this Etag
        header in an If-None-Match header; on receiving such a header, the
        server can check whether the entity at that URL has changed from the
        clients last version, and if not, it can return a 304 to indicate
        the client can use it's current representation.
        """
        r1 = await async_client.get(url + "etag")
        # make sure we cached it
        assert await async_client._transport.cache.aget(url + "etag")

        # make the same request
        r2 = await async_client.get(url + "etag")
        assert cache_hit(r2)
        assert raw_resp(r2) == raw_resp(r1)

        # tell the server to change the etags of the response
        await async_client.get(url + "update_etag")

        r3 = await async_client.get(url + "etag")
        assert not cache_hit(r3)
        assert raw_resp(r3) != raw_resp(r1)

        r4 = await async_client.get(url + "etag")
        assert cache_hit(r4)
        assert raw_resp(r4) == raw_resp(r3)
예제 #5
0
    async def test_vary_example(self, async_client, cache, url):
        """RFC 2616 13.6

        When the cache receives a subsequent request whose Request-URI
        specifies one or more cache entries including a Vary header field,
        the cache MUST NOT use such a cache entry to construct a response
        to the new request unless all of the selecting request-headers
        present in the new request match the corresponding stored
        request-headers in the original request.

        Or, in simpler terms, when you make a request and the server
        returns defines a Vary header, unless all the headers listed
        in the Vary header are the same, it won't use the cached
        value.
        """
        vary_url = urljoin(url, "/vary_accept")

        r = await async_client.get(vary_url, headers={"foo": "a"})
        cached_response, _vary_data = await cache.aget(vary_url)

        # make the same request
        resp = await async_client.get(vary_url, headers={"foo": "b"})
        assert cache_hit(resp)

        # make a similar request, changing the accept header
        resp = await async_client.get(vary_url,
                                      headers={
                                          "Accept": "text/plain, text/html",
                                          "foo": "c"
                                      })

        with pytest.raises(AssertionError):
            self.assert_cached_equal(cached_response, resp)
        assert not cache_hit(resp)

        # Just confirming two things here:
        #
        #   1) The server used the vary header
        #   2) We have more than one header we vary on
        #
        # The reason for this is that when we don't specify the header
        # in the request, it is considered the same in terms of
        # whether or not to use the cached value.
        assert "vary" in r.headers
        assert len(r.headers["vary"].replace(" ", "").split(",")) == 2
예제 #6
0
    async def test_bust_cache_on_redirect(self, url):
        await self.async_client.get(url + "permanent_redirect",
                                    allow_redirects=False)

        resp = await self.async_client.get(
            url + "permanent_redirect",
            headers={"cache-control": "no-cache"},
            allow_redirects=False,
        )
        assert not cache_hit(resp)
예제 #7
0
    async def test_cache_for_one_day(self, url):
        the_url = url + "optional_cacheable_request"
        r = await self.async_client.get(the_url)

        assert "expires" in r.headers
        assert "warning" in r.headers

        pprint(dict(r.headers))

        r = await self.async_client.get(the_url)
        pprint(dict(r.headers))
        assert cache_hit(r)
예제 #8
0
    async def test_expires_after_one_day(self, url):
        the_url = url + "no_cache"
        resp = httpx.get(the_url)
        assert resp.headers["cache-control"] == "no-cache"

        r = await self.async_client.get(the_url)

        assert "expires" in r.headers
        assert "warning" in r.headers
        assert r.headers["cache-control"] == "public"

        r = await self.async_client.get(the_url)
        assert cache_hit(r)
예제 #9
0
    async def test_cache_chunked_response(self, url, async_client):
        """
        Verify that an otherwise cacheable response is cached when the
        response is chunked.
        """
        url = url + "stream"
        r = await async_client.get(url)
        print(async_client._transport.cache.data)
        assert r.headers.get("transfer-encoding") == "chunked"

        r = await async_client.get(url,
                                   headers={"Cache-Control": "max-age=3600"})
        assert cache_hit(r)
예제 #10
0
    async def test_expired_etags_if_none_match_response(
            self, async_client, url):
        """Make sure an expired response that contains an ETag uses
        the If-None-Match header.
        """
        # Cache an old etag response
        with freeze_time("2012-01-14"):
            await async_client.get(url + "etag")

        assert await async_client._transport.cache.aget(url + "etag")

        r2 = await async_client.get(url + "etag")
        assert cache_hit(r2)

        real_request = get_last_request(async_client)
        assert "if-none-match" in real_request.headers
        assert r2.status_code == 200
예제 #11
0
 async def test_delete_invalidates_cache(self, url, async_client):
     await async_client.get(url)
     await async_client.delete(url)
     r3 = await async_client.get(url)
     assert not cache_hit(r3)
예제 #12
0
 async def test_patch_invalidates_cache(self, url, async_client):
     await async_client.get(url)
     await async_client.patch(url, data={"foo": "bar"})
     r3 = await async_client.get(url)
     assert not cache_hit(r3)
예제 #13
0
 async def test_get_with_no_cache_does_not_cache(self, url, async_client):
     await async_client.get(url)
     r2 = await async_client.get(url, headers={"Cache-Control": "no-cache"})
     assert not cache_hit(r2)
예제 #14
0
 async def test_get_caches(self, url, async_client):
     await async_client.get(url)
     r2 = await async_client.get(url)
     assert cache_hit(r2)
예제 #15
0
 async def test_stream_is_not_cached_when_content_is_not_read(
         self, url, async_client):
     async with async_client.stream("GET", url + "stream"):
         pass
     async with async_client.stream("GET", url + "stream") as resp:
         assert not cache_hit(resp)