Skip to content

Commit 647edeb

Browse files
author
Vasileios Karakasis
authored
Merge pull request #1243 from vkarak/bugfix/spawned_process_error_formatting
[bugfix] Fix formatting of the error message when an OS command fails
2 parents cd9f83b + 85f0b26 commit 647edeb

File tree

4 files changed

+75
-71
lines changed

4 files changed

+75
-71
lines changed

reframe/core/exceptions.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,21 @@ def __init__(self, stdout, stderr):
144144
class SpawnedProcessError(ReframeError):
145145
'''Raised when a spawned OS command has failed.'''
146146

147-
def __init__(self, command, stdout, stderr, exitcode):
147+
def __init__(self, args, stdout, stderr, exitcode):
148148
super().__init__()
149149

150-
# Format message and put it in args
150+
if isinstance(args, str):
151+
self._command = args
152+
else:
153+
self._command = ' '.join(args)
154+
155+
self._stdout = stdout
156+
self._stderr = stderr
157+
self._exitcode = exitcode
158+
159+
# Format message
151160
lines = [
152-
"command '%s' failed with exit code %s:" % (command, exitcode)
161+
f"command '{self.command}' failed with exit code {self.exitcode}:"
153162
]
154163
lines.append('=== STDOUT ===')
155164
if stdout:
@@ -160,10 +169,6 @@ def __init__(self, command, stdout, stderr, exitcode):
160169
lines.append(stderr)
161170

162171
self._message = '\n'.join(lines)
163-
self._command = command
164-
self._stdout = stdout
165-
self._stderr = stderr
166-
self._exitcode = exitcode
167172

168173
@property
169174
def command(self):
@@ -185,10 +190,12 @@ def exitcode(self):
185190
class SpawnedProcessTimeout(SpawnedProcessError):
186191
'''Raised when a spawned OS command has timed out.'''
187192

188-
def __init__(self, command, stdout, stderr, timeout):
189-
super().__init__(command, stdout, stderr, None)
193+
def __init__(self, args, stdout, stderr, timeout):
194+
super().__init__(args, stdout, stderr, None)
195+
self._timeout = timeout
190196

191-
lines = ["command '%s' timed out after %ss:" % (command, timeout)]
197+
# Format message
198+
lines = [f"command '{self.command}' timed out after {self.timeout}s:"]
192199
lines.append('=== STDOUT ===')
193200
if self._stdout:
194201
lines.append(self._stdout)
@@ -198,7 +205,6 @@ def __init__(self, command, stdout, stderr, timeout):
198205
lines.append(self._stderr)
199206

200207
self._message = '\n'.join(lines)
201-
self._timeout = timeout
202208

203209
@property
204210
def timeout(self):

reframe/utility/os_ext.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,25 +51,6 @@ def run_command(cmd, check=False, timeout=None, shell=False, log=True):
5151
return completed
5252

5353

54-
def grep_command_output(cmd, pattern, where='stdout'):
55-
completed = subprocess.run(shlex.split(cmd),
56-
stdout=subprocess.PIPE,
57-
stderr=subprocess.PIPE,
58-
universal_newlines=True)
59-
if where == 'stdout':
60-
outlist = [completed.stdout]
61-
elif where == 'stderr':
62-
outlist = [completed.stderr]
63-
else:
64-
outlist = [completed.stdout, completed.stderr]
65-
66-
for out in outlist:
67-
if re.search(pattern, out, re.MULTILINE):
68-
return True
69-
70-
return False
71-
72-
7354
def run_command_async(cmd,
7455
stdout=subprocess.PIPE,
7556
stderr=subprocess.PIPE,

unittests/test_exceptions.py

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,28 @@ def test_spawned_process_error(self):
5757
exc_args = ('foo bar', 'partial output', 'error message', 1)
5858
e = exc.SpawnedProcessError(*exc_args)
5959
with pytest.raises(
60-
exc.ReframeError,
61-
match=r"command 'foo bar' failed with exit code 1:\n"
62-
r"=== STDOUT ===\n"
63-
r'partial output\n'
64-
r"=== STDERR ===\n"
65-
r"error message"):
60+
exc.ReframeError,
61+
match=(r"command 'foo bar' failed with exit code 1:\n"
62+
r"=== STDOUT ===\n"
63+
r'partial output\n'
64+
r"=== STDERR ===\n"
65+
r"error message")
66+
):
67+
raise_exc(e)
68+
69+
assert exc_args == e.args
70+
71+
def test_spawned_process_error_list_args(self):
72+
exc_args = (['foo', 'bar'], 'partial output', 'error message', 1)
73+
e = exc.SpawnedProcessError(*exc_args)
74+
with pytest.raises(
75+
exc.ReframeError,
76+
match=(r"command 'foo bar' failed with exit code 1:\n"
77+
r"=== STDOUT ===\n"
78+
r'partial output\n'
79+
r"=== STDERR ===\n"
80+
r"error message")
81+
):
6682
raise_exc(e)
6783

6884
assert exc_args == e.args
@@ -71,33 +87,35 @@ def test_spawned_process_error_nostdout(self):
7187
exc_args = ('foo bar', '', 'error message', 1)
7288
e = exc.SpawnedProcessError(*exc_args)
7389
with pytest.raises(
74-
exc.ReframeError,
75-
match=r"command 'foo bar' failed with exit code 1:\n"
76-
r"=== STDOUT ===\n"
77-
r"=== STDERR ===\n"
78-
r"error message"):
90+
exc.ReframeError,
91+
match=(r"command 'foo bar' failed with exit code 1:\n"
92+
r"=== STDOUT ===\n"
93+
r"=== STDERR ===\n"
94+
r"error message")
95+
):
7996
raise_exc(e)
8097

8198
def test_spawned_process_error_nostderr(self):
8299
exc_args = ('foo bar', 'partial output', '', 1)
83100
e = exc.SpawnedProcessError(*exc_args)
84101
with pytest.raises(
85-
exc.ReframeError,
86-
match=r"command 'foo bar' failed with exit code 1:\n"
87-
r"=== STDOUT ===\n"
88-
r'partial output\n'
89-
r"=== STDERR ==="):
102+
exc.ReframeError,
103+
match=(r"command 'foo bar' failed with exit code 1:\n"
104+
r"=== STDOUT ===\n"
105+
r'partial output\n'
106+
r"=== STDERR ===")
107+
):
90108
raise_exc(e)
91109

92110
def test_spawned_process_timeout(self):
93111
exc_args = ('foo bar', 'partial output', 'partial error', 10)
94112
e = exc.SpawnedProcessTimeout(*exc_args)
95113
with pytest.raises(exc.ReframeError,
96-
match=r"command 'foo bar' timed out after 10s:\n"
97-
r"=== STDOUT ===\n"
98-
r'partial output\n'
99-
r"=== STDERR ===\n"
100-
r"partial error"):
114+
match=(r"command 'foo bar' timed out after 10s:\n"
115+
r"=== STDOUT ===\n"
116+
r'partial output\n'
117+
r"=== STDERR ===\n"
118+
r"partial error")):
101119
raise_exc(e)
102120

103121
assert exc_args == e.args
@@ -106,20 +124,20 @@ def test_spawned_process_timeout_nostdout(self):
106124
exc_args = ('foo bar', '', 'partial error', 10)
107125
e = exc.SpawnedProcessTimeout(*exc_args)
108126
with pytest.raises(exc.ReframeError,
109-
match=r"command 'foo bar' timed out after 10s:\n"
110-
r"=== STDOUT ===\n"
111-
r"=== STDERR ===\n"
112-
r"partial error"):
127+
match=(r"command 'foo bar' timed out after 10s:\n"
128+
r"=== STDOUT ===\n"
129+
r"=== STDERR ===\n"
130+
r"partial error")):
113131
raise_exc(e)
114132

115133
def test_spawned_process_timeout_nostderr(self):
116134
exc_args = ('foo bar', 'partial output', '', 10)
117135
e = exc.SpawnedProcessTimeout(*exc_args)
118136
with pytest.raises(exc.ReframeError,
119-
match=r"command 'foo bar' timed out after 10s:\n"
120-
r"=== STDOUT ===\n"
121-
r'partial output\n'
122-
r"=== STDERR ==="):
137+
match=(r"command 'foo bar' timed out after 10s:\n"
138+
r"=== STDOUT ===\n"
139+
r'partial output\n'
140+
r"=== STDERR ===")):
123141
raise_exc(e)
124142

125143
def test_job_error(self):

unittests/test_utility.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,21 @@ def test_command_success(self):
2727
assert completed.stdout == 'foobar\n'
2828

2929
def test_command_error(self):
30-
with pytest.raises(SpawnedProcessError):
30+
with pytest.raises(SpawnedProcessError,
31+
match=r"command 'false' failed with exit code 1"):
3132
os_ext.run_command('false', check=True)
3233

3334
def test_command_timeout(self):
34-
try:
35+
with pytest.raises(
36+
SpawnedProcessTimeout,
37+
match=r"command 'sleep 3' timed out after 2s"
38+
) as exc_info:
3539
os_ext.run_command('sleep 3', timeout=2)
36-
except SpawnedProcessTimeout as e:
37-
assert e.timeout == 2
38-
# Try to get the string repr. of the exception: see bug #658
39-
s = str(e)
40-
else:
41-
pytest.fail('expected timeout')
40+
41+
assert exc_info.value.timeout == 2
42+
43+
# Try to get the string repr. of the exception: see bug #658
44+
s = str(exc_info.value)
4245

4346
def test_command_async(self):
4447
from datetime import datetime
@@ -55,10 +58,6 @@ def test_command_async(self):
5558
assert t_launch.seconds < 1
5659
assert t_sleep.seconds >= 1
5760

58-
def test_grep(self):
59-
assert os_ext.grep_command_output(cmd='echo hello', pattern='hello')
60-
assert not os_ext.grep_command_output(cmd='echo hello', pattern='foo')
61-
6261
def test_copytree(self):
6362
dir_src = tempfile.mkdtemp()
6463
dir_dst = tempfile.mkdtemp()

0 commit comments

Comments
 (0)