Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
avocado
提交
9a8dfafd
A
avocado
项目概览
openeuler
/
avocado
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
avocado
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
9a8dfafd
编写于
1月 31, 2019
作者:
C
Caio Carrara
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'ldoktor/process-wait3'
Signed-off-by:
N
Caio Carrara
<
ccarrara@redhat.com
>
上级
d378f0db
e51cfe0a
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
109 addition
and
34 deletion
+109
-34
avocado/utils/process.py
avocado/utils/process.py
+59
-34
selftests/unit/test_utils_process.py
selftests/unit/test_utils_process.py
+50
-0
未找到文件。
avocado/utils/process.py
浏览文件 @
9a8dfafd
...
...
@@ -808,14 +808,64 @@ class SubProcess(object):
self
.
_fill_results
(
rc
)
return
rc
def
wait
(
self
):
def
wait
(
self
,
timeout
=
None
,
sig
=
signal
.
SIGTERM
):
"""
Call the subprocess poll() method, fill results if rc is not None.
:param timeout: Time (seconds) we'll wait until the process is
finished. If it's not, we'll try to terminate it
and it's children using ``sig`` and get a
status. When the process refuses to die
within 1s we use SIGKILL and report the status
(be it exit_code or zombie)
:param sig: Signal to send to the process in case it did not end after
the specified timeout.
"""
def
nuke_myself
():
self
.
result
.
interrupted
=
(
"timeout after %ss"
%
(
time
.
time
()
-
self
.
start_time
))
try
:
kill_process_tree
(
self
.
get_pid
(),
sig
,
timeout
=
1
)
except
Exception
:
try
:
kill_process_tree
(
self
.
get_pid
(),
signal
.
SIGKILL
,
timeout
=
1
)
log
.
warning
(
"Process '%s' refused to die in 1s after "
"sending %s to, destroyed it successfully "
"using SIGKILL."
,
self
.
cmd
,
sig
)
except
Exception
:
log
.
error
(
"Process '%s' refused to die in 1s after "
"sending %s, followed by SIGKILL, probably "
"dealing with a zombie process."
,
self
.
cmd
,
sig
)
self
.
_init_subprocess
()
rc
=
self
.
_popen
.
wait
()
if
rc
is
not
None
:
self
.
_fill_results
(
rc
)
rc
=
None
if
timeout
is
None
:
rc
=
self
.
_popen
.
wait
()
elif
timeout
>
0.0
:
timer
=
threading
.
Timer
(
timeout
,
nuke_myself
)
try
:
timer
.
start
()
rc
=
self
.
_popen
.
wait
()
finally
:
timer
.
cancel
()
if
rc
is
None
:
stop_time
=
time
.
time
()
+
1
while
time
.
time
()
<
stop_time
:
rc
=
self
.
_popen
.
poll
()
if
rc
is
not
None
:
break
else
:
nuke_myself
()
rc
=
self
.
_popen
.
poll
()
if
rc
is
None
:
# If all this work fails, we're dealing with a zombie process.
raise
AssertionError
(
'Zombie Process %s'
%
self
.
_popen
.
pid
)
self
.
_fill_results
(
rc
)
return
rc
def
stop
(
self
):
...
...
@@ -860,7 +910,10 @@ class SubProcess(object):
:param timeout: Time (seconds) we'll wait until the process is
finished. If it's not, we'll try to terminate it
and get a status.
and it's children using ``sig`` and get a
status. When the process refuses to die
within 1s we use SIGKILL and report the status
(be it exit_code or zombie)
:type timeout: float
:param sig: Signal to send to the process in case it did not end after
the specified timeout.
...
...
@@ -868,36 +921,8 @@ class SubProcess(object):
:returns: The command result object.
:rtype: A :class:`CmdResult` instance.
"""
def
timeout_handler
():
self
.
send_signal
(
sig
)
self
.
result
.
interrupted
=
"timeout after %ss"
%
timeout
self
.
_init_subprocess
()
if
timeout
is
None
:
self
.
wait
()
elif
timeout
>
0.0
:
timer
=
threading
.
Timer
(
timeout
,
timeout_handler
)
try
:
timer
.
start
()
self
.
wait
()
finally
:
timer
.
cancel
()
if
self
.
result
.
exit_status
is
None
:
stop_time
=
time
.
time
()
+
1
while
time
.
time
()
<
stop_time
:
self
.
poll
()
if
self
.
result
.
exit_status
is
not
None
:
break
else
:
self
.
kill
()
self
.
poll
()
# If all this work fails, we're dealing with a zombie process.
e_msg
=
'Zombie Process %s'
%
self
.
_popen
.
pid
assert
self
.
result
.
exit_status
is
not
None
,
e_msg
self
.
wait
(
timeout
,
sig
)
return
self
.
result
...
...
selftests/unit/test_utils_process.py
浏览文件 @
9a8dfafd
...
...
@@ -4,6 +4,7 @@ import os
import
shlex
import
unittest
import
sys
import
time
try
:
from
unittest
import
mock
...
...
@@ -13,6 +14,7 @@ except ImportError:
from
..
import
recent_mock
from
avocado.utils
import
astring
from
avocado.utils
import
script
from
avocado.utils
import
gdb
from
avocado.utils
import
process
from
avocado.utils
import
path
...
...
@@ -35,6 +37,20 @@ def probe_binary(binary):
ECHO_CMD
=
probe_binary
(
'echo'
)
FICTIONAL_CMD
=
'/usr/bin/fictional_cmd'
REFUSE_TO_DIE
=
"""import signal
import time
for sig in range(64):
try:
signal.signal(sig, signal.SIG_IGN)
except:
pass
end = time.time() + 120
while time.time() < end:
time.sleep(1)"""
class
TestSubProcess
(
unittest
.
TestCase
):
...
...
@@ -321,6 +337,40 @@ class TestProcessRun(unittest.TestCase):
self
.
assertEqual
(
result
.
stdout
,
encoded_text
)
self
.
assertEqual
(
result
.
stdout_text
,
text
)
@
unittest
.
skipIf
(
int
(
os
.
environ
.
get
(
"AVOCADO_CHECK_LEVEL"
,
1
))
<
2
,
"Skipping test that take a long time to run, are "
"resource intensive or time sensitve"
)
def
test_run_with_timeout_ugly_cmd
(
self
):
with
script
.
TemporaryScript
(
"refuse_to_die"
,
REFUSE_TO_DIE
)
as
exe
:
cmd
=
"%s '%s'"
%
(
sys
.
executable
,
exe
.
path
)
# Wait 1s to set the traps
res
=
process
.
run
(
cmd
,
timeout
=
1
,
ignore_status
=
True
)
self
.
assertLess
(
res
.
duration
,
100
,
"Took longer than expected, "
"process probably not interrupted by Avocado.
\n
%s"
%
res
)
self
.
assertNotEqual
(
res
.
exit_status
,
0
,
"Command finished without "
"reporting failure but should be killed.
\n
%s"
%
res
)
@
unittest
.
skipIf
(
int
(
os
.
environ
.
get
(
"AVOCADO_CHECK_LEVEL"
,
0
))
<
2
,
"Skipping test that take a long time to run, are "
"resource intensive or time sensitve"
)
def
test_run_with_negative_timeout_ugly_cmd
(
self
):
with
script
.
TemporaryScript
(
"refuse_to_die"
,
REFUSE_TO_DIE
)
as
exe
:
cmd
=
"%s '%s'"
%
(
sys
.
executable
,
exe
.
path
)
# Wait 1s to set the traps
proc
=
process
.
SubProcess
(
cmd
)
proc
.
start
()
time
.
sleep
(
1
)
proc
.
wait
(
-
1
)
res
=
proc
.
result
self
.
assertLess
(
res
.
duration
,
100
,
"Took longer than expected, "
"process probably not interrupted by Avocado.
\n
%s"
%
res
)
self
.
assertNotEqual
(
res
.
exit_status
,
0
,
"Command finished without "
"reporting failure but should be killed.
\n
%s"
%
res
)
class
MiscProcessTests
(
unittest
.
TestCase
):
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录