tests: Add argument to trim output to a reasonable size

The output of the "values" tshark glossary has over 1.3M lines. Writing
this to stdout with some test failures is problematic in a number of ways.
Also it's not helpful because stderr is written after stdout (not interleaved)
so there is no output context to the error message. The error/warning
message (from stderr, that triggered the test failure) needs to be
sufficient to provide a good understaning of the test failure.

The output is trimmed to first+last N lines. Some lines are kept as
informational and because it may be useful if the program aborts.

Fixes #17203.
This commit is contained in:
João Valverde 2021-02-04 03:01:17 +00:00 committed by Wireshark GitLab Utility
parent 791d101d4d
commit ba23c3b316
2 changed files with 21 additions and 7 deletions

View File

@ -55,6 +55,7 @@ class LoggingPopen(subprocess.Popen):
'''
def __init__(self, proc_args, *args, **kwargs):
self.log_fd = kwargs.pop('log_fd', None)
self.max_lines = kwargs.pop('max_lines', None)
kwargs['stdout'] = subprocess.PIPE
kwargs['stderr'] = subprocess.PIPE
# Make sure communicate() gives us bytes.
@ -63,11 +64,24 @@ class LoggingPopen(subprocess.Popen):
super().__init__(proc_args, *args, **kwargs)
self.stdout_str = ''
self.stderr_str = ''
@staticmethod
def trim_output(out_log, max_lines):
lines = out_log.splitlines(True)
if not len(lines) > max_lines * 2 + 1:
return out_log
header = lines[:max_lines]
body = lines[max_lines:-max_lines]
body = "<<< trimmed {} lines of output >>>\n".format(len(body))
footer = lines[-max_lines:]
return ''.join(header) + body + ''.join(footer)
def wait_and_log(self):
'''Wait for the process to finish and log its output.'''
out_data, err_data = self.communicate(timeout=process_timeout)
out_log = out_data.decode('UTF-8', 'replace')
if self.max_lines and self.max_lines > 0:
out_log = self.trim_output(out_log, self.max_lines)
err_log = err_data.decode('UTF-8', 'replace')
self.log_fd.flush()
self.log_fd.write('-- Begin stdout for {} --\n'.format(self.cmd_str))
@ -249,7 +263,7 @@ class SubprocessTestCase(unittest.TestCase):
return False
return True
def startProcess(self, proc_args, stdin=None, env=None, shell=False, cwd=None):
def startProcess(self, proc_args, stdin=None, env=None, shell=False, cwd=None, max_lines=None):
'''Start a process in the background. Returns a subprocess.Popen object.
You typically wait for it using waitProcess() or assertWaitProcess().'''
@ -261,7 +275,7 @@ class SubprocessTestCase(unittest.TestCase):
# fixture (via a test method parameter or class decorator).
assert not (env is None and hasattr(self, '_fixture_request')), \
"Decorate class with @fixtures.mark_usefixtures('test_env')"
proc = LoggingPopen(proc_args, stdin=stdin, env=env, shell=shell, log_fd=self.log_fd, cwd=cwd)
proc = LoggingPopen(proc_args, stdin=stdin, env=env, shell=shell, log_fd=self.log_fd, cwd=cwd, max_lines=max_lines)
self.processes.append(proc)
return proc
@ -278,14 +292,14 @@ class SubprocessTestCase(unittest.TestCase):
process.wait_and_log()
self.assertEqual(process.returncode, expected_return)
def runProcess(self, args, env=None, shell=False, cwd=None):
def runProcess(self, args, env=None, shell=False, cwd=None, max_lines=None):
'''Start a process and wait for it to finish.'''
process = self.startProcess(args, env=env, shell=shell, cwd=cwd)
process = self.startProcess(args, env=env, shell=shell, cwd=cwd, max_lines=max_lines)
process.wait_and_log()
return process
def assertRun(self, args, env=None, shell=False, expected_return=0, cwd=None):
def assertRun(self, args, env=None, shell=False, expected_return=0, cwd=None, max_lines=None):
'''Start a process and wait for it to finish. Check its return code.'''
process = self.runProcess(args, env=env, shell=shell, cwd=cwd)
process = self.runProcess(args, env=env, shell=shell, cwd=cwd, max_lines=max_lines)
self.assertEqual(process.returncode, expected_return)
return process

View File

@ -165,7 +165,7 @@ class case_tshark_dump_glossaries(subprocesstest.SubprocessTestCase):
self.log_fd.truncate()
except Exception:
pass
self.assertRun((cmd_tshark, '-G', glossary), env=base_env)
self.assertRun((cmd_tshark, '-G', glossary), env=base_env, max_lines=20)
self.assertEqual(self.countOutput(count_stdout=False, count_stderr=True), 0, 'Found error output while printing glossary ' + glossary)
def test_tshark_glossary_valid_utf8(self, cmd_tshark, base_env):