예제 #1
0
    def __init__(
        self,
        run_mode: RunMode = RunMode.THREAD,
        loop: Optional[asyncio.AbstractEventLoop] = None,
        ssl_verify: Optional[Union[bool, str]] = None,
        ssl_cert: Optional[Union[str, Sequence[str]]] = None,
    ) -> None:
        """Instantiate a client using the given run_mode. If you do not pass in an event loop, then
        either a shared loop in a separate thread (THREAD mode) or the default asyncio
        event loop (FULL_ASYNCIO mode) will be used.
        Not passing in an event loop will make sure we share the :py:class:`aiohttp.ClientSession` object
        between AsyncioClient instances.

        :param ssl_verify: Set to False to disable SSL certificate validation. Provide the path to a
            CA bundle if you need to use a custom one.
        :param ssl_cert: Provide a client-side certificate to use. Either a sequence of strings pointing
            to the certificate (1) and the private key (2), or a string pointing to the combined certificate
            and key.
        """
        self.run_mode = run_mode
        if self.run_mode == RunMode.THREAD:
            self.loop = loop or get_thread_loop()
            self.run_coroutine_func = asyncio.run_coroutine_threadsafe  # type: Callable
            self.response_adapter = AioHTTPResponseAdapter
            self.bravado_future_class = HttpFuture
            self.future_adapter = FutureAdapter  # type: Type[BaseFutureAdapter]
        elif run_mode == RunMode.FULL_ASYNCIO:
            from aiobravado.http_future import HttpFuture as AsyncioHttpFuture

            self.loop = loop or asyncio.get_event_loop()
            self.run_coroutine_func = asyncio.ensure_future
            self.response_adapter = AsyncioHTTPResponseAdapter
            self.bravado_future_class = AsyncioHttpFuture
            self.future_adapter = AsyncioFutureAdapter
        else:
            raise ValueError("Don't know how to handle run mode {}".format(
                str(run_mode)))

        # don't use the shared client_session if we've been passed an explicit loop argument
        if loop:
            self.client_session = aiohttp.ClientSession(loop=loop)
        else:
            self.client_session = get_client_session(self.loop)

        # translate the requests-type SSL options to a ssl.SSLContext object as used by aiohttp.
        # see https://aiohttp.readthedocs.io/en/stable/client_advanced.html#ssl-control-for-tcp-sockets
        if isinstance(ssl_verify, str) or ssl_cert:
            self.ssl_verify = None  # type: Optional[bool]
            cafile = None
            if isinstance(ssl_verify, str):
                cafile = ssl_verify
            self.ssl_context = ssl.create_default_context(
                cafile=cafile)  # type: Optional[ssl.SSLContext]
            if ssl_cert:
                if isinstance(ssl_cert, str):
                    ssl_cert = [ssl_cert]
                self.ssl_context.load_cert_chain(*ssl_cert)
        else:
            self.ssl_verify = ssl_verify
            self.ssl_context = None
예제 #2
0
def test_client_from_asyncio(integration_server):
    """Let's make sure that the event loop for our HTTP client that runs in a different thread
    behaves properly with the 'standard' asyncio loop that people would normally use when doing
    asynchronous programming. While we're at it, let's also make sure two instances of
    AsyncioClient work well together."""
    # recreate the separate event loop and client session for the HTTP client so we start with a clean slate
    # this is important since we measure the time this test takes, and the test_timeout() tasks might
    # interfere with it
    loop = thread_loop.get_thread_loop()
    if http_client.client_session:
        run_coroutine_threadsafe(http_client.client_session.close(), loop)
    http_client.client_session = None
    # not going to properly shut down the running loop, this will be cleaned up on exit
    thread_loop.event_loop = None

    # get a second event loop running in the current thread; we'll use this one to run the test
    loop = asyncio.get_event_loop()
    start_time = time.time()
    loop.run_until_complete(_test_asyncio_client(integration_server))
    end_time = time.time()

    # There are three things being executed asynchronously:
    # 1. sleep 1 second in the main event loop
    # 2. fetch the response for client1 (the server sleeps 1 second)
    # 3. fetch the response for client2 (the server sleeps 1 second)
    # All of this combined should take only a bit more than one second.
    # While this assertion could become flaky depending on how busy the system that runs the test
    # is for now it's a nice confirmation that things work as expected. We can remove it later if
    # it becomes a problem.
    assert end_time - start_time < 2
예제 #3
0
 def loop(self) -> asyncio.AbstractEventLoop:
     if self._loop is not None:
         return self._loop
     elif self.run_mode == RunMode.THREAD:
         return get_thread_loop()
     elif self.run_mode == RunMode.FULL_ASYNCIO:
         return asyncio.get_event_loop()
     else:  # pragma: no cover
         # should be impossible because this is validated by __init__
         raise ValueError(self.run_mode)