From a8827a5d9581e8a5082eb1811d832a4e87631d77 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 28 Nov 2017 03:56:05 +0900 Subject: [PATCH] Boost test speed by pytest-xdist --- tests/conftest.py | 23 +++++++++++++++++++++++ tests/test_keep_alive_timeout.py | 13 +++++++------ tests/test_logging.py | 3 +-- tests/test_multiprocessing.py | 4 ++-- tests/test_request_timeout.py | 6 +++--- tests/test_requests.py | 8 ++++---- tests/test_response.py | 4 ++-- tests/test_server_events.py | 4 ++-- tests/test_signal_handlers.py | 7 +++---- tests/test_url_building.py | 14 +++++++++----- tox.ini | 3 ++- 11 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 tests/conftest.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..dd3dc6d7 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,23 @@ +import re +import sanic + + +def pytest_collection_modifyitems(session, config, items): + base_port = sanic.testing.PORT + + worker_id = getattr(config, 'slaveinput', {}).get('slaveid', 'master') + m = re.search(r'[0-9]+', worker_id) + if m: + num_id = int(m.group(0)) + 1 + else: + num_id = 0 + new_port = base_port + num_id + + def new_test_client(app, port=new_port): + return sanic.testing.SanicTestClient(app, port) + + sanic.Sanic.test_port = new_port + sanic.Sanic.test_client = property(new_test_client) + + app = sanic.Sanic() + assert app.test_client.port == new_port diff --git a/tests/test_keep_alive_timeout.py b/tests/test_keep_alive_timeout.py index 15f6d705..c3de8462 100644 --- a/tests/test_keep_alive_timeout.py +++ b/tests/test_keep_alive_timeout.py @@ -7,7 +7,7 @@ from sanic.config import Config from sanic import server import aiohttp from aiohttp import TCPConnector -from sanic.testing import SanicTestClient, HOST, PORT +from sanic.testing import SanicTestClient, HOST class ReuseableTCPConnector(TCPConnector): @@ -30,7 +30,7 @@ class ReuseableTCPConnector(TCPConnector): class ReuseableSanicTestClient(SanicTestClient): def __init__(self, app, loop=None): - super(ReuseableSanicTestClient, self).__init__(app) + super().__init__(app, port=app.test_port) if loop is None: loop = asyncio.get_event_loop() self._loop = loop @@ -68,13 +68,14 @@ class ReuseableSanicTestClient(SanicTestClient): import traceback traceback.print_tb(e2.__traceback__) exceptions.append(e2) - #Don't stop here! self.app.stop() + # Don't stop here! self.app.stop() if self._server is not None: _server = self._server else: _server_co = self.app.create_server(host=HOST, debug=debug, - port=PORT, **server_kwargs) + port=self.app.test_port, + **server_kwargs) server.trigger_events( self.app.listeners['before_server_start'], loop) @@ -88,7 +89,7 @@ class ReuseableSanicTestClient(SanicTestClient): raise e1 self._server = _server = http_server server.trigger_events( - self.app.listeners['after_server_start'], loop) + self.app.listeners['after_server_start'], loop) self.app.listeners['after_server_start'].pop() if do_kill_server: @@ -133,7 +134,7 @@ class ReuseableSanicTestClient(SanicTestClient): url = uri else: url = 'http://{host}:{port}{uri}'.format( - host=HOST, port=PORT, uri=uri) + host=HOST, port=self.port, uri=uri) do_kill_session = kwargs.pop('end_session', False) if self._session: session = self._session diff --git a/tests/test_logging.py b/tests/test_logging.py index e95b7ce5..1a040a5c 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -101,7 +101,6 @@ def test_log_connection_lost(debug, monkeypatch): log = stream.getvalue() if debug: - assert log.startswith( - 'Connection lost before response written @') + assert 'Connection lost before response written @' in log else: assert 'Connection lost before response written @' not in log diff --git a/tests/test_multiprocessing.py b/tests/test_multiprocessing.py index 1342c6d3..519ad171 100644 --- a/tests/test_multiprocessing.py +++ b/tests/test_multiprocessing.py @@ -3,7 +3,7 @@ import random import signal from sanic import Sanic -from sanic.testing import HOST, PORT +from sanic.testing import HOST def test_multiprocessing(): @@ -20,7 +20,7 @@ def test_multiprocessing(): signal.signal(signal.SIGALRM, stop_on_alarm) signal.alarm(1) - app.run(HOST, PORT, workers=num_workers) + app.run(HOST, app.test_port, workers=num_workers) assert len(process_list) == num_workers diff --git a/tests/test_request_timeout.py b/tests/test_request_timeout.py index a1d8a885..113ffdd7 100644 --- a/tests/test_request_timeout.py +++ b/tests/test_request_timeout.py @@ -6,7 +6,7 @@ from sanic.response import text from sanic.config import Config import aiohttp from aiohttp import TCPConnector -from sanic.testing import SanicTestClient, HOST, PORT +from sanic.testing import SanicTestClient, HOST class DelayableTCPConnector(TCPConnector): @@ -96,7 +96,7 @@ class DelayableTCPConnector(TCPConnector): class DelayableSanicTestClient(SanicTestClient): def __init__(self, app, loop, request_delay=1): - super(DelayableSanicTestClient, self).__init__(app) + super(DelayableSanicTestClient, self).__init__(app, port=app.test_port) self._request_delay = request_delay self._loop = None @@ -108,7 +108,7 @@ class DelayableSanicTestClient(SanicTestClient): url = uri else: url = 'http://{host}:{port}{uri}'.format( - host=HOST, port=PORT, uri=uri) + host=HOST, port=self.port, uri=uri) conn = DelayableTCPConnector(pre_request_delay=self._request_delay, verify_ssl=False, loop=self._loop) async with aiohttp.ClientSession(cookies=cookies, connector=conn, diff --git a/tests/test_requests.py b/tests/test_requests.py index e47520c4..9eb88243 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -9,7 +9,7 @@ from sanic import Sanic from sanic.exceptions import ServerError from sanic.response import json, text from sanic.request import DEFAULT_HTTP_CONTENT_TYPE -from sanic.testing import HOST, PORT +from sanic.testing import HOST # ------------------------------------------------------------ # @@ -338,7 +338,7 @@ def test_url_attributes_no_ssl(path, query, expected_url): app.add_route(handler, path) request, response = app.test_client.get(path + '?{}'.format(query)) - assert request.url == expected_url.format(HOST, PORT) + assert request.url == expected_url.format(HOST, app.test_port) parsed = urlparse(request.url) @@ -369,9 +369,9 @@ def test_url_attributes_with_ssl(path, query, expected_url): app.add_route(handler, path) request, response = app.test_client.get( - 'https://{}:{}'.format(HOST, PORT) + path + '?{}'.format(query), + 'https://{}:{}'.format(HOST, app.test_port) + path + '?{}'.format(query), server_kwargs={'ssl': context}) - assert request.url == expected_url.format(HOST, PORT) + assert request.url == expected_url.format(HOST, app.test_port) parsed = urlparse(request.url) diff --git a/tests/test_response.py b/tests/test_response.py index 086b4e58..6ac77cec 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -10,7 +10,7 @@ from random import choice from sanic import Sanic from sanic.response import HTTPResponse, stream, StreamingHTTPResponse, file, file_stream, json -from sanic.testing import HOST, PORT +from sanic.testing import HOST from unittest.mock import MagicMock JSON_DATA = {'ok': True} @@ -139,7 +139,7 @@ def test_stream_response_writes_correct_content_to_transport(streaming_app): app.stop() - streaming_app.run(host=HOST, port=PORT) + streaming_app.run(host=HOST, port=streaming_app.test_port) @pytest.fixture diff --git a/tests/test_server_events.py b/tests/test_server_events.py index d78f0aed..ab0a1fb1 100644 --- a/tests/test_server_events.py +++ b/tests/test_server_events.py @@ -6,7 +6,7 @@ import signal import pytest from sanic import Sanic -from sanic.testing import HOST, PORT +from sanic.testing import HOST AVAILABLE_LISTENERS = [ 'before_server_start', @@ -31,7 +31,7 @@ def start_stop_app(random_name_app, **run_kwargs): signal.signal(signal.SIGALRM, stop_on_alarm) signal.alarm(1) try: - random_name_app.run(HOST, PORT, **run_kwargs) + random_name_app.run(HOST, random_name_app.test_port, **run_kwargs) except KeyboardInterrupt: pass diff --git a/tests/test_signal_handlers.py b/tests/test_signal_handlers.py index c4cca92b..967e903f 100644 --- a/tests/test_signal_handlers.py +++ b/tests/test_signal_handlers.py @@ -1,8 +1,7 @@ from sanic import Sanic from sanic.response import HTTPResponse -from sanic.testing import HOST, PORT +from sanic.testing import HOST from unittest.mock import MagicMock -import pytest import asyncio from queue import Queue @@ -31,7 +30,7 @@ def test_register_system_signals(): app.listener('before_server_start')(set_loop) app.listener('after_server_stop')(after) - app.run(HOST, PORT) + app.run(HOST, app.test_port) assert calledq.get() == True @@ -47,5 +46,5 @@ def test_dont_register_system_signals(): app.listener('before_server_start')(set_loop) app.listener('after_server_stop')(after) - app.run(HOST, PORT, register_sys_signals=False) + app.run(HOST, app.test_port, register_sys_signals=False) assert calledq.get() == False diff --git a/tests/test_url_building.py b/tests/test_url_building.py index f3ed534f..ed41b017 100644 --- a/tests/test_url_building.py +++ b/tests/test_url_building.py @@ -5,7 +5,7 @@ from sanic import Sanic from sanic.response import text from sanic.views import HTTPMethodView from sanic.blueprints import Blueprint -from sanic.testing import PORT as test_port, HOST as test_host +from sanic.testing import HOST as test_host from sanic.exceptions import URLBuildError import string @@ -15,11 +15,11 @@ URL_FOR_VALUE1 = '/myurl?arg1=v1&arg1=v2' URL_FOR_ARGS2 = dict(arg1=['v1', 'v2'], _anchor='anchor') URL_FOR_VALUE2 = '/myurl?arg1=v1&arg1=v2#anchor' URL_FOR_ARGS3 = dict(arg1='v1', _anchor='anchor', _scheme='http', - _server='{}:{}'.format(test_host, test_port), _external=True) -URL_FOR_VALUE3 = 'http://{}:{}/myurl?arg1=v1#anchor'.format(test_host, test_port) + _server='{}:PORT_PLACEHOLDER'.format(test_host), _external=True) +URL_FOR_VALUE3 = 'http://{}:PORT_PLACEHOLDER/myurl?arg1=v1#anchor'.format(test_host) URL_FOR_ARGS4 = dict(arg1='v1', _anchor='anchor', _external=True, - _server='http://{}:{}'.format(test_host, test_port),) -URL_FOR_VALUE4 = 'http://{}:{}/myurl?arg1=v1#anchor'.format(test_host, test_port) + _server='http://{}:PORT_PLACEHOLDER'.format(test_host),) +URL_FOR_VALUE4 = 'http://{}:PORT_PLACEHOLDER/myurl?arg1=v1#anchor'.format(test_host) def _generate_handlers_from_names(app, l): @@ -61,6 +61,10 @@ def test_simple_url_for_getting_with_more_params(args, url): def passes(request): return text('this should pass') + if '_server' in args: + args['_server'] = args['_server'].replace( + 'PORT_PLACEHOLDER', str(app.test_port)) + url = url.replace('PORT_PLACEHOLDER', str(app.test_port)) assert url == app.url_for('passes', **args) request, response = app.test_client.get(url) assert response.status == 200 diff --git a/tox.ini b/tox.ini index ff43a139..0b573f6b 100644 --- a/tox.ini +++ b/tox.ini @@ -12,12 +12,13 @@ deps = pytest-cov pytest-sanic pytest-sugar + pytest-xdist aiohttp==1.3.5 chardet<=2.3.0 beautifulsoup4 gunicorn commands = - pytest tests --cov sanic --cov-report= {posargs} + pytest tests -n 4 --cov sanic --cov-report= {posargs} - coverage combine --append coverage report -m