Use eventlet.patcher.original to get Python select module in get_hub

get_hub function was added in commit b155da42 with the idea to bypass
eventlet automatic hub selection that prefers epoll if available by default.

Since version 0.20.0 eventlet removed select.poll() function in its patched
select module (eventlet.green.select), see:
   - https://github.com/eventlet/eventlet/commit/614a20462

So if eventlet monkey patching is done before a get_hub() call (as now in
wsgi.py since commit c9410c7d) if we use 'import select' we get the eventlet
version that don't have poll attribute.

To prevent that we use eventlet.patcher.original function to get python select
module to test if poll() is available on current platform.

Change-Id: I69b3db3951b3d3b6583845978deb2883492e7f0f
Closes-Bug: 1804627
(cherry picked from commit 4809884d9f)
This commit is contained in:
Romain de Joux 2018-11-22 11:24:02 +01:00 committed by Tim Burke
parent b38a303d68
commit 8eba4f8c8f
2 changed files with 42 additions and 1 deletions

View File

@ -2015,9 +2015,18 @@ def get_hub():
In contrast, both poll() and select() specify the set of interesting
file descriptors with each call, so there's no problem with forking.
As eventlet monkey patching is now done before call get_hub() in wsgi.py
if we use 'import select' we get the eventlet version, but since version
0.20.0 eventlet removed select.poll() function in patched select (see:
http://eventlet.net/doc/changelog.html and
https://github.com/eventlet/eventlet/commit/614a20462).
We use eventlet.patcher.original function to get python select module
to test if poll() is available on platform.
"""
try:
import select
select = eventlet.patcher.original('select')
if hasattr(select, "poll"):
return "poll"
return "selects"

View File

@ -4542,6 +4542,38 @@ class TestFileLikeIter(unittest.TestCase):
iter_file.close()
self.assertTrue(iter_file.closed)
def test_get_hub(self):
# This test mock the eventlet.green.select module without poll
# as in eventlet > 0.20
# https://github.com/eventlet/eventlet/commit/614a20462
# We add __original_module_select to sys.modules to mock usage
# of eventlet.patcher.original
class SelectWithPoll(object):
def poll():
pass
class SelectWithoutPoll(object):
pass
# Platform with poll() that call get_hub before eventlet patching
with mock.patch.dict('sys.modules',
{'select': SelectWithPoll,
'__original_module_select': SelectWithPoll}):
self.assertEqual(utils.get_hub(), 'poll')
# Platform with poll() that call get_hub after eventlet patching
with mock.patch.dict('sys.modules',
{'select': SelectWithoutPoll,
'__original_module_select': SelectWithPoll}):
self.assertEqual(utils.get_hub(), 'poll')
# Platform without poll() -- before or after patching doesn't matter
with mock.patch.dict('sys.modules',
{'select': SelectWithoutPoll,
'__original_module_select': SelectWithoutPoll}):
self.assertEqual(utils.get_hub(), 'selects')
class TestStatsdLogging(unittest.TestCase):
def setUp(self):