mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
remove gaiohttp worker (#1971)
* remove gaiohttp worker worker is deprecated and won't work on latest version.
This commit is contained in:
parent
2ea5fbdc86
commit
97a45805f8
@ -59,7 +59,7 @@ WSGI application, this is not a recommended configuration.
|
|||||||
AsyncIO Workers
|
AsyncIO Workers
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
These workers are compatible with python3. You have two kind of workers.
|
These workers are compatible with Python 3.
|
||||||
|
|
||||||
The worker `gthread` is a threaded worker. It accepts connections in the
|
The worker `gthread` is a threaded worker. It accepts connections in the
|
||||||
main loop, accepted connections are added to the thread pool as a
|
main loop, accepted connections are added to the thread pool as a
|
||||||
@ -67,24 +67,8 @@ connection job. On keepalive connections are put back in the loop
|
|||||||
waiting for an event. If no event happen after the keep alive timeout,
|
waiting for an event. If no event happen after the keep alive timeout,
|
||||||
the connection is closed.
|
the connection is closed.
|
||||||
|
|
||||||
The worker `gaiohttp` is a full asyncio worker using aiohttp_.
|
You can port also your application to use aiohttp_'s `web.Application`` API and use the
|
||||||
|
``aiohttp.worker.GunicornWebWorker`` worker.
|
||||||
.. note::
|
|
||||||
The ``gaiohttp`` worker requires the aiohttp_ module to be installed.
|
|
||||||
aiohttp_ has removed its native WSGI application support in version 2.
|
|
||||||
If you want to continue to use the ``gaiohttp`` worker with your WSGI
|
|
||||||
application (e.g. an application that uses Flask or Django), there are
|
|
||||||
three options available:
|
|
||||||
|
|
||||||
#. Install aiohttp_ version 1.3.5 instead of version 2::
|
|
||||||
|
|
||||||
$ pip install aiohttp==1.3.5
|
|
||||||
|
|
||||||
#. Use aiohttp_wsgi_ to wrap your WSGI application. You can take a look
|
|
||||||
at the `example`_ in the Gunicorn repository.
|
|
||||||
#. Port your application to use aiohttp_'s ``web.Application`` API.
|
|
||||||
#. Use the ``aiohttp.worker.GunicornWebWorker`` worker instead of the
|
|
||||||
deprecated ``gaiohttp`` worker.
|
|
||||||
|
|
||||||
Choosing a Worker Type
|
Choosing a Worker Type
|
||||||
======================
|
======================
|
||||||
@ -157,6 +141,5 @@ code in the master process).
|
|||||||
.. _Eventlet: http://eventlet.net/
|
.. _Eventlet: http://eventlet.net/
|
||||||
.. _Gevent: http://www.gevent.org/
|
.. _Gevent: http://www.gevent.org/
|
||||||
.. _Hey: https://github.com/rakyll/hey
|
.. _Hey: https://github.com/rakyll/hey
|
||||||
.. _aiohttp: https://aiohttp.readthedocs.io/en/stable/
|
.. _aiohttp: https://docs.aiohttp.org/en/stable/deployment.html#nginx-gunicorn
|
||||||
.. _aiohttp_wsgi: https://aiohttp-wsgi.readthedocs.io/en/stable/index.html
|
|
||||||
.. _`example`: https://github.com/benoitc/gunicorn/blob/master/examples/frameworks/flaskapp_aiohttp_wsgi.py
|
.. _`example`: https://github.com/benoitc/gunicorn/blob/master/examples/frameworks/flaskapp_aiohttp_wsgi.py
|
||||||
|
|||||||
@ -61,7 +61,7 @@ Commonly Used Arguments
|
|||||||
to run. You'll definitely want to read the production page for the
|
to run. You'll definitely want to read the production page for the
|
||||||
implications of this parameter. You can set this to ``$(NAME)``
|
implications of this parameter. You can set this to ``$(NAME)``
|
||||||
where ``$(NAME)`` is one of ``sync``, ``eventlet``, ``gevent``,
|
where ``$(NAME)`` is one of ``sync``, ``eventlet``, ``gevent``,
|
||||||
``tornado``, ``gthread``, ``gaiohttp`` (deprecated).
|
``tornado``, ``gthread``.
|
||||||
``sync`` is the default. See the :ref:`worker-class` documentation for more
|
``sync`` is the default. See the :ref:`worker-class` documentation for more
|
||||||
information.
|
information.
|
||||||
* ``-n APP_NAME, --name=APP_NAME`` - If setproctitle_ is installed you can
|
* ``-n APP_NAME, --name=APP_NAME`` - If setproctitle_ is installed you can
|
||||||
|
|||||||
@ -638,17 +638,11 @@ class WorkerClass(Setting):
|
|||||||
``pip install gunicorn[tornado]``)
|
``pip install gunicorn[tornado]``)
|
||||||
* ``gthread`` - Python 2 requires the futures package to be installed
|
* ``gthread`` - Python 2 requires the futures package to be installed
|
||||||
(or install it via ``pip install gunicorn[gthread]``)
|
(or install it via ``pip install gunicorn[gthread]``)
|
||||||
* ``gaiohttp`` - Deprecated.
|
|
||||||
|
|
||||||
Optionally, you can provide your own worker by giving Gunicorn a
|
Optionally, you can provide your own worker by giving Gunicorn a
|
||||||
Python path to a subclass of ``gunicorn.workers.base.Worker``.
|
Python path to a subclass of ``gunicorn.workers.base.Worker``.
|
||||||
This alternative syntax will load the gevent class:
|
This alternative syntax will load the gevent class:
|
||||||
``gunicorn.workers.ggevent.GeventWorker``.
|
``gunicorn.workers.ggevent.GeventWorker``.
|
||||||
|
|
||||||
.. deprecated:: 19.8
|
|
||||||
The ``gaiohttp`` worker is deprecated. Please use
|
|
||||||
``aiohttp.worker.GunicornWebWorker`` instead. See
|
|
||||||
:ref:`asyncio-workers` for more information on how to use it.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class WorkerThreads(Setting):
|
class WorkerThreads(Setting):
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
SUPPORTED_WORKERS = {
|
SUPPORTED_WORKERS = {
|
||||||
"sync": "gunicorn.workers.sync.SyncWorker",
|
"sync": "gunicorn.workers.sync.SyncWorker",
|
||||||
"eventlet": "gunicorn.workers.geventlet.EventletWorker",
|
"eventlet": "gunicorn.workers.geventlet.EventletWorker",
|
||||||
"gaiohttp": "gunicorn.workers.gaiohttp.AiohttpWorker",
|
|
||||||
"gevent": "gunicorn.workers.ggevent.GeventWorker",
|
"gevent": "gunicorn.workers.ggevent.GeventWorker",
|
||||||
"gevent_wsgi": "gunicorn.workers.ggevent.GeventPyWSGIWorker",
|
"gevent_wsgi": "gunicorn.workers.ggevent.GeventPyWSGIWorker",
|
||||||
"gevent_pywsgi": "gunicorn.workers.ggevent.GeventPyWSGIWorker",
|
"gevent_pywsgi": "gunicorn.workers.ggevent.GeventPyWSGIWorker",
|
||||||
|
|||||||
@ -1,168 +0,0 @@
|
|||||||
# -*- coding: utf-8 -
|
|
||||||
#
|
|
||||||
# This file is part of gunicorn released under the MIT license.
|
|
||||||
# See the NOTICE for more information.
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import datetime
|
|
||||||
import functools
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
|
|
||||||
try:
|
|
||||||
import ssl
|
|
||||||
except ImportError:
|
|
||||||
ssl = None
|
|
||||||
|
|
||||||
import gunicorn.workers.base as base
|
|
||||||
|
|
||||||
from aiohttp.wsgi import WSGIServerHttpProtocol as OldWSGIServerHttpProtocol
|
|
||||||
|
|
||||||
|
|
||||||
class WSGIServerHttpProtocol(OldWSGIServerHttpProtocol):
|
|
||||||
def log_access(self, request, environ, response, time):
|
|
||||||
self.logger.access(response, request, environ, datetime.timedelta(0, 0, time))
|
|
||||||
|
|
||||||
|
|
||||||
class AiohttpWorker(base.Worker):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kw): # pragma: no cover
|
|
||||||
super().__init__(*args, **kw)
|
|
||||||
cfg = self.cfg
|
|
||||||
if cfg.is_ssl:
|
|
||||||
self.ssl_context = self._create_ssl_context(cfg)
|
|
||||||
else:
|
|
||||||
self.ssl_context = None
|
|
||||||
self.servers = []
|
|
||||||
self.connections = {}
|
|
||||||
|
|
||||||
def init_process(self):
|
|
||||||
# create new event_loop after fork
|
|
||||||
asyncio.get_event_loop().close()
|
|
||||||
|
|
||||||
self.loop = asyncio.new_event_loop()
|
|
||||||
asyncio.set_event_loop(self.loop)
|
|
||||||
|
|
||||||
super().init_process()
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self._runner = asyncio.ensure_future(self._run(), loop=self.loop)
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.loop.run_until_complete(self._runner)
|
|
||||||
finally:
|
|
||||||
self.loop.close()
|
|
||||||
|
|
||||||
def wrap_protocol(self, proto):
|
|
||||||
proto.connection_made = _wrp(
|
|
||||||
proto, proto.connection_made, self.connections)
|
|
||||||
proto.connection_lost = _wrp(
|
|
||||||
proto, proto.connection_lost, self.connections, False)
|
|
||||||
return proto
|
|
||||||
|
|
||||||
def factory(self, wsgi, addr):
|
|
||||||
# are we in debug level
|
|
||||||
is_debug = self.log.loglevel == logging.DEBUG
|
|
||||||
|
|
||||||
proto = WSGIServerHttpProtocol(
|
|
||||||
wsgi, readpayload=True,
|
|
||||||
loop=self.loop,
|
|
||||||
log=self.log,
|
|
||||||
debug=is_debug,
|
|
||||||
keep_alive=self.cfg.keepalive,
|
|
||||||
access_log=self.log.access_log,
|
|
||||||
access_log_format=self.cfg.access_log_format)
|
|
||||||
return self.wrap_protocol(proto)
|
|
||||||
|
|
||||||
def get_factory(self, sock, addr):
|
|
||||||
return functools.partial(self.factory, self.wsgi, addr)
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def close(self):
|
|
||||||
try:
|
|
||||||
if hasattr(self.wsgi, 'close'):
|
|
||||||
yield from self.wsgi.close()
|
|
||||||
except:
|
|
||||||
self.log.exception('Process shutdown exception')
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def _run(self):
|
|
||||||
for sock in self.sockets:
|
|
||||||
factory = self.get_factory(sock.sock, sock.cfg_addr)
|
|
||||||
self.servers.append(
|
|
||||||
(yield from self._create_server(factory, sock)))
|
|
||||||
|
|
||||||
# If our parent changed then we shut down.
|
|
||||||
pid = os.getpid()
|
|
||||||
try:
|
|
||||||
while self.alive or self.connections:
|
|
||||||
self.notify()
|
|
||||||
|
|
||||||
if (self.alive and
|
|
||||||
pid == os.getpid() and self.ppid != os.getppid()):
|
|
||||||
self.log.info("Parent changed, shutting down: %s", self)
|
|
||||||
self.alive = False
|
|
||||||
|
|
||||||
# stop accepting requests
|
|
||||||
if not self.alive:
|
|
||||||
if self.servers:
|
|
||||||
self.log.info(
|
|
||||||
"Stopping server: %s, connections: %s",
|
|
||||||
pid, len(self.connections))
|
|
||||||
for server in self.servers:
|
|
||||||
server.close()
|
|
||||||
self.servers.clear()
|
|
||||||
|
|
||||||
# prepare connections for closing
|
|
||||||
for conn in self.connections.values():
|
|
||||||
if hasattr(conn, 'closing'):
|
|
||||||
conn.closing()
|
|
||||||
|
|
||||||
yield from asyncio.sleep(1.0, loop=self.loop)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if self.servers:
|
|
||||||
for server in self.servers:
|
|
||||||
server.close()
|
|
||||||
|
|
||||||
yield from self.close()
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def _create_server(self, factory, sock):
|
|
||||||
return self.loop.create_server(factory, sock=sock.sock,
|
|
||||||
ssl=self.ssl_context)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _create_ssl_context(cfg):
|
|
||||||
""" Creates SSLContext instance for usage in asyncio.create_server.
|
|
||||||
|
|
||||||
See ssl.SSLSocket.__init__ for more details.
|
|
||||||
"""
|
|
||||||
ctx = ssl.SSLContext(cfg.ssl_version)
|
|
||||||
ctx.load_cert_chain(cfg.certfile, cfg.keyfile)
|
|
||||||
ctx.verify_mode = cfg.cert_reqs
|
|
||||||
if cfg.ca_certs:
|
|
||||||
ctx.load_verify_locations(cfg.ca_certs)
|
|
||||||
if cfg.ciphers:
|
|
||||||
ctx.set_ciphers(cfg.ciphers)
|
|
||||||
return ctx
|
|
||||||
|
|
||||||
|
|
||||||
class _wrp:
|
|
||||||
|
|
||||||
def __init__(self, proto, meth, tracking, add=True):
|
|
||||||
self._proto = proto
|
|
||||||
self._id = id(proto)
|
|
||||||
self._meth = meth
|
|
||||||
self._tracking = tracking
|
|
||||||
self._add = add
|
|
||||||
|
|
||||||
def __call__(self, *args):
|
|
||||||
if self._add:
|
|
||||||
self._tracking[self._id] = self._proto
|
|
||||||
elif self._id in self._tracking:
|
|
||||||
del self._tracking[self._id]
|
|
||||||
|
|
||||||
conn = self._meth(*args)
|
|
||||||
return conn
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
# -*- coding: utf-8 -
|
|
||||||
#
|
|
||||||
# This file is part of gunicorn released under the MIT license.
|
|
||||||
# See the NOTICE for more information.
|
|
||||||
|
|
||||||
from gunicorn import util
|
|
||||||
|
|
||||||
try:
|
|
||||||
import aiohttp # pylint: disable=unused-import
|
|
||||||
except ImportError:
|
|
||||||
raise RuntimeError("You need aiohttp installed to use this worker.")
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
from aiohttp.worker import GunicornWebWorker as AiohttpWorker
|
|
||||||
except ImportError:
|
|
||||||
from gunicorn.workers._gaiohttp import AiohttpWorker
|
|
||||||
|
|
||||||
util.warn(
|
|
||||||
"The 'gaiohttp' worker is deprecated. See --worker-class "
|
|
||||||
"documentation for more information."
|
|
||||||
)
|
|
||||||
__all__ = ['AiohttpWorker']
|
|
||||||
@ -1,193 +0,0 @@
|
|||||||
# -*- coding: utf-8 -
|
|
||||||
#
|
|
||||||
# This file is part of gunicorn released under the MIT license.
|
|
||||||
# See the NOTICE for more information.
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
aiohttp = pytest.importorskip("aiohttp")
|
|
||||||
WSGIServerHttpProtocol = pytest.importorskip("aiohttp.wsgi.WSGIServerHttpProtocol")
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from gunicorn.workers import gaiohttp
|
|
||||||
from gunicorn.workers._gaiohttp import _wrp
|
|
||||||
from gunicorn.config import Config
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
|
|
||||||
class WorkerTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.loop = asyncio.new_event_loop()
|
|
||||||
asyncio.set_event_loop(None)
|
|
||||||
self.worker = gaiohttp.AiohttpWorker('age',
|
|
||||||
'ppid',
|
|
||||||
'sockets',
|
|
||||||
'app',
|
|
||||||
'timeout',
|
|
||||||
Config(),
|
|
||||||
'log')
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.loop.close()
|
|
||||||
|
|
||||||
@mock.patch('gunicorn.workers._gaiohttp.asyncio')
|
|
||||||
def test_init_process(self, m_asyncio):
|
|
||||||
try:
|
|
||||||
self.worker.init_process()
|
|
||||||
except TypeError:
|
|
||||||
# to mask incomplete initialization of AiohttWorker instance:
|
|
||||||
# we pass invalid values for ctor args
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.assertTrue(m_asyncio.get_event_loop.return_value.close.called)
|
|
||||||
self.assertTrue(m_asyncio.new_event_loop.called)
|
|
||||||
self.assertTrue(m_asyncio.set_event_loop.called)
|
|
||||||
|
|
||||||
@mock.patch('gunicorn.workers._gaiohttp.asyncio')
|
|
||||||
def test_run(self, m_asyncio):
|
|
||||||
self.worker.loop = mock.Mock()
|
|
||||||
self.worker.run()
|
|
||||||
|
|
||||||
self.assertTrue(m_asyncio.ensure_future.called)
|
|
||||||
self.assertTrue(self.worker.loop.run_until_complete.called)
|
|
||||||
self.assertTrue(self.worker.loop.close.called)
|
|
||||||
|
|
||||||
def test_factory(self):
|
|
||||||
self.worker.wsgi = mock.Mock()
|
|
||||||
self.worker.loop = mock.Mock()
|
|
||||||
self.worker.log = mock.Mock()
|
|
||||||
self.worker.cfg = Config()
|
|
||||||
|
|
||||||
f = self.worker.factory(
|
|
||||||
self.worker.wsgi, ('localhost', 8080))
|
|
||||||
self.assertIsInstance(f, WSGIServerHttpProtocol)
|
|
||||||
|
|
||||||
@mock.patch('gunicorn.workers._gaiohttp.asyncio')
|
|
||||||
def test__run(self, m_asyncio):
|
|
||||||
self.worker.ppid = 1
|
|
||||||
self.worker.alive = True
|
|
||||||
self.worker.servers = []
|
|
||||||
sock = mock.Mock()
|
|
||||||
sock.cfg_addr = ('localhost', 8080)
|
|
||||||
self.worker.sockets = [sock]
|
|
||||||
self.worker.wsgi = mock.Mock()
|
|
||||||
self.worker.log = mock.Mock()
|
|
||||||
self.worker.notify = mock.Mock()
|
|
||||||
loop = self.worker.loop = mock.Mock()
|
|
||||||
loop.create_server.return_value = asyncio.Future(loop=self.loop)
|
|
||||||
loop.create_server.return_value.set_result(sock)
|
|
||||||
|
|
||||||
self.loop.run_until_complete(self.worker._run())
|
|
||||||
|
|
||||||
self.assertTrue(self.worker.log.info.called)
|
|
||||||
self.assertTrue(self.worker.notify.called)
|
|
||||||
|
|
||||||
@mock.patch('gunicorn.workers._gaiohttp.asyncio')
|
|
||||||
def test__run_unix_socket(self, m_asyncio):
|
|
||||||
self.worker.ppid = 1
|
|
||||||
self.worker.alive = True
|
|
||||||
self.worker.servers = []
|
|
||||||
sock = mock.Mock()
|
|
||||||
sock.cfg_addr = '/tmp/gunicorn.sock'
|
|
||||||
self.worker.sockets = [sock]
|
|
||||||
self.worker.wsgi = mock.Mock()
|
|
||||||
self.worker.log = mock.Mock()
|
|
||||||
self.worker.notify = mock.Mock()
|
|
||||||
loop = self.worker.loop = mock.Mock()
|
|
||||||
loop.create_server.return_value = asyncio.Future(loop=self.loop)
|
|
||||||
loop.create_server.return_value.set_result(sock)
|
|
||||||
|
|
||||||
self.loop.run_until_complete(self.worker._run())
|
|
||||||
|
|
||||||
self.assertTrue(self.worker.log.info.called)
|
|
||||||
self.assertTrue(self.worker.notify.called)
|
|
||||||
|
|
||||||
def test__run_connections(self):
|
|
||||||
conn = mock.Mock()
|
|
||||||
self.worker.ppid = 1
|
|
||||||
self.worker.alive = False
|
|
||||||
self.worker.servers = [mock.Mock()]
|
|
||||||
self.worker.connections = {1: conn}
|
|
||||||
self.worker.sockets = []
|
|
||||||
self.worker.wsgi = mock.Mock()
|
|
||||||
self.worker.log = mock.Mock()
|
|
||||||
self.worker.loop = self.loop
|
|
||||||
self.worker.loop.create_server = mock.Mock()
|
|
||||||
self.worker.notify = mock.Mock()
|
|
||||||
|
|
||||||
def _close_conns():
|
|
||||||
self.worker.connections = {}
|
|
||||||
|
|
||||||
self.loop.call_later(0.1, _close_conns)
|
|
||||||
self.loop.run_until_complete(self.worker._run())
|
|
||||||
|
|
||||||
self.assertTrue(self.worker.log.info.called)
|
|
||||||
self.assertTrue(self.worker.notify.called)
|
|
||||||
self.assertFalse(self.worker.servers)
|
|
||||||
self.assertTrue(conn.closing.called)
|
|
||||||
|
|
||||||
@mock.patch('gunicorn.workers._gaiohttp.os')
|
|
||||||
@mock.patch('gunicorn.workers._gaiohttp.asyncio.sleep')
|
|
||||||
def test__run_exc(self, m_sleep, m_os):
|
|
||||||
m_os.getpid.return_value = 1
|
|
||||||
m_os.getppid.return_value = 1
|
|
||||||
|
|
||||||
self.worker.servers = [mock.Mock()]
|
|
||||||
self.worker.ppid = 1
|
|
||||||
self.worker.alive = True
|
|
||||||
self.worker.sockets = []
|
|
||||||
self.worker.log = mock.Mock()
|
|
||||||
self.worker.loop = mock.Mock()
|
|
||||||
self.worker.notify = mock.Mock()
|
|
||||||
|
|
||||||
slp = asyncio.Future(loop=self.loop)
|
|
||||||
slp.set_exception(KeyboardInterrupt)
|
|
||||||
m_sleep.return_value = slp
|
|
||||||
|
|
||||||
self.loop.run_until_complete(self.worker._run())
|
|
||||||
self.assertTrue(m_sleep.called)
|
|
||||||
self.assertTrue(self.worker.servers[0].close.called)
|
|
||||||
|
|
||||||
def test_close_wsgi_app(self):
|
|
||||||
self.worker.ppid = 1
|
|
||||||
self.worker.alive = False
|
|
||||||
self.worker.servers = [mock.Mock()]
|
|
||||||
self.worker.connections = {}
|
|
||||||
self.worker.sockets = []
|
|
||||||
self.worker.log = mock.Mock()
|
|
||||||
self.worker.loop = self.loop
|
|
||||||
self.worker.loop.create_server = mock.Mock()
|
|
||||||
self.worker.notify = mock.Mock()
|
|
||||||
|
|
||||||
self.worker.wsgi = mock.Mock()
|
|
||||||
self.worker.wsgi.close.return_value = asyncio.Future(loop=self.loop)
|
|
||||||
self.worker.wsgi.close.return_value.set_result(1)
|
|
||||||
|
|
||||||
self.loop.run_until_complete(self.worker._run())
|
|
||||||
self.assertTrue(self.worker.wsgi.close.called)
|
|
||||||
|
|
||||||
self.worker.wsgi = mock.Mock()
|
|
||||||
self.worker.wsgi.close.return_value = asyncio.Future(loop=self.loop)
|
|
||||||
self.worker.wsgi.close.return_value.set_exception(ValueError())
|
|
||||||
|
|
||||||
self.loop.run_until_complete(self.worker._run())
|
|
||||||
self.assertTrue(self.worker.wsgi.close.called)
|
|
||||||
|
|
||||||
def test_wrp(self):
|
|
||||||
conn = object()
|
|
||||||
tracking = {}
|
|
||||||
meth = mock.Mock()
|
|
||||||
wrp = _wrp(conn, meth, tracking)
|
|
||||||
wrp()
|
|
||||||
|
|
||||||
self.assertIn(id(conn), tracking)
|
|
||||||
self.assertTrue(meth.called)
|
|
||||||
|
|
||||||
meth = mock.Mock()
|
|
||||||
wrp = _wrp(conn, meth, tracking, False)
|
|
||||||
wrp()
|
|
||||||
|
|
||||||
self.assertNotIn(1, tracking)
|
|
||||||
self.assertTrue(meth.called)
|
|
||||||
1
tox.ini
1
tox.ini
@ -14,7 +14,6 @@ commands =
|
|||||||
gunicorn \
|
gunicorn \
|
||||||
tests/test_arbiter.py \
|
tests/test_arbiter.py \
|
||||||
tests/test_config.py \
|
tests/test_config.py \
|
||||||
tests/test_gaiohttp.py \
|
|
||||||
tests/test_http.py \
|
tests/test_http.py \
|
||||||
tests/test_invalid_requests.py \
|
tests/test_invalid_requests.py \
|
||||||
tests/test_logger.py \
|
tests/test_logger.py \
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user