Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into clean-up-integratio…
Browse files Browse the repository at this point in the history
…n-tests
  • Loading branch information
sjaensch committed Feb 22, 2019
2 parents 0d46d8d + 121fdc0 commit ad87a22
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 21 deletions.
15 changes: 14 additions & 1 deletion bravado_asyncio/future_adapter.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import asyncio
import concurrent.futures
import time
from typing import Any
from typing import Optional

import aiohttp.client_exceptions
from bravado.http_future import FutureAdapter as BaseFutureAdapter
from bravado.http_future import FutureAdapter as BravadoFutureAdapter

from bravado_asyncio.definitions import AsyncioResponse


class BaseFutureAdapter(BravadoFutureAdapter):

def __init__(self, future: Any) -> None:
raise NotImplementedError('Do not instantiate BaseFutureAdapter, use one of its subclasses')


class FutureAdapter(BaseFutureAdapter):
"""FutureAdapter that will be used when run_mode is THREAD. The result method is
a normal Python function, and we expect future to be from the concurrent.futures module."""
Expand All @@ -27,6 +34,9 @@ def result(self, timeout: Optional[float] = None) -> AsyncioResponse:

return AsyncioResponse(response=response, remaining_timeout=remaining_timeout)

def cancel(self) -> None:
self.future.cancel()


class AsyncioFutureAdapter(BaseFutureAdapter):
"""FutureAdapter that will be used when run_mode is FULL_ASYNCIO. The result method is
Expand All @@ -45,3 +55,6 @@ async def result(self, timeout: Optional[float] = None) -> AsyncioResponse:
remaining_timeout = timeout - time_elapsed if timeout else None

return AsyncioResponse(response=response, remaining_timeout=remaining_timeout)

def cancel(self) -> None:
self.future.cancel()
8 changes: 5 additions & 3 deletions bravado_asyncio/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
from typing import Callable # noqa: F401
from typing import cast
from typing import Dict
from typing import MutableMapping
from typing import Optional
from typing import Sequence
from typing import Type
from typing import Union

import aiohttp
Expand All @@ -23,12 +25,12 @@

from bravado_asyncio.definitions import RunMode
from bravado_asyncio.future_adapter import AsyncioFutureAdapter
from bravado_asyncio.future_adapter import BaseFutureAdapter
from bravado_asyncio.future_adapter import FutureAdapter
from bravado_asyncio.response_adapter import AioHTTPResponseAdapter
from bravado_asyncio.response_adapter import AsyncioHTTPResponseAdapter
from bravado_asyncio.thread_loop import get_thread_loop


log = logging.getLogger(__name__)


Expand Down Expand Up @@ -83,7 +85,7 @@ def __init__(
self.run_coroutine_func = asyncio.run_coroutine_threadsafe # type: Callable
self.response_adapter = AioHTTPResponseAdapter
self.bravado_future_class = HttpFuture
self.future_adapter = FutureAdapter # type: http_future.FutureAdapter
self.future_adapter = FutureAdapter # type: Type[BaseFutureAdapter]
elif run_mode == RunMode.FULL_ASYNCIO:
from aiobravado.http_future import HttpFuture as AsyncioHttpFuture

Expand Down Expand Up @@ -119,7 +121,7 @@ def __init__(

def request(
self,
request_params: Dict[str, Any],
request_params: MutableMapping[str, Any],
operation: Optional[Operation] = None,
request_config: Optional[RequestConfig] = None,
) -> HttpFuture:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
],
install_requires=[
'aiohttp>=3.3',
'bravado>=10.0.0',
'bravado>=10.3.0',
'yelp-bytes',
],
extras_require={
Expand Down
3 changes: 0 additions & 3 deletions tests/integration/bravado_integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ class TestServerBravadoAsyncioClient(IntegrationTestsBaseClass):
aiohttp.ClientConnectionError(),
}

def cancel_http_future(self, http_future):
http_future.future.future.cancel()

def test_bytes_header(self, swagger_http_server):
# TODO: integrate this test into bravado integration tests suite
response = self.http_client.request({
Expand Down
34 changes: 21 additions & 13 deletions tests/integration/integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os.path
import time
from asyncio import run_coroutine_threadsafe
from concurrent.futures import CancelledError

import pytest
from bravado import requests_client
Expand All @@ -23,10 +24,15 @@ def swagger_client(integration_server, request):
# to make sure they both behave the same.
# Once this integration suite has become stable (i.e. we're happy with the approach and the test coverage)
# it could move to bravado and test all major HTTP clients (requests, fido, asyncio).
spec_url = '{}/swagger.yaml'.format(integration_server)
return get_swagger_client(integration_server, request.param())


def get_swagger_client(server_url, http_client_instance):
spec_url = '{}/swagger.yaml'.format(server_url)
return SwaggerClient.from_url(
spec_url,
http_client=request.param(),
http_client=http_client_instance,
config={'also_return_response': True},
)


Expand Down Expand Up @@ -169,6 +175,17 @@ def test_server_500(swagger_client):
swagger_client.pet.deletePet(petId=42).response(timeout=1)


def test_cancellation(integration_server):
swagger_client = get_swagger_client(integration_server, http_client.AsyncioClient())
bravado_future = swagger_client.store.getInventory() # request takes roughly 1 second to complete
bravado_future.cancel()

with pytest.raises(CancelledError):
bravado_future.result()

bravado_future.cancel() # make sure we can call it again without issues


def test_timeout_request_options(swagger_client):
other_future = swagger_client.pet.getPetById(petId=42)
with pytest.raises(BravadoTimeoutError):
Expand Down Expand Up @@ -227,20 +244,11 @@ async def sleep_coroutine():
return 42


async def get_swagger_client(spec_url):
return SwaggerClient.from_url(
spec_url,
http_client=http_client.AsyncioClient(),
)


async def _test_asyncio_client(integration_server):
spec_url = '{}/swagger.yaml'.format(integration_server)
# schedule our first coroutine (after _test_asyncio_client) in the default event loop
future = asyncio.ensure_future(sleep_coroutine())
# more work for the default event loop
client1 = await get_swagger_client(spec_url)
client2 = await get_swagger_client(spec_url.replace('localhost', '127.0.0.1'))
client1 = get_swagger_client(integration_server, http_client.AsyncioClient())
client2 = get_swagger_client(integration_server.replace('localhost', '127.0.0.1'), http_client.AsyncioClient())

# two tasks for the event loop running in a separate thread
future1 = client1.store.getInventory()
Expand Down

0 comments on commit ad87a22

Please sign in to comment.