xref: /OK3568_Linux_fs/yocto/poky/meta/lib/oeqa/selftest/cases/runcmd.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#
2*4882a593Smuzhiyun# SPDX-License-Identifier: MIT
3*4882a593Smuzhiyun#
4*4882a593Smuzhiyun
5*4882a593Smuzhiyunfrom oeqa.selftest.case import OESelftestTestCase
6*4882a593Smuzhiyunfrom oeqa.utils.commands import runCmd
7*4882a593Smuzhiyunfrom oeqa.utils import CommandError
8*4882a593Smuzhiyun
9*4882a593Smuzhiyunimport subprocess
10*4882a593Smuzhiyunimport threading
11*4882a593Smuzhiyunimport time
12*4882a593Smuzhiyunimport signal
13*4882a593Smuzhiyun
14*4882a593Smuzhiyunclass MemLogger(object):
15*4882a593Smuzhiyun    def __init__(self):
16*4882a593Smuzhiyun        self.info_msgs = []
17*4882a593Smuzhiyun        self.error_msgs = []
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun    def info(self, msg):
20*4882a593Smuzhiyun        self.info_msgs.append(msg)
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun    def error(self, msg):
23*4882a593Smuzhiyun        self.error_msgs.append(msg)
24*4882a593Smuzhiyun
25*4882a593Smuzhiyunclass RunCmdTests(OESelftestTestCase):
26*4882a593Smuzhiyun    """ Basic tests for runCmd() utility function """
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun    # The delta is intentionally smaller than the timeout, to detect cases where
29*4882a593Smuzhiyun    # we incorrectly apply the timeout more than once.
30*4882a593Smuzhiyun    TIMEOUT = 10
31*4882a593Smuzhiyun    DELTA = 8
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun    def test_result_okay(self):
34*4882a593Smuzhiyun        result = runCmd("true")
35*4882a593Smuzhiyun        self.assertEqual(result.status, 0)
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun    def test_result_false(self):
38*4882a593Smuzhiyun        result = runCmd("false", ignore_status=True)
39*4882a593Smuzhiyun        self.assertEqual(result.status, 1)
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun    def test_shell(self):
42*4882a593Smuzhiyun        # A shell is used for all string commands.
43*4882a593Smuzhiyun        result = runCmd("false; true", ignore_status=True)
44*4882a593Smuzhiyun        self.assertEqual(result.status, 0)
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun    def test_no_shell(self):
47*4882a593Smuzhiyun        self.assertRaises(FileNotFoundError,
48*4882a593Smuzhiyun                          runCmd, "false; true", shell=False)
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun    def test_list_not_found(self):
51*4882a593Smuzhiyun        self.assertRaises(FileNotFoundError,
52*4882a593Smuzhiyun                          runCmd, ["false; true"])
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun    def test_list_okay(self):
55*4882a593Smuzhiyun        result = runCmd(["true"])
56*4882a593Smuzhiyun        self.assertEqual(result.status, 0)
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun    def test_result_assertion(self):
59*4882a593Smuzhiyun        self.assertRaisesRegexp(AssertionError, "Command 'echo .* false' returned non-zero exit status 1:\nfoobar",
60*4882a593Smuzhiyun                                runCmd, "echo foobar >&2; false", shell=True)
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun    def test_result_exception(self):
63*4882a593Smuzhiyun        self.assertRaisesRegexp(CommandError, "Command 'echo .* false' returned non-zero exit status 1 with output: foobar",
64*4882a593Smuzhiyun                                runCmd, "echo foobar >&2; false", shell=True, assert_error=False)
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun    def test_output(self):
67*4882a593Smuzhiyun        result = runCmd("echo stdout; echo stderr >&2", shell=True, sync=False)
68*4882a593Smuzhiyun        self.assertEqual("stdout\nstderr", result.output)
69*4882a593Smuzhiyun        self.assertEqual("", result.error)
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun    def test_output_split(self):
72*4882a593Smuzhiyun        result = runCmd("echo stdout; echo stderr >&2", shell=True, stderr=subprocess.PIPE, sync=False)
73*4882a593Smuzhiyun        self.assertEqual("stdout", result.output)
74*4882a593Smuzhiyun        self.assertEqual("stderr", result.error)
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun    def test_timeout(self):
77*4882a593Smuzhiyun        numthreads = threading.active_count()
78*4882a593Smuzhiyun        start = time.time()
79*4882a593Smuzhiyun        # Killing a hanging process only works when not using a shell?!
80*4882a593Smuzhiyun        result = runCmd(['sleep', '60'], timeout=self.TIMEOUT, ignore_status=True, sync=False)
81*4882a593Smuzhiyun        self.assertEqual(result.status, -signal.SIGTERM)
82*4882a593Smuzhiyun        end = time.time()
83*4882a593Smuzhiyun        self.assertLess(end - start, self.TIMEOUT + self.DELTA)
84*4882a593Smuzhiyun        self.assertEqual(numthreads, threading.active_count(), msg="Thread counts were not equal before (%s) and after (%s), active threads: %s" % (numthreads, threading.active_count(), threading.enumerate()))
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun    def test_timeout_split(self):
87*4882a593Smuzhiyun        numthreads = threading.active_count()
88*4882a593Smuzhiyun        start = time.time()
89*4882a593Smuzhiyun        # Killing a hanging process only works when not using a shell?!
90*4882a593Smuzhiyun        result = runCmd(['sleep', '60'], timeout=self.TIMEOUT, ignore_status=True, stderr=subprocess.PIPE, sync=False)
91*4882a593Smuzhiyun        self.assertEqual(result.status, -signal.SIGTERM)
92*4882a593Smuzhiyun        end = time.time()
93*4882a593Smuzhiyun        self.assertLess(end - start, self.TIMEOUT + self.DELTA)
94*4882a593Smuzhiyun        self.assertEqual(numthreads, threading.active_count(), msg="Thread counts were not equal before (%s) and after (%s), active threads: %s" % (numthreads, threading.active_count(), threading.enumerate()))
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun    def test_stdin(self):
97*4882a593Smuzhiyun        numthreads = threading.active_count()
98*4882a593Smuzhiyun        result = runCmd("cat", data=b"hello world", timeout=self.TIMEOUT, sync=False)
99*4882a593Smuzhiyun        self.assertEqual("hello world", result.output)
100*4882a593Smuzhiyun        self.assertEqual(numthreads, threading.active_count(), msg="Thread counts were not equal before (%s) and after (%s), active threads: %s" % (numthreads, threading.active_count(), threading.enumerate()))
101*4882a593Smuzhiyun        self.assertEqual(numthreads, 1)
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun    def test_stdin_timeout(self):
104*4882a593Smuzhiyun        numthreads = threading.active_count()
105*4882a593Smuzhiyun        start = time.time()
106*4882a593Smuzhiyun        result = runCmd(['sleep', '60'], data=b"hello world", timeout=self.TIMEOUT, ignore_status=True, sync=False)
107*4882a593Smuzhiyun        self.assertEqual(result.status, -signal.SIGTERM)
108*4882a593Smuzhiyun        end = time.time()
109*4882a593Smuzhiyun        self.assertLess(end - start, self.TIMEOUT + self.DELTA)
110*4882a593Smuzhiyun        self.assertEqual(numthreads, threading.active_count(), msg="Thread counts were not equal before (%s) and after (%s), active threads: %s" % (numthreads, threading.active_count(), threading.enumerate()))
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun    def test_log(self):
113*4882a593Smuzhiyun        log = MemLogger()
114*4882a593Smuzhiyun        result = runCmd("echo stdout; echo stderr >&2", shell=True, output_log=log, sync=False)
115*4882a593Smuzhiyun        self.assertEqual(["Running: echo stdout; echo stderr >&2", "stdout", "stderr"], log.info_msgs)
116*4882a593Smuzhiyun        self.assertEqual([], log.error_msgs)
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun    def test_log_split(self):
119*4882a593Smuzhiyun        log = MemLogger()
120*4882a593Smuzhiyun        result = runCmd("echo stdout; echo stderr >&2", shell=True, output_log=log, stderr=subprocess.PIPE, sync=False)
121*4882a593Smuzhiyun        self.assertEqual(["Running: echo stdout; echo stderr >&2", "stdout"], log.info_msgs)
122*4882a593Smuzhiyun        self.assertEqual(["stderr"], log.error_msgs)
123