Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow custom port to TestServer #2613

Merged
merged 5 commits into from
Dec 18, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* The format is <Name> <Surname>.
* Please keep alphabetical order, the file is sorted by names.
- [ ] Add a new news fragment into the `CHANGES` folder
* name it `<issue_id>.<type>` for example (588.bug)
* name it `<issue_id>.<type>` for example (588.bugfix)
* if you don't have an `issue_id` change it to the pr id after creating the pr
* ensure type is one of the following:
* `.feature`: Signifying a new feature.
Expand Down
1 change: 1 addition & 0 deletions CHANGES/2613.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow a custom port to be used by `TestServer` (and associated pytest fixtures)
8 changes: 4 additions & 4 deletions aiohttp/pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ def test_server(loop):
"""
servers = []

async def go(app, **kwargs):
server = TestServer(app)
async def go(app, *, port=None, **kwargs):
server = TestServer(app, port=port)
await server.start_server(loop=loop, **kwargs)
servers.append(server)
return server
Expand All @@ -248,8 +248,8 @@ def raw_test_server(loop):
"""
servers = []

async def go(handler, **kwargs):
server = RawTestServer(handler)
async def go(handler, *, port=None, **kwargs):
server = RawTestServer(handler, port=port)
await server.start_server(loop=loop, **kwargs)
servers.append(server)
return server
Expand Down
19 changes: 12 additions & 7 deletions aiohttp/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ def unused_port():

class BaseTestServer(ABC):
def __init__(self, *, scheme=sentinel, loop=None,
host='127.0.0.1', skip_url_asserts=False, **kwargs):
host='127.0.0.1', port=None, skip_url_asserts=False,
**kwargs):
self._loop = loop
self.port = None
self.server = None
Expand All @@ -49,14 +50,18 @@ def __init__(self, *, scheme=sentinel, loop=None,
self._closed = False
self.scheme = scheme
self.skip_url_asserts = skip_url_asserts
self.port = port

async def start_server(self, loop=None, **kwargs):
if self.server:
return
self._loop = loop
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.bind((self.host, 0))
self.port = self._socket.getsockname()[1]
if self.port:
self._socket.bind((self.host, self.port))
else:
self._socket.bind((self.host, 0))
self.port = self._socket.getsockname()[1]
self._ssl = kwargs.pop('ssl', None)
if self.scheme is sentinel:
if self._ssl:
Expand Down Expand Up @@ -134,9 +139,9 @@ async def __aexit__(self, exc_type, exc_value, traceback):
class TestServer(BaseTestServer):

def __init__(self, app, *,
scheme=sentinel, host='127.0.0.1', **kwargs):
scheme=sentinel, host='127.0.0.1', port=None, **kwargs):
self.app = app
super().__init__(scheme=scheme, host=host, **kwargs)
super().__init__(scheme=scheme, host=host, port=port, **kwargs)

async def _make_factory(self, **kwargs):
self.app._set_loop(self._loop)
Expand All @@ -154,9 +159,9 @@ async def _close_hook(self):
class RawTestServer(BaseTestServer):

def __init__(self, handler, *,
scheme=sentinel, host='127.0.0.1', **kwargs):
scheme=sentinel, host='127.0.0.1', port=None, **kwargs):
self._handler = handler
super().__init__(scheme=scheme, host=host, **kwargs)
super().__init__(scheme=scheme, host=host, port=port, **kwargs)

async def _make_factory(self, debug=True, **kwargs):
self.handler = Server(
Expand Down
21 changes: 16 additions & 5 deletions docs/testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ app test client::

Pytest tooling has the following fixtures:

.. data:: test_server(app, **kwargs)
.. data:: test_server(app, *, port=None, **kwargs)

A fixture factory that creates
:class:`~aiohttp.test_utils.TestServer`::
Expand All @@ -144,11 +144,14 @@ Pytest tooling has the following fixtures:
*app* is the :class:`aiohttp.web.Application` used
to start server.

*port* optional, port the server is run at, if
not provided a random unused port is used.

*kwargs* are parameters passed to
:meth:`aiohttp.web.Application.make_handler`


.. data:: test_client(app, **kwargs)
.. data:: test_client(app, server_kwargs=None, **kwargs)
test_client(server, **kwargs)
test_client(raw_server, **kwargs)

Expand All @@ -168,17 +171,23 @@ Pytest tooling has the following fixtures:
:class:`aiohttp.test_utils.TestServer` or
:class:`aiohttp.test_utils.RawTestServer` instance.

*server_kwargs* are parameters passed to the test server if an app
is passed, else ignored.

*kwargs* are parameters passed to
:class:`aiohttp.test_utils.TestClient` constructor.

.. data:: raw_test_server(handler, **kwargs)
.. data:: raw_test_server(handler, *, port=None, **kwargs)

A fixture factory that creates
:class:`~aiohttp.test_utils.RawTestServer` instance from given web
handler.

*handler* should be a coroutine which accepts a request and returns
response, e.g.::
response, e.g.

*port* optional, port the server is run at, if
not provided a random unused port is used.::

async def test_f(raw_test_server, test_client):

Expand Down Expand Up @@ -563,7 +572,7 @@ Test server usually works in conjunction with
:class:`aiohttp.test_utils.TestClient` which provides handy client methods
for accessing to the server.

.. class:: BaseTestServer(*, scheme='http', host='127.0.0.1')
.. class:: BaseTestServer(*, scheme='http', host='127.0.0.1', port=None)

Base class for test servers.

Expand All @@ -572,6 +581,8 @@ for accessing to the server.
:param str host: a host for TCP socket, IPv4 *local host*
(``'127.0.0.1'``) by default.

:param int port: optional port for TCP socket, if not provided a
random unused port is used.

.. attribute:: scheme

Expand Down
21 changes: 19 additions & 2 deletions tests/test_pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async def hello(request):
return web.Response(body=b'Hello, world')


def create_app(loop):
def create_app(loop=None):
app = web.Application()
app.router.add_route('GET', '/', hello)
return app
Expand Down Expand Up @@ -124,10 +124,27 @@ def make_app(loop):
with pytest.raises(RuntimeError):
await test_client(make_app)


async def test_custom_port_test_client(test_client, unused_port):
port = unused_port()
client = await test_client(create_app, server_kwargs={'port': port})
assert client.port == port
resp = await client.get('/')
assert resp.status == 200
text = await resp.text()
assert 'Hello, world' in text


async def test_custom_port_test_server(test_server, unused_port):
app = create_app()
port = unused_port()
server = await test_server(app, port=port)
assert server.port == port

""")
testdir.makeconftest(CONFTEST)
result = testdir.runpytest('-p', 'no:sugar', '--loop=pyloop')
result.assert_outcomes(passed=10)
result.assert_outcomes(passed=12)


def test_warning_checks(testdir):
Expand Down
15 changes: 15 additions & 0 deletions tests/test_test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,18 @@ async def test_client_context_manager_response(method, app, loop):
if method != 'head':
text = await resp.text()
assert "Hello, world" in text


async def test_custom_port(loop, app, unused_port):
port = unused_port()
client = _TestClient(_TestServer(app, loop=loop, port=port), loop=loop)
await client.start_server()

assert client.server.port == port

resp = await client.get('/')
assert resp.status == 200
text = await resp.text()
assert _hello_world_str == text

await client.close()