示例#1
0
async def test_keepalive_timeout(server):
    """
    Keep-alive connections should timeout.
    """
    async with ConnectionPool() as http:
        response = await http.request("GET", server.url)
        await response.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1

        http.next_keepalive_check = 0.0
        await http.check_keepalive_expiry()

        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1

    async with ConnectionPool() as http:
        http.KEEP_ALIVE_EXPIRY = 0.0

        response = await http.request("GET", server.url)
        await response.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1

        http.next_keepalive_check = 0.0
        await http.check_keepalive_expiry()

        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 0
示例#2
0
async def test_http2_settings_in_handshake():
    backend = MockHTTP2Backend(app=app)
    dispatch = ConnectionPool(backend=backend, http2=True)

    async with AsyncClient(dispatch=dispatch) as client:
        await client.get("http://example.org")

    h2_conn = backend.server.conn

    assert isinstance(h2_conn, h2.connection.H2Connection)
    expected_settings = {
        SettingCodes.HEADER_TABLE_SIZE: 4096,
        SettingCodes.ENABLE_PUSH: 0,
        SettingCodes.MAX_CONCURRENT_STREAMS: 100,
        SettingCodes.INITIAL_WINDOW_SIZE: 65535,
        SettingCodes.MAX_FRAME_SIZE: 16384,
        SettingCodes.MAX_HEADER_LIST_SIZE: 65536,
        # This one's here because h2 helpfully populates remote_settings
        # with default values even if the peer doesn't send the setting.
        SettingCodes.ENABLE_CONNECT_PROTOCOL: 0,
    }
    assert dict(h2_conn.remote_settings) == expected_settings

    # We don't expect the ENABLE_CONNECT_PROTOCOL to be in the handshake
    expected_settings.pop(SettingCodes.ENABLE_CONNECT_PROTOCOL)

    assert len(backend.server.settings_changed) == 1
    settings = backend.server.settings_changed[0]

    assert isinstance(settings, h2.events.RemoteSettingsChanged)
    assert len(settings.changed_settings) == len(expected_settings)
    for setting_code, changed_setting in settings.changed_settings.items():
        assert isinstance(changed_setting, h2.settings.ChangedSetting)
        assert changed_setting.new_value == expected_settings[setting_code]
示例#3
0
async def test_http2_get_request():
    backend = MockHTTP2Backend(app=app)
    dispatch = ConnectionPool(backend=backend, http2=True)

    async with AsyncClient(dispatch=dispatch) as client:
        response = await client.get("http://example.org")

    assert response.status_code == 200
    assert json.loads(response.content) == {"method": "GET", "path": "/", "body": ""}
示例#4
0
async def test_premature_response_close(server):
    """
    A premature close should close the connection.
    """
    async with ConnectionPool() as http:
        response = await http.request("GET", server.url)
        await response.aclose()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 0
示例#5
0
async def test_close_connections(server):
    """
    Using a `Connection: close` header should close the connection.
    """
    headers = [(b"connection", b"close")]
    async with ConnectionPool() as http:
        response = await http.request("GET", server.url, headers=headers)
        await response.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 0
示例#6
0
async def test_standard_response_close(server):
    """
    A standard close should keep the connection open.
    """
    async with ConnectionPool() as http:
        response = await http.request("GET", server.url)
        await response.aread()
        await response.aclose()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1
示例#7
0
async def test_streaming_response_holds_connection(server):
    """
    A streaming request should hold the connection open until the response is read.
    """
    async with ConnectionPool() as http:
        response = await http.request("GET", server.url)
        assert len(http.active_connections) == 1
        assert len(http.keepalive_connections) == 0

        await response.aread()

        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1
示例#8
0
async def test_http2_large_post_request():
    backend = MockHTTP2Backend(app=app)
    dispatch = ConnectionPool(backend=backend, http2=True)

    data = b"a" * 100000
    async with AsyncClient(dispatch=dispatch) as client:
        response = await client.post("http://example.org", data=data)
    assert response.status_code == 200
    assert json.loads(response.content) == {
        "method": "POST",
        "path": "/",
        "body": data.decode(),
    }
示例#9
0
async def test_keepalive_connections(server):
    """
    Connections should default to staying in a keep-alive state.
    """
    async with ConnectionPool() as http:
        response = await http.request("GET", server.url)
        await response.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1

        response = await http.request("GET", server.url)
        await response.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1
示例#10
0
async def test_differing_connection_keys(server):
    """
    Connections to differing connection keys should result in multiple connections.
    """
    async with ConnectionPool() as http:
        response = await http.request("GET", server.url)
        await response.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1

        response = await http.request("GET", "http://localhost:8000/")
        await response.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 2
示例#11
0
async def test_connection_closed_free_semaphore_on_acquire(server):
    """
    Verify that max_connections semaphore is released
    properly on a disconnected connection.
    """
    async with ConnectionPool(pool_limits=httpx.PoolLimits(
            hard_limit=1)) as http:
        response = await http.request("GET", server.url)
        await response.aread()

        # Close the connection so we're forced to recycle it
        await server.restart()

        response = await http.request("GET", server.url)
        assert response.status_code == 200
示例#12
0
async def test_soft_limit(server):
    """
    The soft_limit config should limit the maximum number of keep-alive connections.
    """
    pool_limits = httpx.PoolLimits(soft_limit=1)

    async with ConnectionPool(pool_limits=pool_limits) as http:
        response = await http.request("GET", server.url)
        await response.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1

        response = await http.request("GET", "http://localhost:8000/")
        await response.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1
示例#13
0
async def test_keepalive_connection_closed_by_server_is_reestablished(server):
    """
    Upon keep-alive connection closed by remote a new connection
    should be reestablished.
    """
    async with ConnectionPool() as http:
        response = await http.request("GET", server.url)
        await response.aread()

        # Shutdown the server to close the keep-alive connection
        await server.restart()

        response = await http.request("GET", server.url)
        await response.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 1
示例#14
0
async def test_http2_multiple_requests():
    backend = MockHTTP2Backend(app=app)
    dispatch = ConnectionPool(backend=backend, http2=True)

    async with AsyncClient(dispatch=dispatch) as client:
        response_1 = await client.get("http://example.org/1")
        response_2 = await client.get("http://example.org/2")
        response_3 = await client.get("http://example.org/3")

    assert response_1.status_code == 200
    assert json.loads(response_1.content) == {"method": "GET", "path": "/1", "body": ""}

    assert response_2.status_code == 200
    assert json.loads(response_2.content) == {"method": "GET", "path": "/2", "body": ""}

    assert response_3.status_code == 200
    assert json.loads(response_3.content) == {"method": "GET", "path": "/3", "body": ""}
示例#15
0
async def test_http2_reconnect():
    """
    If a connection has been dropped between requests, then we should
    be seemlessly reconnected.
    """
    backend = MockHTTP2Backend(app=app)
    dispatch = ConnectionPool(backend=backend, http2=True)

    async with AsyncClient(dispatch=dispatch) as client:
        response_1 = await client.get("http://example.org/1")
        backend.server.close_connection = True
        response_2 = await client.get("http://example.org/2")

    assert response_1.status_code == 200
    assert json.loads(response_1.content) == {"method": "GET", "path": "/1", "body": ""}

    assert response_2.status_code == 200
    assert json.loads(response_2.content) == {"method": "GET", "path": "/2", "body": ""}
示例#16
0
async def test_multiple_concurrent_connections(server):
    """
    Multiple concurrent requests should open multiple concurrent connections.
    """
    async with ConnectionPool() as http:
        response_a = await http.request("GET", server.url)
        assert len(http.active_connections) == 1
        assert len(http.keepalive_connections) == 0

        response_b = await http.request("GET", server.url)
        assert len(http.active_connections) == 2
        assert len(http.keepalive_connections) == 0

        await response_b.aread()
        assert len(http.active_connections) == 1
        assert len(http.keepalive_connections) == 1

        await response_a.aread()
        assert len(http.active_connections) == 0
        assert len(http.keepalive_connections) == 2
示例#17
0
async def test_connection_pool_closed_close_keepalive_and_free_semaphore(
        server):
    """
    Closing the connection pool should close remaining keepalive connections and
    release the max_connections semaphore.
    """
    http = ConnectionPool(pool_limits=httpx.PoolLimits(hard_limit=1))

    async with http:
        response = await http.request("GET", server.url)
        await response.aread()
        assert response.status_code == 200
        assert len(http.keepalive_connections) == 1

    assert len(http.keepalive_connections) == 0

    # Perform a second round of requests to make sure the max_connections semaphore
    # was released properly.
    async with http:
        response = await http.request("GET", server.url)
        await response.aread()
        assert response.status_code == 200