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_cross_host_redirect(self): http = PoolManager() self.addCleanup(http.clear) cross_host_location = '%s/echo?a=b' % self.base_url_alt try: http.request('GET', '%s/redirect' % self.base_url, fields={'target': cross_host_location}, timeout=1, retries=0) self.fail( "Request succeeded instead of raising an exception like it should." ) except MaxRetryError: pass r = http.request('GET', '%s/redirect' % self.base_url, fields={'target': '%s/echo?a=b' % self.base_url_alt}, timeout=1, retries=1) self.assertEqual(r._pool.host, self.host_alt)
def test_too_many_redirects(self): http = PoolManager() self.addCleanup(http.clear) try: r = http.request('GET', '%s/redirect' % self.base_url, fields={ 'target': '%s/redirect?target=%s/' % (self.base_url, self.base_url) }, retries=1) self.fail("Failed to raise MaxRetryError exception, returned %r" % r.status) except MaxRetryError: pass try: 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)) self.fail("Failed to raise MaxRetryError exception, returned %r" % r.status) except MaxRetryError: pass
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_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_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_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', DEFAULT_CA_DIR), ('ssl_version', 'SSLv23'), ('ssl_context', ssl_.create_urllib3_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_headers(self): http = PoolManager(headers={'Foo': 'bar'}) self.addCleanup(http.clear) r = http.request('GET', '%s/headers' % self.base_url) returned_headers = json.loads(r.data.decode()) self.assertEqual(returned_headers.get('Foo'), 'bar') r = http.request('POST', '%s/headers' % self.base_url) returned_headers = json.loads(r.data.decode()) self.assertEqual(returned_headers.get('Foo'), 'bar') r = http.request_encode_url('GET', '%s/headers' % self.base_url) returned_headers = json.loads(r.data.decode()) self.assertEqual(returned_headers.get('Foo'), 'bar') r = http.request_encode_body('POST', '%s/headers' % self.base_url) returned_headers = json.loads(r.data.decode()) self.assertEqual(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()) self.assertEqual(returned_headers.get('Foo'), None) self.assertEqual(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()) self.assertEqual(returned_headers.get('Foo'), None) self.assertEqual(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_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_cleanup_on_connection_error(self): ''' Test that connections are recycled to the pool on connection errors where no http response is received. ''' poolsize = 3 with PoolManager(maxsize=poolsize, block=True) as http: pool = http.connection_from_host(self.host, self.port) self.assertEqual(pool.pool.qsize(), poolsize) # force a connection error by supplying a non-existent # url. We won't get a response for this and so the # conn won't be implicitly returned to the pool. url = "%s/redirect" % self.base_url self.assertRaises(MaxRetryError, http.request, 'GET', url, fields={'target': '/'}, retries=0) r = http.request('GET', url, fields={'target': '/'}, retries=1) r.release_conn() # the pool should still contain poolsize elements self.assertEqual(pool.pool.qsize(), poolsize)
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) self.assertEqual(r.status, 303) self.assertEqual(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'}) self.assertEqual(r.status, 200) self.assertEqual(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] self.assertEqual(actual, expected)
def test_redirect_after(self): with PoolManager() as http: r = http.request('GET', '%s/redirect_after' % self.base_url, retries=False) self.assertEqual(r.status, 303) t = time.time() r = http.request('GET', '%s/redirect_after' % self.base_url) self.assertEqual(r.status, 200) delta = time.time() - t self.assertTrue(delta >= 1) t = time.time() timestamp = t + 2 r = http.request( 'GET', self.base_url + '/redirect_after?date=' + str(timestamp)) self.assertEqual(r.status, 200) delta = time.time() - t self.assertTrue(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 self.assertEqual(r.status, 200) self.assertTrue(delta < 1)
def test_raise_on_redirect(self): http = PoolManager() self.addCleanup(http.clear) 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)) self.assertEqual(r.status, 303)
def test_redirect_to_relative_url(self): http = PoolManager() self.addCleanup(http.clear) r = http.request('GET', '%s/redirect' % self.base_url, fields={'target': '/redirect'}, redirect=False) self.assertEqual(r.status, 303) r = http.request('GET', '%s/redirect' % self.base_url, fields={'target': '/redirect'}) self.assertEqual(r.status, 200) self.assertEqual(r.data, b'Dummy server!')
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? http = PoolManager() self.addCleanup(http.clear) # 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 self.assertEqual(r.status, 200) self.assertEqual(r.data, b'Dummy server!')
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) self.assertEqual(resp.status, 418)
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) self.assertEqual(resp.status, 418)
def test_retry_redirect_history(self): with PoolManager() as http: resp = http.request('GET', '%s/redirect' % self.base_url, fields={'target': '/'}) self.assertEqual(resp.status, 200) self.assertEqual( resp.retries.history, (RequestHistory('GET', self.base_url + '/redirect?target=%2F', None, 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) self.assertEqual(resp.status, 200)
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) self.assertEqual(resp.status, 200)
def test_default_method_whitelist_retried(self): """ urllib3 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) self.assertEqual(resp.status, 200)
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_max_retry(self): with PoolManager() as http: try: r = http.request('GET', '%s/redirect' % self.base_url, fields={'target': '/'}, retries=0) self.fail( "Failed to raise MaxRetryError exception, returned %r" % r.status) except MaxRetryError: pass
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) self.assertEqual(resp.status, 200) self.assertEqual(resp.retries.total, 1) self.assertEqual(resp.retries.history, (RequestHistory( 'GET', '/successful_retry', None, 418, None), ))
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) self.assertEqual(resp.status, 418)
def test_raise_on_status(self): http = PoolManager() self.addCleanup(http.clear) try: # 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))) self.fail("Failed to raise MaxRetryError exception, returned %r" % r.status) except MaxRetryError: pass try: # 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)) self.fail("Failed to raise MaxRetryError exception, returned %r" % r.status) except MaxRetryError: pass # 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)) self.assertEqual(r.status, 500)
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', DEFAULT_CA_DIR), ('ssl_version', 'SSLv23'), ('ssl_context', ssl_.create_urllib3_context()), ] p = PoolManager() conns = [] conns.append(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)