Boost test speed by pytest-xdist

This commit is contained in:
Jeong YunWon 2017-11-28 03:56:05 +09:00 committed by Jeong YunWon
parent 72254a7af9
commit a8827a5d95
11 changed files with 58 additions and 31 deletions

23
tests/conftest.py Normal file
View File

@ -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

View File

@ -7,7 +7,7 @@ from sanic.config import Config
from sanic import server from sanic import server
import aiohttp import aiohttp
from aiohttp import TCPConnector from aiohttp import TCPConnector
from sanic.testing import SanicTestClient, HOST, PORT from sanic.testing import SanicTestClient, HOST
class ReuseableTCPConnector(TCPConnector): class ReuseableTCPConnector(TCPConnector):
@ -30,7 +30,7 @@ class ReuseableTCPConnector(TCPConnector):
class ReuseableSanicTestClient(SanicTestClient): class ReuseableSanicTestClient(SanicTestClient):
def __init__(self, app, loop=None): def __init__(self, app, loop=None):
super(ReuseableSanicTestClient, self).__init__(app) super().__init__(app, port=app.test_port)
if loop is None: if loop is None:
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
self._loop = loop self._loop = loop
@ -68,13 +68,14 @@ class ReuseableSanicTestClient(SanicTestClient):
import traceback import traceback
traceback.print_tb(e2.__traceback__) traceback.print_tb(e2.__traceback__)
exceptions.append(e2) exceptions.append(e2)
#Don't stop here! self.app.stop() # Don't stop here! self.app.stop()
if self._server is not None: if self._server is not None:
_server = self._server _server = self._server
else: else:
_server_co = self.app.create_server(host=HOST, debug=debug, _server_co = self.app.create_server(host=HOST, debug=debug,
port=PORT, **server_kwargs) port=self.app.test_port,
**server_kwargs)
server.trigger_events( server.trigger_events(
self.app.listeners['before_server_start'], loop) self.app.listeners['before_server_start'], loop)
@ -133,7 +134,7 @@ class ReuseableSanicTestClient(SanicTestClient):
url = uri url = uri
else: else:
url = 'http://{host}:{port}{uri}'.format( 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) do_kill_session = kwargs.pop('end_session', False)
if self._session: if self._session:
session = self._session session = self._session

View File

@ -101,7 +101,6 @@ def test_log_connection_lost(debug, monkeypatch):
log = stream.getvalue() log = stream.getvalue()
if debug: if debug:
assert log.startswith( assert 'Connection lost before response written @' in log
'Connection lost before response written @')
else: else:
assert 'Connection lost before response written @' not in log assert 'Connection lost before response written @' not in log

View File

@ -3,7 +3,7 @@ import random
import signal import signal
from sanic import Sanic from sanic import Sanic
from sanic.testing import HOST, PORT from sanic.testing import HOST
def test_multiprocessing(): def test_multiprocessing():
@ -20,7 +20,7 @@ def test_multiprocessing():
signal.signal(signal.SIGALRM, stop_on_alarm) signal.signal(signal.SIGALRM, stop_on_alarm)
signal.alarm(1) 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 assert len(process_list) == num_workers

View File

@ -6,7 +6,7 @@ from sanic.response import text
from sanic.config import Config from sanic.config import Config
import aiohttp import aiohttp
from aiohttp import TCPConnector from aiohttp import TCPConnector
from sanic.testing import SanicTestClient, HOST, PORT from sanic.testing import SanicTestClient, HOST
class DelayableTCPConnector(TCPConnector): class DelayableTCPConnector(TCPConnector):
@ -96,7 +96,7 @@ class DelayableTCPConnector(TCPConnector):
class DelayableSanicTestClient(SanicTestClient): class DelayableSanicTestClient(SanicTestClient):
def __init__(self, app, loop, request_delay=1): 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._request_delay = request_delay
self._loop = None self._loop = None
@ -108,7 +108,7 @@ class DelayableSanicTestClient(SanicTestClient):
url = uri url = uri
else: else:
url = 'http://{host}:{port}{uri}'.format( 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, conn = DelayableTCPConnector(pre_request_delay=self._request_delay,
verify_ssl=False, loop=self._loop) verify_ssl=False, loop=self._loop)
async with aiohttp.ClientSession(cookies=cookies, connector=conn, async with aiohttp.ClientSession(cookies=cookies, connector=conn,

View File

@ -9,7 +9,7 @@ from sanic import Sanic
from sanic.exceptions import ServerError from sanic.exceptions import ServerError
from sanic.response import json, text from sanic.response import json, text
from sanic.request import DEFAULT_HTTP_CONTENT_TYPE 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) app.add_route(handler, path)
request, response = app.test_client.get(path + '?{}'.format(query)) 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) parsed = urlparse(request.url)
@ -369,9 +369,9 @@ def test_url_attributes_with_ssl(path, query, expected_url):
app.add_route(handler, path) app.add_route(handler, path)
request, response = app.test_client.get( 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}) 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) parsed = urlparse(request.url)

View File

@ -10,7 +10,7 @@ from random import choice
from sanic import Sanic from sanic import Sanic
from sanic.response import HTTPResponse, stream, StreamingHTTPResponse, file, file_stream, json 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 from unittest.mock import MagicMock
JSON_DATA = {'ok': True} JSON_DATA = {'ok': True}
@ -139,7 +139,7 @@ def test_stream_response_writes_correct_content_to_transport(streaming_app):
app.stop() app.stop()
streaming_app.run(host=HOST, port=PORT) streaming_app.run(host=HOST, port=streaming_app.test_port)
@pytest.fixture @pytest.fixture

View File

@ -6,7 +6,7 @@ import signal
import pytest import pytest
from sanic import Sanic from sanic import Sanic
from sanic.testing import HOST, PORT from sanic.testing import HOST
AVAILABLE_LISTENERS = [ AVAILABLE_LISTENERS = [
'before_server_start', 'before_server_start',
@ -31,7 +31,7 @@ def start_stop_app(random_name_app, **run_kwargs):
signal.signal(signal.SIGALRM, stop_on_alarm) signal.signal(signal.SIGALRM, stop_on_alarm)
signal.alarm(1) signal.alarm(1)
try: try:
random_name_app.run(HOST, PORT, **run_kwargs) random_name_app.run(HOST, random_name_app.test_port, **run_kwargs)
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass

View File

@ -1,8 +1,7 @@
from sanic import Sanic from sanic import Sanic
from sanic.response import HTTPResponse from sanic.response import HTTPResponse
from sanic.testing import HOST, PORT from sanic.testing import HOST
from unittest.mock import MagicMock from unittest.mock import MagicMock
import pytest
import asyncio import asyncio
from queue import Queue from queue import Queue
@ -31,7 +30,7 @@ def test_register_system_signals():
app.listener('before_server_start')(set_loop) app.listener('before_server_start')(set_loop)
app.listener('after_server_stop')(after) app.listener('after_server_stop')(after)
app.run(HOST, PORT) app.run(HOST, app.test_port)
assert calledq.get() == True assert calledq.get() == True
@ -47,5 +46,5 @@ def test_dont_register_system_signals():
app.listener('before_server_start')(set_loop) app.listener('before_server_start')(set_loop)
app.listener('after_server_stop')(after) 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 assert calledq.get() == False

View File

@ -5,7 +5,7 @@ from sanic import Sanic
from sanic.response import text from sanic.response import text
from sanic.views import HTTPMethodView from sanic.views import HTTPMethodView
from sanic.blueprints import Blueprint 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 from sanic.exceptions import URLBuildError
import string 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_ARGS2 = dict(arg1=['v1', 'v2'], _anchor='anchor')
URL_FOR_VALUE2 = '/myurl?arg1=v1&arg1=v2#anchor' URL_FOR_VALUE2 = '/myurl?arg1=v1&arg1=v2#anchor'
URL_FOR_ARGS3 = dict(arg1='v1', _anchor='anchor', _scheme='http', URL_FOR_ARGS3 = dict(arg1='v1', _anchor='anchor', _scheme='http',
_server='{}:{}'.format(test_host, test_port), _external=True) _server='{}:PORT_PLACEHOLDER'.format(test_host), _external=True)
URL_FOR_VALUE3 = 'http://{}:{}/myurl?arg1=v1#anchor'.format(test_host, test_port) URL_FOR_VALUE3 = 'http://{}:PORT_PLACEHOLDER/myurl?arg1=v1#anchor'.format(test_host)
URL_FOR_ARGS4 = dict(arg1='v1', _anchor='anchor', _external=True, URL_FOR_ARGS4 = dict(arg1='v1', _anchor='anchor', _external=True,
_server='http://{}:{}'.format(test_host, test_port),) _server='http://{}:PORT_PLACEHOLDER'.format(test_host),)
URL_FOR_VALUE4 = 'http://{}:{}/myurl?arg1=v1#anchor'.format(test_host, test_port) URL_FOR_VALUE4 = 'http://{}:PORT_PLACEHOLDER/myurl?arg1=v1#anchor'.format(test_host)
def _generate_handlers_from_names(app, l): 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): def passes(request):
return text('this should pass') 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) assert url == app.url_for('passes', **args)
request, response = app.test_client.get(url) request, response = app.test_client.get(url)
assert response.status == 200 assert response.status == 200

View File

@ -12,12 +12,13 @@ deps =
pytest-cov pytest-cov
pytest-sanic pytest-sanic
pytest-sugar pytest-sugar
pytest-xdist
aiohttp==1.3.5 aiohttp==1.3.5
chardet<=2.3.0 chardet<=2.3.0
beautifulsoup4 beautifulsoup4
gunicorn gunicorn
commands = commands =
pytest tests --cov sanic --cov-report= {posargs} pytest tests -n 4 --cov sanic --cov-report= {posargs}
- coverage combine --append - coverage combine --append
coverage report -m coverage report -m