diff --git a/lib/colorer.py b/lib/colorer.py index d6fae06f..8c867c1b 100644 --- a/lib/colorer.py +++ b/lib/colorer.py @@ -20,6 +20,33 @@ def color_log(*args, **kwargs): color_stdout(*args, **kwargs) +def qa_notice(*args, **kwargs): + """ Print a notice for an QA engineer at the terminal. + + Example:: + + * [QA Notice] + * + * Attempt to stop already stopped server 'foo' + * + """ + # Import from the function to avoid recursive import. + from lib.utils import prefix_each_line + + # Use 'info' color by default (yellow). + if 'schema' not in kwargs: + kwargs = dict(kwargs, schema='info') + + # Join all positional arguments (like color_stdout() do) and + # decorate with a header and asterisks. + data = ''.join([str(msg) for msg in args]) + data = prefix_each_line('* ', data) + data = '\n* [QA Notice]\n*\n{}*\n'.format(data) + + # Write out. + color_stdout(data, **kwargs) + + class CSchema(object): objects = {} diff --git a/lib/inspector.py b/lib/inspector.py index f730f0f0..1d68deaa 100644 --- a/lib/inspector.py +++ b/lib/inspector.py @@ -10,6 +10,7 @@ from lib.utils import prefix_each_line from lib.colorer import color_stdout from lib.colorer import color_log +from lib.colorer import qa_notice from lib.tarantool_server import TarantoolStartError from lib.preprocessor import LuaPreprocessorException @@ -102,8 +103,7 @@ def handle(self, socket, addr): # propagate to the main greenlet raise except LuaPreprocessorException as e: - color_stdout('\n* [QA Notice]\n*\n* {0}\n*\n'.format(str(e)), - schema='info') + qa_notice(str(e)) result = {'error': str(e)} except Exception as e: self.parser.kill_current_test() diff --git a/lib/tarantool_server.py b/lib/tarantool_server.py index 8799602b..d35b9aaf 100644 --- a/lib/tarantool_server.py +++ b/lib/tarantool_server.py @@ -15,6 +15,7 @@ from gevent import socket from greenlet import GreenletExit +from threading import Timer try: from cStringIO import StringIO @@ -23,7 +24,9 @@ from lib.admin_connection import AdminConnection, AdminAsyncConnection from lib.box_connection import BoxConnection -from lib.colorer import color_stdout, color_log +from lib.colorer import color_stdout +from lib.colorer import color_log +from lib.colorer import qa_notice from lib.preprocessor import TestState from lib.server import Server from lib.test import Test @@ -984,9 +987,26 @@ def stop(self, silent=True, signal=signal.SIGTERM): self.process.send_signal(signal) except OSError: pass + + # Waiting for stopping the server. If the timeout + # reached, send SIGKILL. + timeout = 5 + + def kill(): + qa_notice('The server \'{}\' does not stop during {} ' + 'seconds after the {} ({}) signal.\n' + 'Info: {}\n' + 'Sending SIGKILL...'.format( + self.name, timeout, signal, signame(signal), + format_process(self.process.pid))) + self.process.kill() + + timer = Timer(timeout, kill) + timer.start() if self.crash_detector is not None: save_join(self.crash_detector) self.wait_stop() + timer.cancel() self.status = None if re.search(r'^/', str(self._admin.port)):