Skip to content

Commit 39e95b4

Browse files
committed
Add integration tests for st2common.util.green.shell.run_command()
function, including regression test case for zombie / stray process issue.
1 parent 708fa44 commit 39e95b4

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Copyright 2020 The StackStorm Authors.
2+
# Copyright 2019 Extreme Networks, Inc.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
import os
17+
18+
from st2common.util.monkey_patch import monkey_patch
19+
20+
monkey_patch()
21+
22+
from st2tests.base import IntegrationTestCase
23+
24+
from st2common.util.green.shell import run_command
25+
from st2common.util.green.shell import TIMEOUT_EXIT_CODE
26+
from st2common.util.shell import kill_process
27+
from st2common.util.shell import quote_unix
28+
29+
_all__ = ["GreenShellUtilsTestCase"]
30+
31+
32+
class GreenShellUtilsTestCase(IntegrationTestCase):
33+
def test_run_command_success(self):
34+
# 0 exit code
35+
exit_code, stdout, stderr, timed_out = run_command(
36+
cmd='echo "test stdout" ; >&2 echo "test stderr"', shell=True
37+
)
38+
self.assertEqual(exit_code, 0)
39+
self.assertEqual(stdout.strip(), b"test stdout")
40+
self.assertEqual(stderr.strip(), b"test stderr")
41+
self.assertFalse(timed_out)
42+
43+
# non-zero exit code
44+
exit_code, stdout, stderr, timed_out = run_command(
45+
cmd='echo "test stdout" ; >&2 echo "test stderr" ; exit 5', shell=True
46+
)
47+
self.assertEqual(exit_code, 5)
48+
self.assertEqual(stdout.strip(), b"test stdout")
49+
self.assertEqual(stderr.strip(), b"test stderr")
50+
self.assertFalse(timed_out)
51+
52+
# implicit non zero code (invalid command)
53+
exit_code, stdout, stderr, timed_out = run_command(
54+
cmd="foobarbarbazrbar", shell=True
55+
)
56+
self.assertEqual(exit_code, 127)
57+
self.assertEqual(stdout.strip(), b"")
58+
self.assertTrue(b"foobarbarbazrbar: not found" in stderr.strip())
59+
self.assertFalse(timed_out)
60+
61+
def test_run_command_timeout_shell_and_custom_kill_func(self):
62+
# This test represents our local runner setup where we use a preexec_func + custom kill_func
63+
# NOTE: When using shell=True. we should alaways use custom kill_func to ensure child shell
64+
# processses are in fact killed as well.
65+
exit_code, stdout, stderr, timed_out = run_command(
66+
cmd='echo "pre sleep"; sleep 1589; echo "post sleep"',
67+
preexec_func=os.setsid,
68+
timeout=1,
69+
kill_func=kill_process,
70+
shell=True,
71+
)
72+
self.assertEqual(exit_code, TIMEOUT_EXIT_CODE)
73+
self.assertEqual(stdout.strip(), b"pre sleep")
74+
self.assertEqual(stderr.strip(), b"")
75+
self.assertTrue(timed_out)
76+
77+
# Verify there is no zombie process left laying around
78+
self.assertNoStrayProcessesLeft("sleep 1589")
79+
80+
def test_run_command_timeout_no_shell_no_custom_kill_func(self):
81+
exit_code, stdout, stderr, timed_out = run_command(
82+
cmd=["sleep", "1599"], preexec_func=os.setsid, timeout=1
83+
)
84+
self.assertEqual(exit_code, TIMEOUT_EXIT_CODE)
85+
self.assertEqual(stdout.strip(), b"")
86+
self.assertEqual(stderr.strip(), b"")
87+
self.assertTrue(timed_out)
88+
89+
# Verify there is no zombie process left laying around
90+
self.assertNoStrayProcessesLeft("sleep 1599")
91+
92+
def assertNoStrayProcessesLeft(self, grep_string: str) -> None:
93+
"""
94+
Assert that there are no stray / zombie processes left with the provided command line
95+
string.
96+
"""
97+
exit_code, stdout, stderr, timed_out = run_command(
98+
cmd="ps aux | grep %s | grep -v grep" % (quote_unix(grep_string)),
99+
shell=True,
100+
)
101+
102+
if stdout.strip() != b"" and stderr.strip() != b"":
103+
raise AssertionError(
104+
"Expected no stray processes, but found Some. stdout: %s, stderr: %s"
105+
% (stdout, stderr)
106+
)

0 commit comments

Comments
 (0)