class BaseClient(Generic[SessionT], HookableMixin, metaclass=abc.ABCMeta): '''Base client.''' class ClientEvent(enum.Enum): new_session = 'new_session' def __init__(self, connection_pool: Optional[ConnectionPool] = None): ''' Args: connection_pool: Connection pool. ''' super().__init__() if connection_pool is not None: self._connection_pool = connection_pool else: self._connection_pool = ConnectionPool() self.event_dispatcher.register(self.ClientEvent.new_session) @abc.abstractmethod def _session_class(self) -> Callable[[], SessionT]: '''Return session class.''' return BaseSession # return something for code checkers def session(self) -> SessionT: '''Return a new session.''' session = self._session_class()( connection_pool=self._connection_pool, ) self.event_dispatcher.notify(self.ClientEvent.new_session, session) return session def close(self): '''Close the connection pool.''' _logger.debug('Client closing.') self._connection_pool.close()
def test_multiple_hosts(self): pool = ConnectionPool(max_host_count=5, max_count=20) for port in range(10): session = yield from pool.session('localhost', port) with session as connection: self.assertTrue(connection)
def test_host_max_limit(self): pool = ConnectionPool(max_host_count=2) yield from pool.acquire('localhost', self.get_http_port()) yield from pool.acquire('localhost', self.get_http_port()) with self.assertRaises(asyncio.TimeoutError): yield from asyncio.wait_for( pool.acquire('localhost', self.get_http_port()), 0.1)
def test_clean(self): pool = ConnectionPool(max_host_count=2) conn1 = yield from pool.acquire('localhost', self.get_http_port()) conn2 = yield from pool.acquire('localhost', self.get_http_port()) yield from pool.release(conn1) yield from pool.release(conn2) yield from pool.clean() self.assertEqual(0, len(pool.host_pools))
def __init__(self, connection_pool: Optional[ConnectionPool] = None): ''' Args: connection_pool: Connection pool. ''' super().__init__() if connection_pool is not None: self._connection_pool = connection_pool else: self._connection_pool = ConnectionPool() self.event_dispatcher.register(self.ClientEvent.new_session)
def test_session(self): pool = ConnectionPool() for dummy in range(10): session = yield from \ pool.session('localhost', self.get_http_port()) with session as connection: if connection.closed(): yield from connection.connect() self.assertEqual(1, len(pool.host_pools)) host_pool = list(pool.host_pools.values())[0] self.assertIsInstance(host_pool, HostPool) self.assertEqual(1, host_pool.count())
def test_connection_pool_release_clean_race_condition(self): pool = ConnectionPool(max_host_count=1) connection = yield from pool.acquire('127.0.0.1', 1234) connection_2_task = asyncio. async (pool.acquire('127.0.0.1', 1234)) yield from asyncio.sleep(0.01) pool.no_wait_release(connection) yield from pool.clean(force=True) connection_2 = yield from connection_2_task # This line should not KeyError crash: yield from pool.release(connection_2)
def __init__(self, connection_pool: Optional[ConnectionPool]=None): ''' Args: connection_pool: Connection pool. ''' super().__init__() if connection_pool is not None: self._connection_pool = connection_pool else: self._connection_pool = ConnectionPool() self.event_dispatcher.register(self.ClientEvent.new_session)
class BaseClient(Generic[SessionT], HookableMixin, metaclass=abc.ABCMeta): '''Base client.''' class ClientEvent(enum.Enum): new_session = 'new_session' def __init__(self, connection_pool: Optional[ConnectionPool]=None): ''' Args: connection_pool: Connection pool. ''' super().__init__() if connection_pool is not None: self._connection_pool = connection_pool else: self._connection_pool = ConnectionPool() self.event_dispatcher.register(self.ClientEvent.new_session) @abc.abstractmethod def _session_class(self) -> Callable[[], SessionT]: '''Return session class.''' return BaseSession # return something for code checkers def session(self) -> SessionT: '''Return a new session.''' session = self._session_class()( connection_pool=self._connection_pool, ) self.event_dispatcher.notify(self.ClientEvent.new_session, session) return session def close(self): '''Close the connection pool.''' _logger.debug('Client closing.') self._connection_pool.close()
def test_client_exception_recovery(self): connection_factory = functools.partial(Connection, timeout=2.0) connection_pool = ConnectionPool(connection_factory=connection_factory) client = Client(connection_pool=connection_pool) for dummy in range(7): with self.assertRaises(NetworkError), client.session() as session: request = Request(self.get_url('/header_early_close')) yield from session.start(request) for dummy in range(7): with client.session() as session: request = Request(self.get_url('/')) response = yield from session.start(request) self.assertEqual(200, response.status_code) yield from session.download() self.assertTrue(session.done())
def test_basic_acquire(self): pool = ConnectionPool(max_host_count=2) conn1 = yield from pool.acquire('localhost', self.get_http_port()) conn2 = yield from pool.acquire('localhost', self.get_http_port()) yield from pool.release(conn1) yield from pool.release(conn2) conn3 = yield from pool.acquire('localhost', self.get_http_port()) conn4 = yield from pool.acquire('localhost', self.get_http_port()) yield from pool.release(conn3) yield from pool.release(conn4)
def test_over_host_max_limit_cycling(self): pool = ConnectionPool(max_host_count=10, max_count=10) @asyncio.coroutine def con_fut(): session = yield from \ pool.session('localhost', self.get_http_port()) with session as connection: if connection.closed(): yield from connection.connect() futs = [con_fut() for dummy in range(20)] yield from asyncio.wait(futs) self.assertEqual(1, len(pool.host_pools)) connection_pool_entry = list(pool.host_pools.values())[0] self.assertIsInstance(connection_pool_entry, HostPool) self.assertGreaterEqual(10, connection_pool_entry.count())
def test_happy_eyeballs(self): connection_factory = functools.partial(Connection, connect_timeout=10) resolver = Resolver() pool = ConnectionPool(resolver=resolver, connection_factory=connection_factory) conn1 = yield from pool.acquire('google.com', 80) conn2 = yield from pool.acquire('google.com', 80) yield from conn1.connect() yield from conn2.connect() conn1.close() conn2.close() yield from pool.release(conn1) yield from pool.release(conn2) conn3 = yield from pool.acquire('google.com', 80) yield from conn3.connect() conn3.close() yield from pool.release(conn3)