Files

93 lines
2.7 KiB
Python

import logging
import multiprocessing
import os
import signal
import socket
import time
import pytest
from ._internal import deprecated
class LiveServer:
"""The helper class used to manage a live server. Handles creation and
stopping application in a separate process.
:param app: The application to run.
:param host: The host where to listen (default localhost).
:param port: The port to run application.
:param wait: The timeout after which test case is aborted if
application is not started.
"""
def __init__(self, app, host, port, wait, clean_stop=False):
self.app = app
self.port = port
self.host = host
self.wait = wait
self.clean_stop = clean_stop
self._process = None
def start(self):
"""Start application in a separate process."""
def worker(app, host, port):
app.run(host=host, port=port, use_reloader=False, threaded=True)
self._process = multiprocessing.Process(
target=worker, args=(self.app, self.host, self.port)
)
self._process.daemon = True
self._process.start()
keep_trying = True
start_time = time.time()
while keep_trying:
elapsed_time = time.time() - start_time
if elapsed_time > self.wait:
pytest.fail(
"Failed to start the server after {!s} "
"seconds.".format(self.wait)
)
if self._is_ready():
keep_trying = False
def _is_ready(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((self.host, self.port))
except socket.error:
ret = False
else:
ret = True
finally:
sock.close()
return ret
def stop(self):
"""Stop application process."""
if self._process:
if self.clean_stop and self._stop_cleanly():
return
if self._process.is_alive():
# If it's still alive, kill it
self._process.terminate()
def _stop_cleanly(self, timeout=5):
"""Attempts to stop the server cleanly by sending a SIGINT signal and waiting for
``timeout`` seconds.
:return: True if the server was cleanly stopped, False otherwise.
"""
try:
os.kill(self._process.pid, signal.SIGINT)
self._process.join(timeout)
return True
except Exception as ex:
logging.error("Failed to join the live server process: %r", ex)
return False
def __repr__(self):
return "<LiveServer listening at %s>" % self.url()