From c1b1b14c80a0ea285c8d3b7867cfce70321e7e29 Mon Sep 17 00:00:00 2001 From: Alexander Turenko Date: Mon, 30 Nov 2020 02:35:22 +0300 Subject: [PATCH 1/2] refactoring: provide internal qa_notice() function Now we have only one place, where a [QA Notice] message is printed. But we'll have more and it is convenient to have one function for this purpose. The function should be used in places, where we observe an incorrect behaviour of tarantool or a test, but want to lower it to a warning and proceed further. Of course, there should be a solid reason to do so. Part of #157 --- lib/colorer.py | 27 +++++++++++++++++++++++++++ lib/inspector.py | 4 ++-- 2 files changed, 29 insertions(+), 2 deletions(-) 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() From cf397eb50f81c84e8a8204fbfc77e9543f59715f Mon Sep 17 00:00:00 2001 From: Roman Tokarev Date: Mon, 19 Aug 2019 11:03:44 +0300 Subject: [PATCH 2/2] Send SIGKILL if server does not stop after timeout If a tarantool instance does not handle SIGTERM correctly, it is the bug in tarantool. A testing system should reveal problems rather than hide them. However this patch doing that and I'll explain why. Many tests we have perform instance starting / stopping: they are written to spot different problems, but not this one. If everything else except hanging at stop is okay, there is no reason to fail the test. We print a notice on the terminal in the case and proceed further. In future, when all problems of this kind will be resolved, we can interpret presence of such notices as error. However now it'll not add anything for quality of our testing. We had a problem of this kind ([1]) in the past and now have another one ([2]). Until it will be resolved, it worth to handle the situation on the testing system side. [1]: https://github.com/tarantool/tarantool/issues/4127 [2]: https://github.com/tarantool/tarantool/issues/5573 Part of #157 Co-authored-by: Alexander Turenko --- lib/tarantool_server.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) 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)):