diff --git a/test/lib/tarantool_connection.py b/test/lib/tarantool_connection.py index 5dfdd481e2416692a60292c89f859ef21510caf0..dc4ccf1dd7b30e7c323dbc705d2010bce0efb1cc 100644 --- a/test/lib/tarantool_connection.py +++ b/test/lib/tarantool_connection.py @@ -58,8 +58,11 @@ class AdminConnection: try: if self.socket.recv(0, socket.MSG_DONTWAIT) == '': self.reconnect() - except socket.error: - pass + except socket.error as e: + if e.errno == 11: + pass + else: + self.reconnect() def execute(self, command): self.opt_reconnect() diff --git a/test/lib/tarantool_silverbox_server.py b/test/lib/tarantool_silverbox_server.py index d8b169390cdc5bf26219a30ed64736e41c41a504..634e6696fe9e407efd224300e6d2325342110b8f 100644 --- a/test/lib/tarantool_silverbox_server.py +++ b/test/lib/tarantool_silverbox_server.py @@ -7,6 +7,7 @@ import sys import signal import time import socket +import daemon def wait_until_connected(host, port): """Wait until the server is started and accepting connections""" @@ -32,8 +33,14 @@ def prepare_gdb(args, vardir): if term not in ["xterm", "rxvt", "urxvt", "gnome-terminal", "konsole"]: raise RuntimeError("--gdb: unsupported terminal {0}".format(term)) - gdbargs = '{0} -e gdb {1} -ex "break main" -ex "run"'.format(term, args[0]) - args = [ "/bin/sh", "-c", gdbargs ] + args = [ term, "-e ", "gdb", "-ex", "break main", "-ex", "run"] + args + return args + + +def prepare_valgrind(args, valgrind_args, vardir): + "Prepare server startup argumetns to run under valgrind." + args = ([ "valgrind", "--log-file=valgrind.log", "--quiet" ] + + valgrind_args.split(",") + args) return args @@ -113,7 +120,7 @@ class TarantoolSilverboxServer: if not silent: print "Starting {0} {1}.".format(os.path.basename(self.abspath_to_exe), version) - + def start(self, silent = False): if self.is_started: @@ -126,14 +133,27 @@ class TarantoolSilverboxServer: args = [self.abspath_to_exe] - if self.args.start_and_exit: + if (self.args.start_and_exit and not self.args.valgrind + and not self.args.gdb): args.append("--daemonize") if self.args.gdb: args = prepare_gdb(args, self.args.vardir) + elif self.args.valgrind: + args = prepare_valgrind(args, self.args.valgrind_args, self.args.vardir) - self.server = pexpect.spawn(args[0], args[1:], cwd = self.args.vardir) -# wait until the server is connectedk + if self.args.start_and_exit and self.args.valgrind: + pid = os.fork() + if pid > 0: + os.wait() + else: + with daemon.DaemonContext(working_directory = self.args.vardir): + os.execvp(args[0], args) + else: + self.server = pexpect.spawn(args[0], args[1:], cwd = self.args.vardir) + if self.args.start_and_exit: + self.server.wait() +# wait until the server is connectedk if self.args.gdb and self.args.start_and_exit: time.sleep(1) elif not self.args.start_and_exit and not self.args.gdb: diff --git a/test/lib/test_suite.py b/test/lib/test_suite.py index a41cc088e4445de6f7aba13d0c27b9c9f8fd1c44..3a2c479ef9815911e6ff49ed5a9b5e05dd705b48 100644 --- a/test/lib/test_suite.py +++ b/test/lib/test_suite.py @@ -56,16 +56,19 @@ class FilteredStream: class Test: """An individual test file. A test can run itself, and remembers its completion state.""" - def __init__(self, name, suite_ini): + def __init__(self, name, args, suite_ini): """Initialize test properties: path to test file, path to temporary result file, path to the client program, test status.""" self.name = name self.result = name.replace(".test", ".result") self.reject = name.replace(".test", ".reject") + self.valgrind_log = args.vardir + "/valgrind.log" + self.args = args self.suite_ini = suite_ini self.is_executed = False self.is_executed_ok = None self.is_equal_result = None + self.is_valgrind_clean = True def passed(self): """Return true if this test was run successfully.""" @@ -112,7 +115,10 @@ class Test: if self.is_executed_ok and os.path.isfile(self.result): self.is_equal_result = filecmp.cmp(self.result, self.reject) - if self.is_executed_ok and self.is_equal_result: + if self.args.valgrind: + self.is_valgrind_clean = os.path.getsize(self.valgrind_log) == 0 + + if self.is_executed_ok and self.is_equal_result and self.is_valgrind_clean: print "[ pass ]" os.remove(self.reject) elif (self.is_executed_ok and not self.is_equal_result and not @@ -125,6 +131,9 @@ class Test: if not self.is_executed_ok: self.print_diagnostics() where = ": test execution aborted, reason '{0}'".format(diagnostics) + elif not self.is_valgrind_clean: + print "Test failed! Valgrind reports errors" \ + " (see {0}/valgrind.log)".format(self.args.vardir) else: self.print_unidiff() where = ": wrong test output" @@ -224,7 +233,7 @@ class TestSuite: for test_name in glob.glob(os.path.join(suite_path, "*.test")): for test_pattern in self.args.tests: if test_name.find(test_pattern) != -1: - self.tests.append(Test(test_name, self.ini)) + self.tests.append(Test(test_name, self.args, self.ini)) print "Found " + str(len(self.tests)) + " tests." def run_all(self): diff --git a/test/test-run.py b/test/test-run.py index 4321b2e3be520e8b1ed0bcf80ff4392f8d4c1f8e..ae232599b7c17f69661814eea3f87339cbe8bbab 100755 --- a/test/test-run.py +++ b/test/test-run.py @@ -95,6 +95,19 @@ class Options: help = "Start the server under 'gdb' debugger. Default: false." " See also --start-and-exit.") + parser.add_argument( + "--valgrind", + dest = "valgrind", + action = "store_true", + default = False, + help = "Start the server under 'valgrind'. Default: false.") + + parser.add_argument( + "--valgrind-args", + dest = "valgrind_args", + default = "--tool=memcheck", + help = "Arguments passed to 'valgrind'. Default: --tool=memcheck.") + parser.add_argument( "--bindir", dest = "bindir",