diff --git a/test/box/xlog.result b/test/box/xlog.result index 703e40f21b090c55220cdc5b214c229f27360a4d..ee29f761090a5aeddd3063cae4325018691efb8f 100644 --- a/test/box/xlog.result +++ b/test/box/xlog.result @@ -17,7 +17,6 @@ box.space[0]:insert(3, 'third tuple') - [3, 'third tuple'] ... 00000000000000000004.xlog.inprogress exists -Stopping the server... 00000000000000000004.xlog.inprogress has been successfully renamed # An inprogress xlog file with one record must be renamed during recovery. diff --git a/test/box/xlog.test.py b/test/box/xlog.test.py index df308636d58d64439570652dc232ca408ad689f0..09e0857698e178217f864b26d13991055e0b6fa4 100644 --- a/test/box/xlog.test.py +++ b/test/box/xlog.test.py @@ -1,9 +1,8 @@ -# encoding: utf-8 -# import os -from os.path import abspath import shutil +from os.path import abspath + # cleanup vardir server.stop() server.deploy() @@ -40,7 +39,7 @@ admin("box.space[0]:insert(3, 'third tuple')") if os.access(wal_inprogress, os.F_OK): print "00000000000000000004.xlog.inprogress exists" -server.stop(silent=False) +server.stop() if os.access(wal, os.F_OK) and not os.access(wal_inprogress, os.F_OK): print "00000000000000000004.xlog.inprogress has been successfully renamed" diff --git a/test/lib/colorer.py b/test/lib/colorer.py index f6059db015ca624b29970529f2fd3575eb065db3..642199eb43f0c1abfaa60577fa25b34223f6f6c5 100644 --- a/test/lib/colorer.py +++ b/test/lib/colorer.py @@ -1,53 +1,111 @@ +import os +import sys + +class Singleton(type): + _instances = {} + def __call__(cls, *args, **kwargs): + if cls not in cls._instances: + cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + return cls._instances[cls] + class Colorer(object): """ - Colorer/Styler for VT102+ (Not full). Based on: + Colorer/Styler based on VT220+ specifications (Not full). Based on: 1. ftp://ftp.cs.utk.edu/pub/shuford/terminal/dec_vt220_codes.txt 2. http://invisible-island.net/xterm/ctlseqs/ctlseqs.html """ - color = { - "black" : 0, - "red" : 1, - "green" : 2, - "yellow" : 3, - "blue" : 4, - "magenta" : 5, - "cyan" : 6, - "white" : 7 + __metaclass__ = Singleton + fgcolor = { + "black" : '0;30', + "red" : '0;31', + "green" : '0;32', + "brown" : '0;33', + "blue" : '0;34', + "magenta" : '0;35', + "cyan" : '0;36', + "grey" : '0;37', + "lgrey" : '1;30', + "lred" : '1;31', + "lgreen" : '1;32', + "yellow" : '1;33', + "lblue" : '1;34', + "lmagenta" : '1;35', + "lcyan" : '1;36', + "white" : '1;37', + } + bgcolor = { + "black" : '0;40', + "red" : '0;41', + "green" : '0;42', + "brown" : '0;43', + "blue" : '0;44', + "magenta" : '0;45', + "cyan" : '0;46', + "grey" : '0;47', + "lgrey" : '1;40', + "lred" : '1;41', + "lgreen" : '1;42', + "yellow" : '1;43', + "lblue" : '1;44', + "lmagenta" : '1;45', + "lcyan" : '1;46', + "white" : '1;47', } - foreground = 30 - background = 40 attributes = { - "off" : 0, + "bold" : '1', + "underline" : '4', + "blinking" : '5', + "negative" : '7', + "invisible" : '8', + } + begin = "\033[" + end = "m" + disable = begin+'0'+end - "bold" : 1, - "booff" : 22, + def __init__(self): + self.stdout = sys.stdout + self.is_term = self.stdout.isatty() + self.colors = int(os.popen('tput colors').read()) if self.is_term else None - "underline" : 4, - "unoff" : 24, + def set_stdout(self): + sys.stdout = self - "blinking" : 5, - "bloff" : 25, + def ret_stdout(self): + sys.stdout = self.stdout - "negative" : 7, - "neoff" : 27, + def write(self, *args, **kwargs): + flags = [] + for i in self.attributes: + if i in kwargs and kwargs[i] == True: + flags.append(self.attributes[i]) + flags.append(self.fgcolor[kwargs['fgcolor']]) if 'fgcolor' in kwargs else None + flags.append(self.bgcolor[kwargs['bgcolor']]) if 'bgcolor' in kwargs else None - "invisible": 8 - "inoff" : 28, - } - disable = "\033[0m" - def __init__(self): - self.stdout = sys.stdout - self.is_term = self.stdout.isatty() + if self.is_term: + self.stdout.write(self.begin+';'.join(flags)+self.end) + for i in args: + self.stdout.write(str(i)) + if self.is_term: + self.stdout.write(self.disable) + self.stdout.flush() + + def __call__(self, *args, **kwargs): + self.write(*args, **kwargs) + + def writeout_unidiff(self, diff): + for i in diff: + if i.startswith('+'): + self.write(i, fgcolor='blue') + elif i.startswith('-'): + self.write(i, fgcolor='red') + elif i.startswith('@'): + self.write(i, fgcolor='magenta') + + def flush(self): + return self.stdout.flush() + + def fileno(self): + return self.stdout.fileno() - def write(self, *args **kwargs): - a.push() - fgcolor = kwargs['fgcolor'] if 'fgcolor' in kwargs else None - a.push(str(self.color[kwargs['fgcolor']]+self.foreground)) - bgcolor = kwargs['bgcolor'] if 'bgcolor' in kwargs else None - bold = kwargs['bold'] if 'bold' in kwargs else False - uline = kwargs['underline'] if 'underline' in kwargs else False - blink = kwargs['blinking'] if 'blinking' in kwargs else False - neg = kwargs['negative'] if 'negative' in kwargs else False - inv = kwargs['invisible'] if 'invisible' in kwargs else False - - self.stdout.write() + def isatty(self): + return self.is_term diff --git a/test/lib/tarantool_server.py b/test/lib/tarantool_server.py index 033cf342f102c28babca1107c3bb86c1dd9fec2b..575f4a0bf014f57b816f72ae39221ba8f1fa0787 100644 --- a/test/lib/tarantool_server.py +++ b/test/lib/tarantool_server.py @@ -21,7 +21,7 @@ from lib.test_suite import FilteredStream, Test, check_libs from lib.admin_connection import AdminConnection from lib.preprocessor import State - +from lib.colorer import Colorer try: import cStringIO as StringIO except ImportError: @@ -29,6 +29,7 @@ except ImportError: check_libs() import tarantool +color_stdout = Colorer() def check_port(port): """Check if the port we're connecting to is available""" @@ -165,7 +166,8 @@ class TarantoolServer(Server): builddir = os.path.join(builddir, "src/box") path = builddir + os.pathsep + os.environ["PATH"] if not silent: - print "Looking for server binary in {0} ...".format(path) + color_stdout("Looking for server binary in ", fgcolor='lmagenta') + color_stdout(path+" ...\n", fgcolor='green') for _dir in path.split(os.pathsep): exe = os.path.join(_dir, self.default_bin_name) if os.access(exe, os.X_OK): @@ -185,13 +187,15 @@ class TarantoolServer(Server): self.valgrind_log = os.path.abspath(os.path.join(self.vardir, self.valgrind_log)) if not silent: - print "Installing the server..." - print " Found executable at " + self.binary - print " Creating and populating working directory in " + self.vardir + "..." + color_stdout("Installing the server ...\n", fgcolor='lmagenta') + color_stdout(" Found executable at ", fgcolor='lmagenta') + color_stdout(self.binary+'\n', fgcolor='green', bold=True) + color_stdout(" Creating and populating working directory in ", fgcolor='lmagenta') + color_stdout(self.vardir+' ...\n', fgcolor='green', bold=True) if os.access(self.vardir, os.F_OK): if not silent: - print " Found old vardir, deleting..." + color_stdout(" Found old vardir, deleting ...\n", fgcolor='lmagenta') self.kill_old_server() self.cleanup() else: @@ -302,21 +306,23 @@ class TarantoolServer(Server): if self.is_started: if not silent: - print "The server is already started." + color_stdout("The server is already started.\n", fgcolor='lred') return if not silent: - print "Starting the server..." + color_stdout("Starting the server ...\n", fgcolor='lmagenta') version = self.version() - print "Starting {0} {1}.".format(os.path.basename(self.binary), version) + color_stdout("Starting ", fgcolor='lmagenta') + color_stdout(os.path.basename(self.binary), " \n", fgcolor='green') + color_stdout(version, "\n", fgcolor='grey') check_port(self.port) args = self.prepare_args() if self.gdb: args = prepare_gdb(self.binary, args) - print "You started the server in gdb mode." - print "To attach, use `screen -r tnt-gdb`" + color_stdout("You started the server in gdb mode.\n", fgcolor='yellow', bold=True) + color_stdout("To attach, use `screen -r tnt-gdb`\n", fgcolor='yellow', bold=True) elif self.valgrind: args = prepare_valgrind([self.binary] + args, self.valgrind_log, os.path.abspath(os.path.join(self.vardir, @@ -342,11 +348,11 @@ class TarantoolServer(Server): start up.""" if not self.is_started: if not silent: - print "The server is not started." + color_stdout("The server is not started.\n", fgcolor='red') return if not silent: - print "Stopping the server..." + color_stdout("Stopping the server ...\n", fgcolor='lmagenta') if self.process == None: self.kill_old_server() @@ -424,7 +430,7 @@ class TarantoolServer(Server): return # Nothing to do if not silent: - print " Found old server, pid {0}, killing...".format(pid) + color_stdout(" Found old server, pid {0}, killing ...".format(pid), fgcolor='yellow') try: os.kill(pid, signal.SIGTERM) @@ -446,13 +452,11 @@ class TarantoolServer(Server): pass return pid - def print_log(self, lines, stdout=None): - if stdout is None: - stdout = sys.stdout - stdout.write("\nLast {0} lines of Tarantool Log file:\n".format(lines)) + def print_log(self, lines): + color_stdout.write("\nLast {0} lines of Tarantool Log file:\n".format(lines), fgcolor='lred') with open(os.path.join(self.vardir, 'tarantool.log'), 'r') as log: for i in log.readlines()[-lines:]: - stdout.write(i) + color_stdout.write(i, fgcolor='grey') def wait_until_started(self): """Wait until the server is started and accepting connections""" diff --git a/test/lib/test_suite.py b/test/lib/test_suite.py index 57678a72dbfe93294b6aafd5939af9bc4e1d7a08..cf507f604433008079f36d293947aca2a684f9db 100644 --- a/test/lib/test_suite.py +++ b/test/lib/test_suite.py @@ -11,7 +11,9 @@ import collections import ConfigParser from lib.server import Server +from lib.colorer import Colorer +color_stdout = Colorer() try: from cStringIO import StringIO except ImportError: @@ -87,7 +89,7 @@ def print_tail_n(filename, num_lines): with open(filename, "r+") as logfile: tail_n = collections.deque(logfile, num_lines) for line in tail_n: - sys.stdout.write(line) + color_stdout.write(line, fgcolor='lblue') class Test: @@ -172,20 +174,20 @@ class Test: check_valgrind_log(server.valgrind_log) == False elif self.skip: - print "[ SKIP ]" + color_stdout("[ SKIP ]\n", fgcolor='grey') if os.path.exists(self.tmp_result): os.remove(self.tmp_result) elif self.is_executed_ok and self.is_equal_result and self.is_valgrind_clean: - print "[ PASS ]" + color_stdout("[ PASS ]\n", fgcolor='green') if os.path.exists(self.tmp_result): os.remove(self.tmp_result) elif (self.is_executed_ok and not self.is_equal_result and not os.path.isfile(self.result)): os.rename(self.tmp_result, self.result) - print "[ NEW ]" + color_stdout("[ NEW ]\n", fgcolor='lblue') else: os.rename(self.tmp_result, self.reject) - print "[ FAIL ]" if not self.is_terminated else "[ TERMINATED ]" + color_stdout("[ FAIL ]\n" if not self.is_terminated else "[ TERMINATED ]\n", fgcolor='red') where = "" if not self.is_executed_ok: @@ -208,7 +210,7 @@ class Test: """Print 10 lines of client program output leading to test failure. Used to diagnose a failure of the client program""" - print message + color_stdout(message, color='lred') print_tail_n(logfile, 10) def print_unidiff(self): @@ -216,7 +218,7 @@ class Test: to establish the cause of a failure when .test differs from .result.""" - print "Test failed! Result content mismatch:" + color_stdout("\nTest failed! Result content mismatch:\n", fgcolor='lred') with open(self.result, "r") as result: with open(self.reject, "r") as reject: result_time = time.ctime(os.stat(self.result).st_mtime) @@ -227,8 +229,8 @@ class Test: self.reject, result_time, reject_time) - for line in diff: - sys.stdout.write(line) + + color_stdout.writeout_unidiff(diff) class TestSuite: """Each test suite contains a number of related tests files, @@ -280,10 +282,11 @@ class TestSuite: raise RuntimeError("Unknown server: core = {0}".format( self.ini["core"])) - print "Collecting tests in \"" + suite_path + "\": " +\ - self.ini["description"] + "." + color_stdout("Collecting tests in ", fgcolor='lmagenta') + color_stdout(repr(suite_path), fgcolor='green') + color_stdout(": ", self.ini["description"], ".\n", fgcolor='lmagenta') self.server.find_tests(self, suite_path) - print "Found " + str(len(self.tests)) + " tests." + color_stdout("Found ", str(len(self.tests)), " tests.\n", fgcolor='green') def run_all(self): """For each file in the test suite, run client program @@ -307,45 +310,46 @@ class TestSuite: shutil.copy(i, self.args.vardir) if self.args.start_and_exit: - print " Start and exit requested, exiting..." + color_stdout(" Start and exit requested, exiting...\n", fgcolor='yellow') exit(0) longsep = '='*70 shortsep = '-'*60 - print longsep - print "TEST".ljust(48), "RESULT" - print shortsep + color_stdout(longsep, "\n", fgcolor='blue') + color_stdout("TEST".ljust(48), fgcolor='lblue') + color_stdout("RESULT\n", fgcolor='green') + color_stdout(shortsep, "\n", fgcolor='blue') failed_tests = [] try: for test in self.tests: - sys.stdout.write(test.name.ljust(48)) + color_stdout(test.name.ljust(48), fgcolor='lblue') # for better diagnostics in case of a long-running test - sys.stdout.flush() test_name = os.path.basename(test.name) if (test_name in self.ini["disabled"] or not self.server.debug and test_name in self.ini["release_disabled"] or self.args.valgrind and test_name in self.ini["valgrind_disabled"]): - print "[ DISABLED ]" + color_stdout("[ DISABLED ]\n", fgcolor='grey') else: test.run(self.server) if not test.passed(): failed_tests.append(test.name) except (KeyboardInterrupt) as e: - print '\n', + color_stdout('\n') raise finally: - print shortsep + color_stdout(shortsep, "\n", fgcolor='blue') self.server.stop(silent=False) self.server.cleanup() if failed_tests: - print "Failed {0} tests: {1}.".format(len(failed_tests), - ", ".join(failed_tests)) + color_stdout("Failed {0} tests: {1}.".format(len(failed_tests), + ", ".join(failed_tests)), + fgcolor='red') if self.args.valgrind and check_valgrind_log(self.server.valgrind_log): - print " Error! There were warnings/errors in valgrind log file:" + color_stdout(" Error! There were warnings/errors in valgrind log file:", fgcolor='red') print_tail_n(self.server.valgrind_log, 20) return ['valgrind error in ' + self.suite_path] return failed_tests diff --git a/test/test-run.py b/test/test-run.py index f085dc32b4e1cf951c485bf7ad160f69bd1c9963..7b6a0d74905170474a1dd7f9d34ca122e8a4e670 100755 --- a/test/test-run.py +++ b/test/test-run.py @@ -32,8 +32,10 @@ import shutil import os.path import argparse +from lib.colorer import Colorer from lib.test_suite import TestSuite +color_stdout = Colorer() # # Run a collection of tests. # @@ -130,7 +132,7 @@ class Options: """Check the arguments for correctness.""" check_error = False if self.args.gdb and self.args.valgrind: - print "Error: option --gdb is not compatible with option --valgrind" + color_stdout("Error: option --gdb is not compatible with option --valgrind", fgcolor='red') check_error = True if check_error: exit(-1) @@ -167,7 +169,7 @@ def main(): failed_tests = [] try: - print "Started", " ".join(sys.argv) + color_stdout("Started {}\n".format(" ".join(sys.argv)), fgcolor='green') suite_names = [] if options.args.suites != []: suite_names = options.args.suites @@ -181,7 +183,7 @@ def main(): for suite in suites: failed_tests.extend(suite.run_all()) except RuntimeError as e: - print "\nFatal error: {0}. Execution aborted.".format(e) + color_stdout("\nFatal error: {0}. Execution aborted.\n".format(e), fgcolor='red') if options.args.gdb: time.sleep(100) return (-1) @@ -189,9 +191,9 @@ def main(): os.chdir(oldcwd) if failed_tests and options.args.is_force: - print '\n===== %d tests failed:' % len(failed_tests) + color_stdout("\n===== {0} tests failed:".format(len(failed_tests))+"\n", fgcolor="red") for test in failed_tests: - print "----- %s" % test + color_stdout("----- "+test+"\n", fgcolor="yellow") return (-1 if failed_tests else 0)