From 1b3aacb8373590b5ce834a7c4e99a821b9b910f9 Mon Sep 17 00:00:00 2001 From: Foo Date: Sun, 30 Apr 2017 13:18:50 +0300 Subject: [PATCH] Move most of the vterm testing code to tests.lib.terminal --- tests/lib/terminal.py | 121 +++++++++++++++++++++++ tests/test_in_vterm/test_tmux.py | 159 +++++++------------------------ 2 files changed, 154 insertions(+), 126 deletions(-) diff --git a/tests/lib/terminal.py b/tests/lib/terminal.py index 29177e2a..84e4be1b 100644 --- a/tests/lib/terminal.py +++ b/tests/lib/terminal.py @@ -2,13 +2,17 @@ from __future__ import (unicode_literals, division, absolute_import, print_function) import threading +import os from time import sleep from itertools import groupby from signal import SIGKILL +from difflib import ndiff import pexpect +from powerline.lib.unicode import u + from tests.lib.vterm import VTerm, Dimensions @@ -135,3 +139,120 @@ class ExpectProcess(threading.Thread): line, attrs = self.get_row(row, attrs, default_props) lines.append(line) return '\n'.join(lines), attrs + + +def test_expected_result(p, expected_result, last_attempt, + last_attempt_cb=None): + expected_text, attrs = expected_result + attempts = 3 + result = None + while attempts: + actual_text, all_attrs = p.get_row(p.dim.rows - 1, attrs) + if actual_text == expected_text: + return True + attempts -= 1 + print('Actual result does not match expected. Attempts left: {0}.'.format(attempts)) + sleep(2) + print('Result:') + print(actual_text) + print('Expected:') + print(expected_text) + print('Attributes:') + print(all_attrs) + print('Screen:') + screen, screen_attrs = p.get_screen(attrs) + print(screen) + print(screen_attrs) + print('_' * 80) + print('Diff:') + print('=' * 80) + print(''.join(( + u(line) for line in ndiff([actual_text + '\n'], [expected_text + '\n'])) + )) + if last_attempt and last_attempt_cb: + last_attempt_cb() + return False + + +ENV_BASE = { + # Reasoning: + # 1. vt* TERMs (used to be vt100 here) make tmux-1.9 use different and + # identical colors for inactive windows. This is not like tmux-1.6: + # foreground color is different from separator color and equal to (0, + # 102, 153) for some reason (separator has correct color). tmux-1.8 is + # fine, so are older versions (though tmux-1.6 and tmux-1.7 do not have + # highlighting for previously active window) and my system tmux-1.9a. + # 2. screen, xterm and some other non-256color terminals both have the same + # issue and make libvterm emit complains like `Unhandled CSI SGR 3231`. + # 3. screen-256color, xterm-256color and other -256color terminals make + # libvterm emit complains about unhandled escapes to stderr. + # 4. `st-256color` does not have any of the above problems, but it may be + # not present on the target system because it is installed with + # x11-terms/st and not with sys-libs/ncurses. + # + # For the given reasons decision was made: to fix tmux-1.9 tests and not + # make libvterm emit any data to stderr st-256color $TERM should be used, up + # until libvterm has its own terminfo database entry (if it ever will). To + # make sure that relevant terminfo entry is present on the target system it + # should be distributed with powerline test package. To make distribution + # not require modifying anything outside of powerline test directory + # TERMINFO variable is set. + # + # This fix propagates to non-tmux vterm tests just in case. + 'TERM': 'st-256color', + # Also $TERMINFO definition in get_env + + 'POWERLINE_CONFIG_PATHS': os.path.abspath('powerline/config_files'), + 'POWERLINE_COMMAND': 'powerline-render', + 'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''), + 'PYTHONPATH': os.environ.get('PYTHONPATH', ''), +} + + +def get_env(vterm_path, test_dir, *args, **kwargs): + env = ENV_BASE.copy() + env.update({ + 'TERMINFO': os.path.join(test_dir, 'terminfo'), + 'PATH': vterm_path, + 'SHELL': os.path.join(vterm_path, 'bash'), + }) + env.update(*args, **kwargs) + return env + + +def do_terminal_tests(tests, cmd, lib, dim, args, env, cwd=None, fin_cb=None, + last_attempt_cb=None, attempts=3): + while attempts: + try: + p = ExpectProcess( + lib=lib, + dim=dim, + cmd=cmd, + args=args, + cwd=cwd, + env=env, + ) + p.start() + + ret = True + + for test_prep, expected_result in tests: + test_prep(p) + ret = ( + ret + and test_expected_result(p, expected_result, attempts == 0, + last_attempt_cb) + ) + + if ret: + return ret + finally: + if fin_cb: + fin_cb(p=p, cmd=cmd, env=env) + p.kill() + p.join(10) + assert(not p.isAlive()) + + attempts -= 1 + + return False diff --git a/tests/test_in_vterm/test_tmux.py b/tests/test_in_vterm/test_tmux.py index 635c83a9..ca3a4b45 100755 --- a/tests/test_in_vterm/test_tmux.py +++ b/tests/test_in_vterm/test_tmux.py @@ -8,36 +8,20 @@ import json from time import sleep from subprocess import check_call -from difflib import ndiff from glob import glob1 from traceback import print_exc -from powerline.lib.unicode import u from powerline.lib.dict import updated from powerline.bindings.tmux import get_tmux_version from powerline import get_fallback_logger -from tests.lib.terminal import ExpectProcess, MutableDimensions +from tests.lib.terminal import (ExpectProcess, MutableDimensions, + do_terminal_tests, get_env) VTERM_TEST_DIR = os.path.abspath('tests/vterm_tmux') -def convert_expected_result(p, expected_result): - return p.get_highlighted_text(expected_result, {}) - - -def cell_properties_key_to_shell_escape(cell_properties_key): - fg, bg, bold, underline, italic = cell_properties_key - return('\x1b[38;2;{0};48;2;{1}{bold}{underline}{italic}m'.format( - ';'.join((str(i) for i in fg)), - ';'.join((str(i) for i in bg)), - bold=(';1' if bold else ''), - underline=(';4' if underline else ''), - italic=(';3' if italic else ''), - )) - - def tmux_logs_iter(test_dir): for tail in glob1(test_dir, '*.log'): yield os.path.join(test_dir, tail) @@ -54,36 +38,6 @@ def print_tmux_logs(): os.unlink(f) -def test_expected_result(p, expected_result, last_attempt, last_attempt_cb): - expected_text, attrs = expected_result - attempts = 3 - result = None - while attempts: - actual_text, all_attrs = p.get_row(p.dim.rows - 1, attrs) - if actual_text == expected_text: - return True - attempts -= 1 - print('Actual result does not match expected. Attempts left: {0}.'.format(attempts)) - sleep(2) - print('Result:') - print(actual_text) - print('Expected:') - print(expected_text) - print('Attributes:') - print(all_attrs) - print('Screen:') - screen, screen_attrs = p.get_screen(attrs) - print(screen) - print(screen_attrs) - print('_' * 80) - print('Diff:') - print('=' * 80) - print(''.join((u(line) for line in ndiff([actual_text], [expected_text])))) - if last_attempt: - last_attempt_cb() - return False - - def get_expected_result(tmux_version, expected_result_old, expected_result_1_7=None, @@ -99,6 +53,17 @@ def get_expected_result(tmux_version, return expected_result_old +def tmux_fin_cb(p, cmd, env): + try: + check_call([ + cmd, '-S', env['POWERLINE_TMUX_SOCKET_PATH'], 'kill-server' + ], env=env, cwd=VTERM_TEST_DIR) + except Exception: + print_exc() + for f in tmux_logs_iter(VTERM_TEST_DIR): + os.unlink(f) + + def main(attempts=3): vterm_path = os.path.join(VTERM_TEST_DIR, 'path') @@ -109,40 +74,11 @@ def main(attempts=3): else: lib = os.environ.get('POWERLINE_LIBVTERM', 'libvterm.so') - env = { - # Reasoning: - # 1. vt* TERMs (used to be vt100 here) make tmux-1.9 use - # different and identical colors for inactive windows. This - # is not like tmux-1.6: foreground color is different from - # separator color and equal to (0, 102, 153) for some reason - # (separator has correct color). tmux-1.8 is fine, so are - # older versions (though tmux-1.6 and tmux-1.7 do not have - # highlighting for previously active window) and my system - # tmux-1.9a. - # 2. screen, xterm and some other non-256color terminals both - # have the same issue and make libvterm emit complains like - # `Unhandled CSI SGR 3231`. - # 3. screen-256color, xterm-256color and other -256color - # terminals make libvterm emit complains about unhandled - # escapes to stderr. - # 4. `st-256color` does not have any of the above problems, but - # it may be not present on the target system because it is - # installed with x11-terms/st and not with sys-libs/ncurses. - # - # For the given reasons decision was made: to fix tmux-1.9 tests - # and not make libvterm emit any data to stderr st-256color - # $TERM should be used, up until libvterm has its own terminfo - # database entry (if it ever will). To make sure that relevant - # terminfo entry is present on the target system it should be - # distributed with powerline test package. To make distribution - # not require modifying anything outside of powerline test - # directory TERMINFO variable is set. - 'TERMINFO': os.path.join(VTERM_TEST_DIR, 'terminfo'), - 'TERM': 'st-256color', - 'PATH': vterm_path, - 'SHELL': os.path.join(VTERM_TEST_DIR, 'path', 'bash'), - 'POWERLINE_CONFIG_PATHS': os.path.abspath('powerline/config_files'), - 'POWERLINE_COMMAND': 'powerline-render', + socket_path = os.path.abspath('tmux-socket-{0}'.format(attempts)) + if os.path.exists(socket_path): + os.unlink(socket_path) + + env = get_env(vterm_path, VTERM_TEST_DIR, { 'POWERLINE_THEME_OVERRIDES': ';'.join(( key + '=' + json.dumps(val) for key, val in ( @@ -162,9 +98,8 @@ def main(attempts=3): ('default.segment_data.s2.contents', 'S2 string here'), ) )), - 'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''), - 'PYTHONPATH': os.environ.get('PYTHONPATH', ''), - } + 'POWERLINE_TMUX_SOCKET_PATH': socket_path, + }) conf_path = os.path.abspath('powerline/bindings/tmux/powerline.conf') conf_line = 'source "' + ( @@ -268,10 +203,10 @@ def main(attempts=3): ), ) - def prepare_test_1(): + def prepare_test_1(p): sleep(5) - def prepare_test_2(): + def prepare_test_2(p): dim.cols = 40 p.resize(dim) sleep(5) @@ -281,10 +216,6 @@ def main(attempts=3): prepare_test_2, ) - socket_path = os.path.abspath('tmux-socket-{0}'.format(attempts)) - if os.path.exists(socket_path): - os.unlink(socket_path) - args = [ # Specify full path to tmux socket (testing tmux instance must not # interfere with user one) @@ -301,41 +232,17 @@ def main(attempts=3): 'new-window', 'bash --norc --noprofile -i', ';', ] - try: - p = ExpectProcess( - lib=lib, - dim=dim, - cmd=tmux_exe, - args=args, - cwd=VTERM_TEST_DIR, - env=env, - ) - p.start() - - ret = True - - for test_prep, expected_result in zip(test_preps, expected_results): - test_prep() - ret = ( - ret - and test_expected_result(p, expected_result, attempts == 0, - print_tmux_logs) - ) - - if ret or attempts == 0: - return ret - finally: - try: - check_call([tmux_exe, '-S', socket_path, 'kill-server'], env=env, - cwd=VTERM_TEST_DIR) - except Exception: - print_exc() - p.kill() - p.join(10) - for f in tmux_logs_iter(VTERM_TEST_DIR): - os.unlink(f) - assert(not p.isAlive()) - return main(attempts=(attempts - 1)) + return do_terminal_tests( + tests=zip(test_preps, expected_results), + cmd=tmux_exe, + lib=lib, + dim=dim, + args=args, + env=env, + cwd=VTERM_TEST_DIR, + fin_cb=tmux_fin_cb, + last_attempt_cb=print_tmux_logs, + ) if __name__ == '__main__':