Пример #1
0
async def test_retries_enabled(server: Server) -> None:
    """
    When retries are enabled, connection failures are retried on with
    a fixed exponential backoff.
    """
    method = b"GET"
    url = (b"http", *server.netloc, b"/")
    headers = [server.host_header]
    backend = AsyncMockBackend()
    retries = 10  # Large enough to not run out of retries within this test.

    async with httpcore.AsyncConnectionPool(retries=retries,
                                            max_keepalive_connections=0,
                                            backend=backend) as http:
        # Standard case, no failures.
        response = await http.arequest(method, url, headers)
        assert backend.pop_open_tcp_stream_intervals() == []
        status_code, _, stream, _ = response
        assert status_code == 200
        await read_body(stream)

        # One failure, then success.
        backend.push(httpcore.ConnectError(), None)
        response = await http.arequest(method, url, headers)
        assert backend.pop_open_tcp_stream_intervals() == [
            pytest.approx(0, abs=1e-3),  # Retry immediately.
        ]
        status_code, _, stream, _ = response
        assert status_code == 200
        await read_body(stream)

        # Three failures, then success.
        backend.push(
            httpcore.ConnectError(),
            httpcore.ConnectTimeout(),
            httpcore.ConnectTimeout(),
            None,
        )
        response = await http.arequest(method, url, headers)
        assert backend.pop_open_tcp_stream_intervals() == [
            pytest.approx(0, abs=1e-3),  # Retry immediately.
            pytest.approx(0.5, rel=0.1),  # First backoff.
            pytest.approx(1.0, rel=0.1),  # Second (increased) backoff.
        ]
        status_code, _, stream, _ = response
        assert status_code == 200
        await read_body(stream)

        # Non-connect exceptions are not retried on.
        backend.push(httpcore.ReadTimeout(), httpcore.NetworkError())
        with pytest.raises(httpcore.ReadTimeout):
            await http.arequest(method, url, headers)
        with pytest.raises(httpcore.NetworkError):
            await http.arequest(method, url, headers)
Пример #2
0
async def test_retries_exceeded(server: Server) -> None:
    """
    When retries are enabled and connecting failures more than the configured number
    of retries, connect exceptions are raised.
    """
    backend = AsyncMockBackend()
    retries = 1

    async with httpcore.AsyncConnectionPool(
        retries=retries, max_keepalive_connections=0, backend=backend
    ) as http:
        response = await http.handle_async_request(
            method=b"GET",
            url=(b"http", *server.netloc, b"/"),
            headers=[server.host_header],
            stream=httpcore.ByteStream(b""),
            extensions={},
        )
        status_code, _, stream, _ = response
        assert status_code == 200
        await read_body(stream)

        # First failure is retried on, second one isn't.
        backend.push(httpcore.ConnectError(), httpcore.ConnectTimeout())
        with pytest.raises(httpcore.ConnectTimeout):
            await http.handle_async_request(
                method=b"GET",
                url=(b"http", *server.netloc, b"/"),
                headers=[server.host_header],
                stream=httpcore.ByteStream(b""),
                extensions={},
            )
Пример #3
0
 async def arequest(self, method, url, headers=None, stream=None, ext=None):
     retry = 2
     while retry > 0:
         retry -= 1
         try:
             return await super().arequest(method, url, headers, stream,
                                           ext)
         except OSError as e:
             # socket.gaierror when DNS resolution fails
             raise httpcore.ConnectError(e)
         except httpcore.CloseError as e:
             # httpcore.CloseError: [Errno 104] Connection reset by peer
             # raised by _keepalive_sweep()
             #   from https://github.com/encode/httpcore/blob/4b662b5c42378a61e54d673b4c949420102379f5/httpcore/_backends/asyncio.py#L198  # noqa
             await close_connections_for_url(self._pool, url)
             logger.warning('httpcore.CloseError: retry', exc_info=e)
             # retry
         except httpcore.RemoteProtocolError as e:
             # in case of httpcore.RemoteProtocolError: Server disconnected
             await close_connections_for_url(self._pool, url)
             logger.warning('httpcore.RemoteProtocolError: retry',
                            exc_info=e)
             # retry
         except (httpcore.ProtocolError, httpcore.NetworkError) as e:
             await close_connections_for_url(self._pool, url)
             raise e
Пример #4
0
def test_raise_on_request_error(client: Client) -> None:
    """If raise exception on a request error."""
    respx.put(
        re.compile(PLATFORM_URL + "/api/v1/requests/.*$"),
        content=httpcore.ConnectError(),
    )

    # TODO: do we really want to leak httpx to our clients?
    # We could catch all exception thrown by httpx, wrap it in a few library
    # exceptions and rethrow those.
    with pytest.raises(httpx.ConnectError):
        client.put(client.identity.public_identity)
Пример #5
0
async def test_no_retries(server: Server) -> None:
    """
    By default, connection failures are not retried on.
    """
    backend = AsyncMockBackend()

    async with httpcore.AsyncConnectionPool(
        max_keepalive_connections=0, backend=backend
    ) as http:
        response = await http.handle_async_request(
            method=b"GET",
            url=(b"http", *server.netloc, b"/"),
            headers=[server.host_header],
            stream=httpcore.ByteStream(b""),
            extensions={},
        )
        status_code, _, stream, _ = response
        assert status_code == 200
        await read_body(stream)

        backend.push(httpcore.ConnectTimeout(), httpcore.ConnectError())

        with pytest.raises(httpcore.ConnectTimeout):
            await http.handle_async_request(
                method=b"GET",
                url=(b"http", *server.netloc, b"/"),
                headers=[server.host_header],
                stream=httpcore.ByteStream(b""),
                extensions={},
            )

        with pytest.raises(httpcore.ConnectError):
            await http.handle_async_request(
                method=b"GET",
                url=(b"http", *server.netloc, b"/"),
                headers=[server.host_header],
                stream=httpcore.ByteStream(b""),
                extensions={},
            )
Пример #6
0
def test_no_retries(server: Server) -> None:
    """
    By default, connection failures are not retried on.
    """
    method = b"GET"
    url = (b"http", *server.netloc, b"/")
    headers = [server.host_header]
    backend = SyncMockBackend()

    with httpcore.SyncConnectionPool(max_keepalive_connections=0,
                                     backend=backend) as http:
        response = http.request(method, url, headers)
        status_code, _, stream, _ = response
        assert status_code == 200
        read_body(stream)

        backend.push(httpcore.ConnectTimeout(), httpcore.ConnectError())

        with pytest.raises(httpcore.ConnectTimeout):
            http.request(method, url, headers)

        with pytest.raises(httpcore.ConnectError):
            http.request(method, url, headers)
Пример #7
0
 def raise_exception_once(*args, **kwargs):
     nonlocal times_called
     times_called += 1
     if times_called == 1:
         raise httpcore.ConnectError()
     return pytest_httpx.to_response()
Пример #8
0
 def connect_failed(*args, **kwargs):
     raise httpcore.ConnectError()