def test_merge_pool_kwargs_none(self): """Assert false-y values to _merge_pool_kwargs result in defaults""" p = PoolManager(strict=True) merged = p._merge_pool_kwargs({}) assert p.connection_pool_kw == merged merged = p._merge_pool_kwargs(None) assert p.connection_pool_kw == merged
def test_assert_hostname_and_fingerprint_flag(self): """Assert that pool manager can accept hostname and fingerprint flags.""" fingerprint = "92:81:FE:85:F7:0C:26:60:EC:D6:B3:BF:93:CF:F9:71:CC:07:7D:0A" p = PoolManager(assert_hostname=True, assert_fingerprint=fingerprint) pool = p.connection_from_url("https://example.com/") assert 1 == len(p.pools) assert pool.assert_hostname assert fingerprint == pool.assert_fingerprint
def test_http_connection_from_host_case_insensitive(self): """Assert scheme case is ignored when getting the https key class.""" p = PoolManager() pool = p.connection_from_host("example.com", scheme="http") other_pool = p.connection_from_host("EXAMPLE.COM", scheme="HTTP") assert 1 == len(p.pools) assert pool is other_pool assert all(isinstance(key, PoolKey) for key in p.pools.keys())
def test_http_connection_from_url_case_insensitive(self): """Assert scheme case is ignored when pooling HTTP connections.""" p = PoolManager() pool = p.connection_from_url("http://example.com/") other_pool = p.connection_from_url("HTTP://EXAMPLE.COM/") assert 1 == len(p.pools) assert pool is other_pool assert all(isinstance(key, PoolKey) for key in p.pools.keys())
def test_https_pool_key_fields(self): """Assert the HTTPSPoolKey fields are honored when selecting a pool.""" connection_pool_kw = [ ("timeout", timeout.Timeout(3.14)), ("retries", retry.Retry(total=6, connect=2)), ("block", True), ("source_address", "127.0.0.1"), ("key_file", DEFAULT_CERTS["keyfile"]), ("cert_file", DEFAULT_CERTS["certfile"]), ("cert_reqs", "CERT_REQUIRED"), ("ca_certs", DEFAULT_CA), ("ca_cert_dir", CERTS_PATH), ("ssl_version", "SSLv23"), ("ssl_context", ssl_.create_ssl_context()), ] p = PoolManager() conn_pools = [ p.connection_from_url("https://example.com/"), p.connection_from_url("https://example.com:4333/"), p.connection_from_url("https://other.example.com/"), ] # Asking for a connection pool with the same key should give us an # existing pool. dup_pools = [] for key, value in connection_pool_kw: p.connection_pool_kw[key] = value conn_pools.append(p.connection_from_url("https://example.com/")) dup_pools.append(p.connection_from_url("https://example.com/")) assert all(x is not y for i, x in enumerate(conn_pools) for j, y in enumerate(conn_pools) if i != j) assert all(pool in conn_pools for pool in dup_pools) assert all(isinstance(key, PoolKey) for key in p.pools.keys())
def test_override_pool_kwargs_url(self): """Assert overriding pool kwargs works with connection_from_url.""" p = PoolManager(block=False) pool_kwargs = {"retries": 100, "block": True} default_pool = p.connection_from_url("http://example.com/") override_pool = p.connection_from_url("http://example.com/", pool_kwargs=pool_kwargs) assert retry.Retry.DEFAULT == default_pool.retries assert not default_pool.block assert 100 == override_pool.retries assert override_pool.block
def test_http_connection_from_context_case_insensitive(self): """Assert scheme case is ignored when getting the https key class.""" p = PoolManager() context = {"scheme": "http", "host": "example.com", "port": "8080"} other_context = { "scheme": "HTTP", "host": "EXAMPLE.COM", "port": "8080" } pool = p.connection_from_context(context) other_pool = p.connection_from_context(other_context) assert 1 == len(p.pools) assert pool is other_pool assert all(isinstance(key, PoolKey) for key in p.pools.keys())
def test_redirect_after(self): with PoolManager() as http: r = http.request("GET", "%s/redirect_after" % self.base_url, retries=False) assert r.status == 303 t = time.time() r = http.request("GET", "%s/redirect_after" % self.base_url) assert r.status == 200 delta = time.time() - t assert delta >= 1 t = time.time() timestamp = t + 2 r = http.request( "GET", self.base_url + "/redirect_after?date=" + str(timestamp) ) assert r.status == 200 delta = time.time() - t assert delta >= 1 # Retry-After is past t = time.time() timestamp = t - 1 r = http.request( "GET", self.base_url + "/redirect_after?date=" + str(timestamp) ) delta = time.time() - t assert r.status == 200 assert delta < 1
def test_disabled_retry(self): """ Disabled retries should disable redirect handling. """ with PoolManager() as http: r = http.request( "GET", "%s/redirect" % self.base_url, fields={"target": "/"}, retries=False, ) assert r.status == 303 r = http.request( "GET", "%s/redirect" % self.base_url, fields={"target": "/"}, retries=Retry(redirect=False), ) assert r.status == 303 with pytest.raises(NewConnectionError): http.request( "GET", "http://thishostdoesnotexist.invalid/", timeout=0.001, retries=False, )
def test_headers(self): with PoolManager(headers={"Foo": "bar"}) as http: r = http.request("GET", "%s/headers" % self.base_url) returned_headers = json.loads(r.data.decode()) assert returned_headers.get("Foo") == "bar" r = http.request("POST", "%s/headers" % self.base_url) returned_headers = json.loads(r.data.decode()) assert returned_headers.get("Foo") == "bar" r = http.request_encode_url("GET", "%s/headers" % self.base_url) returned_headers = json.loads(r.data.decode()) assert returned_headers.get("Foo") == "bar" r = http.request_encode_body("POST", "%s/headers" % self.base_url) returned_headers = json.loads(r.data.decode()) assert returned_headers.get("Foo") == "bar" r = http.request_encode_url( "GET", "%s/headers" % self.base_url, headers={"Baz": "quux"} ) returned_headers = json.loads(r.data.decode()) assert returned_headers.get("Foo") is None assert returned_headers.get("Baz") == "quux" r = http.request_encode_body( "GET", "%s/headers" % self.base_url, headers={"Baz": "quux"} ) returned_headers = json.loads(r.data.decode()) assert returned_headers.get("Foo") is None assert returned_headers.get("Baz") == "quux"
def test_pool_kwargs_socket_options(self): """Assert passing socket options works with connection_from_host""" p = PoolManager(socket_options=[]) override_opts = [ (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1), (socket.IPPROTO_TCP, socket.TCP_NODELAY, 1), ] pool_kwargs = {"socket_options": override_opts} default_pool = p.connection_from_host("example.com", scheme="http") override_pool = p.connection_from_host("example.com", scheme="http", pool_kwargs=pool_kwargs) assert default_pool.conn_kw["socket_options"] == [] assert override_pool.conn_kw["socket_options"] == override_opts
def test_raise_on_status(self): with PoolManager() as http: with pytest.raises(MaxRetryError): # the default is to raise r = http.request( "GET", "%s/status" % self.base_url, fields={"status": "500 Internal Server Error"}, retries=Retry(total=1, status_forcelist=range(500, 600)), ) with pytest.raises(MaxRetryError): # raise explicitly r = http.request( "GET", "%s/status" % self.base_url, fields={"status": "500 Internal Server Error"}, retries=Retry( total=1, status_forcelist=range(500, 600), raise_on_status=True ), ) # don't raise r = http.request( "GET", "%s/status" % self.base_url, fields={"status": "500 Internal Server Error"}, retries=Retry( total=1, status_forcelist=range(500, 600), raise_on_status=False ), ) assert r.status == 500
def test_redirect_cross_host_set_removed_headers(self): with PoolManager() as http: r = http.request( "GET", "%s/redirect" % self.base_url, fields={"target": "%s/headers" % self.base_url_alt}, headers={"X-API-Secret": "foo", "Authorization": "bar"}, retries=Retry(remove_headers_on_redirect=["X-API-Secret"]), ) assert r.status == 200 data = json.loads(r.data.decode("utf-8")) assert "X-API-Secret" not in data assert data["Authorization"] == "bar" r = http.request( "GET", "%s/redirect" % self.base_url, fields={"target": "%s/headers" % self.base_url_alt}, headers={"x-api-secret": "foo", "authorization": "bar"}, retries=Retry(remove_headers_on_redirect=["X-API-Secret"]), ) assert r.status == 200 data = json.loads(r.data.decode("utf-8")) assert "x-api-secret" not in data assert "X-API-Secret" not in data assert data["Authorization"] == "bar"
def test_multi_redirect_history(self): with PoolManager() as http: r = http.request( "GET", "%s/multi_redirect" % self.base_url, fields={"redirect_codes": "303,302,200"}, redirect=False, ) assert r.status == 303 assert r.retries.history == tuple() r = http.request( "GET", "%s/multi_redirect" % self.base_url, retries=10, fields={"redirect_codes": "303,302,301,307,302,200"}, ) assert r.status == 200 assert r.data == b"Done redirecting" expected = [ (303, "/multi_redirect?redirect_codes=302,301,307,302,200"), (302, "/multi_redirect?redirect_codes=301,307,302,200"), (301, "/multi_redirect?redirect_codes=307,302,200"), (307, "/multi_redirect?redirect_codes=302,200"), (302, "/multi_redirect?redirect_codes=200"), ] actual = [ (history.status, history.redirect_location) for history in r.retries.history ] assert actual == expected
def test_redirect_cross_host_remove_headers(self): with PoolManager() as http: r = http.request( "GET", "%s/redirect" % self.base_url, fields={"target": "%s/headers" % self.base_url_alt}, headers={"Authorization": "foo"}, ) assert r.status == 200 data = json.loads(r.data.decode("utf-8")) assert "Authorization" not in data r = http.request( "GET", "%s/redirect" % self.base_url, fields={"target": "%s/headers" % self.base_url_alt}, headers={"authorization": "foo"}, ) assert r.status == 200 data = json.loads(r.data.decode("utf-8")) assert "authorization" not in data assert "Authorization" not in data
def test_read_retries_unsuccessful(self): headers = {"test-name": "test_read_retries_unsuccessful"} with PoolManager() as http: resp = http.request( "GET", "%s/successful_retry" % self.base_url, headers=headers, retries=1 ) assert resp.status == 418
def test_max_retry(self): with PoolManager() as http: with pytest.raises(MaxRetryError): http.request( "GET", "%s/redirect" % self.base_url, fields={"target": "/"}, retries=0, )
def test_retry_redirect_history(self): with PoolManager() as http: resp = http.request( "GET", "%s/redirect" % self.base_url, fields={"target": "/"} ) assert resp.status == 200 assert resp.retries.history == ( RequestHistory( "GET", self.base_url + "/redirect?target=%2F", None, 303, "/" ), )
def test_manager_clear(self): p = PoolManager(5) conn_pool = p.connection_from_url("http://google.com") assert len(p.pools) == 1 conn = conn_pool._get_conn() p.clear() assert len(p.pools) == 0 with pytest.raises(ClosedPoolError): conn_pool._get_conn() conn_pool._put_conn(conn) with pytest.raises(ClosedPoolError): conn_pool._get_conn() assert len(p.pools) == 0
def test_many_urls(self): urls = [ "http://localhost:8081/foo", "http://www.google.com/mail", "http://localhost:8081/bar", "https://www.google.com/", "https://www.google.com/mail", "http://yahoo.com", "http://bing.com", "http://yahoo.com/", ] connections = set() p = PoolManager(10) for url in urls: conn = p.connection_from_url(url) connections.add(conn) assert len(connections) == 5
def test_retries_wrong_whitelist(self): """HTTP response w/ status code not in whitelist shouldn't be retried""" retry = Retry(total=1, status_forcelist=[202]) with PoolManager() as http: resp = http.request( "GET", "%s/successful_retry" % self.base_url, headers={"test-name": "test_wrong_whitelist"}, retries=retry, ) assert resp.status == 418
def test_raise_on_redirect(self): with PoolManager() as http: r = http.request( "GET", "%s/redirect" % self.base_url, fields={ "target": "%s/redirect?target=%s/" % (self.base_url, self.base_url) }, retries=Retry(total=None, redirect=1, raise_on_redirect=False), ) assert r.status == 303
def test_read_retries(self): """ Should retry for status codes in the whitelist """ retry = Retry(read=1, status_forcelist=[418]) with PoolManager() as http: resp = http.request( "GET", "%s/successful_retry" % self.base_url, headers={"test-name": "test_read_retries"}, retries=retry, ) assert resp.status == 200
def test_default_method_whitelist_retried(self): """Hip should retry methods in the default method whitelist""" retry = Retry(total=1, status_forcelist=[418]) with PoolManager() as http: resp = http.request( "OPTIONS", "%s/successful_retry" % self.base_url, headers={"test-name": "test_default_whitelist"}, retries=retry, ) assert resp.status == 200
def test_pools_keyed_with_from_host(self): """Assert pools are still keyed correctly with connection_from_host.""" ssl_kw = [ ("key_file", DEFAULT_CERTS["keyfile"]), ("cert_file", DEFAULT_CERTS["certfile"]), ("cert_reqs", "CERT_REQUIRED"), ("ca_certs", DEFAULT_CA), ("ca_cert_dir", CERTS_PATH), ("ssl_version", "SSLv23"), ("ssl_context", ssl_.create_ssl_context()), ] p = PoolManager() conns = [p.connection_from_host("example.com", 443, scheme="https")] for k, v in ssl_kw: p.connection_pool_kw[k] = v conns.append( p.connection_from_host("example.com", 443, scheme="https")) assert all(x is not y for i, x in enumerate(conns) for j, y in enumerate(conns) if i != j)
def test_read_total_retries(self): """ HTTP response w/ status code in the whitelist should be retried """ headers = {"test-name": "test_read_total_retries"} retry = Retry(total=1, status_forcelist=[418]) with PoolManager() as http: resp = http.request( "GET", "%s/successful_retry" % self.base_url, headers=headers, retries=retry, ) assert resp.status == 200
def test_retries_wrong_method_list(self): """Method not in our whitelist should not be retried, even if code matches""" headers = {"test-name": "test_wrong_method_whitelist"} retry = Retry(total=1, status_forcelist=[418], method_whitelist=["POST"]) with PoolManager() as http: resp = http.request( "GET", "%s/successful_retry" % self.base_url, headers=headers, retries=retry, ) assert resp.status == 418
def test_redirect_cross_host_no_remove_headers(self): with PoolManager() as http: r = http.request( "GET", "%s/redirect" % self.base_url, fields={"target": "%s/headers" % self.base_url_alt}, headers={"Authorization": "foo"}, retries=Retry(remove_headers_on_redirect=[]), ) assert r.status == 200 data = json.loads(r.data.decode("utf-8")) assert data["Authorization"] == "foo"
def test_retry_return_in_response(self): headers = {"test-name": "test_retry_return_in_response"} retry = Retry(total=2, status_forcelist=[418]) with PoolManager() as http: resp = http.request( "GET", "%s/successful_retry" % self.base_url, headers=headers, retries=retry, ) assert resp.status == 200 assert resp.retries.total == 1 assert resp.retries.history == ( RequestHistory("GET", "/successful_retry", None, 418, None), )
def test_missing_port(self): # Can a URL that lacks an explicit port like ':80' succeed, or # will all such URLs fail with an error? with PoolManager() as http: # By globally adjusting `DEFAULT_PORTS` we pretend for a moment # that HTTP's default port is not 80, but is the port at which # our test server happens to be listening. DEFAULT_PORTS["http"] = self.port try: r = http.request("GET", "http://%s/" % self.host, retries=0) finally: DEFAULT_PORTS["http"] = 80 assert r.status == 200 assert r.data == b"Dummy server!"