You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
5.4 KiB
Python

from __future__ import print_function
from __future__ import absolute_import
import gevent
from gevent import socket
from gevent import backdoor
import gevent.testing as greentest
from gevent.testing.params import DEFAULT_BIND_ADDR_TUPLE
from gevent.testing.params import DEFAULT_CONNECT
def read_until(conn, postfix):
read = b''
assert isinstance(postfix, bytes)
while not read.endswith(postfix):
result = conn.recv(1)
if not result:
raise AssertionError('Connection ended before %r. Data read:\n%r' % (postfix, read))
read += result
return read if isinstance(read, str) else read.decode('utf-8')
def readline(conn):
with conn.makefile() as f:
return f.readline()
class WorkerGreenlet(gevent.Greenlet):
spawning_stack_limit = 2
class SocketWithBanner(socket.socket):
__slots__ = ('banner',)
def __init__(self, *args, **kwargs):
self.banner = None
super(SocketWithBanner, self).__init__(*args, **kwargs)
def __enter__(self):
return socket.socket.__enter__(self)
def __exit__(self, t, v, tb):
return socket.socket.__exit__(self, t, v, tb)
@greentest.skipOnAppVeyor(
"With the update to libev 4.31 and potentially closing sockets in the background, "
"alternate tests started hanging on appveyor. Something like .E.E.E. "
"See https://ci.appveyor.com/project/denik/gevent/build/job/n9fynkoyt2bvk8b5 "
"It's not clear why, but presumably a socket isn't getting closed and a watcher is tied "
"to the wrong file descriptor. I haven't been able to reproduce. If it were a systemic "
"problem I'd expect to see more failures, so it is probably specific to resource management "
"in this test."
)
class Test(greentest.TestCase):
__timeout__ = 10
def tearDown(self):
gevent.sleep() # let spawned greenlets die
super(Test, self).tearDown()
def _make_and_start_server(self, *args, **kwargs):
server = backdoor.BackdoorServer(DEFAULT_BIND_ADDR_TUPLE, *args, **kwargs)
server.start()
return server
def _create_connection(self, server):
conn = SocketWithBanner()
conn.connect((DEFAULT_CONNECT, server.server_port))
try:
banner = self._wait_for_prompt(conn)
except:
conn.close()
raise
else:
conn.banner = banner
return conn
def _wait_for_prompt(self, conn):
return read_until(conn, b'>>> ')
def _close(self, conn, cmd=b'quit()\r\n)'):
conn.sendall(cmd)
line = readline(conn)
self.assertEqual(line, '')
conn.close()
@greentest.skipOnLibuvOnTravisOnCPython27(
"segfaults; "
"See https://github.com/gevent/gevent/pull/1156")
def test_multi(self):
with self._make_and_start_server() as server:
def connect():
with self._create_connection(server) as conn:
conn.sendall(b'2+2\r\n')
line = readline(conn)
self.assertEqual(line.strip(), '4', repr(line))
self._close(conn)
jobs = [WorkerGreenlet.spawn(connect) for _ in range(10)]
try:
done = gevent.joinall(jobs, raise_error=True)
finally:
gevent.joinall(jobs, raise_error=False)
self.assertEqual(len(done), len(jobs), done)
def test_quit(self):
with self._make_and_start_server() as server:
with self._create_connection(server) as conn:
self._close(conn)
def test_sys_exit(self):
with self._make_and_start_server() as server:
with self._create_connection(server) as conn:
self._close(conn, b'import sys; sys.exit(0)\r\n')
def test_banner(self):
expected_banner = "Welcome stranger!" # native string
with self._make_and_start_server(banner=expected_banner) as server:
with self._create_connection(server) as conn:
banner = conn.banner
self._close(conn)
self.assertEqual(banner[:len(expected_banner)], expected_banner, banner)
def test_builtins(self):
with self._make_and_start_server() as server:
with self._create_connection(server) as conn:
conn.sendall(b'locals()["__builtins__"]\r\n')
response = read_until(conn, b'>>> ')
self._close(conn)
self.assertLess(
len(response), 300,
msg="locals() unusable: %s..." % response)
def test_switch_exc(self):
from gevent.queue import Queue, Empty
def bad():
q = Queue()
print('switching out, then throwing in')
try:
q.get(block=True, timeout=0.1)
except Empty:
print("Got Empty")
print('switching out')
gevent.sleep(0.1)
print('switched in')
with self._make_and_start_server(locals={'bad': bad}) as server:
with self._create_connection(server) as conn:
conn.sendall(b'bad()\r\n')
response = self._wait_for_prompt(conn)
self._close(conn)
response = response.replace('\r\n', '\n')
self.assertEqual(
'switching out, then throwing in\nGot Empty\nswitching out\nswitched in\n>>> ',
response)
if __name__ == '__main__':
greentest.main() # pragma: testrunner-no-combine