From 72bdab0f879a7c494799950b5150960f015351b6 Mon Sep 17 00:00:00 2001 From: Cleber Rosa Date: Sun, 25 Feb 2018 19:20:15 -0500 Subject: [PATCH] avocado/utils/process.py: make CmdResult.std{out,err}_text smarter In situations where a user of the CmdResult class manually sets the stdout/stderr attributes to a string, instead of the recommended and documented content of type "bytes", it won't be possible to "decode" the bytes into a string of a given encoding, and we'll end up with a crash. Since the goal of std{out,err}_text is to return a text version of stdout, if itself already is of such a type, let's just return it. Additionally, if the data cannot be "decode()d", let's raise an explicit TypeError on this location, rather than later in the code when its value is attempted to be used. Signed-off-by: Cleber Rosa --- avocado/utils/process.py | 13 ++++++++++-- selftests/unit/test_utils_process.py | 30 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/avocado/utils/process.py b/avocado/utils/process.py index 7dede815..b6d354fe 100644 --- a/avocado/utils/process.py +++ b/avocado/utils/process.py @@ -32,6 +32,7 @@ import threading import time from io import BytesIO +from six import string_types from . import gdb from . import runtime @@ -294,11 +295,19 @@ class CmdResult(object): @property def stdout_text(self): - return self.stdout.decode(self.encoding) + if type(self.stdout) in string_types: + return self.stdout + if hasattr(self.stdout, 'decode'): + return self.stdout.decode(self.encoding) + raise TypeError("Unable to decode stdout into a string-like type") @property def stderr_text(self): - return self.stderr.decode(self.encoding) + if type(self.stderr) in string_types: + return self.stderr + if hasattr(self.stderr, 'decode'): + return self.stderr.decode(self.encoding) + raise TypeError("Unable to decode stderr into a string-like type") def __repr__(self): cmd_rep = ("Command: %s\n" diff --git a/selftests/unit/test_utils_process.py b/selftests/unit/test_utils_process.py index 5cae846e..cb832a45 100644 --- a/selftests/unit/test_utils_process.py +++ b/selftests/unit/test_utils_process.py @@ -12,6 +12,9 @@ from avocado.utils import gdb from avocado.utils import process from avocado.utils import path +from six import string_types + + TRUE_CMD = path.find_command('true') @@ -231,6 +234,33 @@ class MiscProcessTests(unittest.TestCase): self.assertEqual("./bin", res) +class CmdResultTests(unittest.TestCase): + + def test_cmd_result_stdout_stderr_bytes(self): + result = process.CmdResult() + self.assertTrue(isinstance(result.stdout, bytes)) + self.assertTrue(isinstance(result.stderr, bytes)) + + def test_cmd_result_stdout_stderr_text(self): + result = process.CmdResult() + self.assertTrue(isinstance(result.stdout_text, string_types)) + self.assertTrue(isinstance(result.stderr_text, string_types)) + + def test_cmd_result_stdout_stderr_already_text(self): + result = process.CmdResult() + result.stdout = "supposed command output, but not as bytes" + result.stderr = "supposed command error, but not as bytes" + self.assertEqual(result.stdout, result.stdout_text) + self.assertEqual(result.stderr, result.stderr_text) + + def test_cmd_result_stdout_stderr_other_type(self): + result = process.CmdResult() + result.stdout = None + result.stderr = None + self.assertRaises(TypeError, lambda x: result.stdout_text) + self.assertRaises(TypeError, lambda x: result.stderr_text) + + class FDDrainerTests(unittest.TestCase): def test_drain_from_pipe_fd(self): -- GitLab