-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mutest: new output arg for out-of-order cmd execution #39
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -940,7 +940,15 @@ | |
raise CalledProcessError(rc, ac, o, e) | ||
return rc, o, e | ||
|
||
def _cmd_status(self, cmds, raises=False, warn=True, stdin=None, **kwargs): | ||
def _cmd_status( | ||
self, | ||
cmds, | ||
raises=False, | ||
warn=True, | ||
stdin=None, | ||
output=True, | ||
**kwargs | ||
): | ||
"""Execute a command.""" | ||
timeout = None | ||
if "timeout" in kwargs: | ||
|
@@ -949,7 +957,11 @@ | |
|
||
pinput, stdin = Commander._cmd_status_input(stdin) | ||
p, actual_cmd = self._popen("cmd_status", cmds, stdin=stdin, **kwargs) | ||
o, e = p.communicate(pinput, timeout=timeout) | ||
if output: | ||
o, e = p.communicate(pinput, timeout=timeout) | ||
else: | ||
o = '' | ||
e = '' | ||
return self._cmd_status_finish(p, cmds, actual_cmd, o, e, raises, warn) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This call is expecting to run after the process has completed (one side effect of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I figured that in the case that an immediate error occurred within the process, then maybe catching it isn't a bad thing. In retrospect though, leaving that up to chance is probably a bad idea and consistency would be preferred so I will probably modify this to skip the |
||
|
||
async def _async_cmd_status( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -431,6 +431,7 @@ def _command( | |
self, | ||
target: str, | ||
cmd: str, | ||
**kwargs, | ||
) -> str: | ||
"""Execute a ``cmd`` and return result. | ||
|
||
|
@@ -439,7 +440,7 @@ def _command( | |
cmd: string to execut on the target. | ||
""" | ||
out = self.targets[target].cmd_nostatus( | ||
cmd, stdin=subprocess.DEVNULL, warn=False | ||
cmd, stdin=subprocess.DEVNULL, warn=False, **kwargs | ||
) | ||
self.last = out = out.rstrip() | ||
report = out if out else "<no output>" | ||
|
@@ -742,20 +743,26 @@ def section(self, desc: str): | |
self.oplogf(" section setting __in_section to True") | ||
self.__print_header(self.info.tag, desc, add_nl) | ||
|
||
def step(self, target: str, cmd: str) -> str: | ||
def step( | ||
self, | ||
target: str, | ||
cmd: str, | ||
output: bool = True, | ||
) -> str: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In general creating these fire-and-forget processes is messy b/c there's no guarantee they will complete before the test exists (in which case they will probably be killed by the kernel, or have PIPE closed signals or something). For non-mutest uses one uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder about the actual use case. Might a new API that runs multiple commands simultaneously and waits for them all to complete would be a cleaner solution ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The use case I have encountered twice now is the desire to create some sort of traffic generator on a node (or two nodes in the case of setting up a client/server pair situation) and then run a series of tests based on the results (perhaps on separate nodes). While it would probably be feasible to do this with some sort of new I do agree that letting the kernel kill the processes is a naive solution though, so perhaps the best solution would be to keep track of all fire-and-forget processes in a list and clean it up later when a node is being deleted? |
||
"""See :py:func:`~munet.mutest.userapi.step`. | ||
|
||
:meta private: | ||
""" | ||
self.logf( | ||
"#%s.%s:%s:STEP:%s:%s", | ||
"#%s.%s:%s:STEP:%s:%s:%s", | ||
self.tag, | ||
self.steps + 1, | ||
self.info.path, | ||
target, | ||
cmd, | ||
output, | ||
) | ||
return self._command(target, cmd) | ||
return self._command(target, cmd, output=output) | ||
|
||
def step_json(self, target: str, cmd: str) -> Union[list, dict]: | ||
"""See :py:func:`~munet.mutest.userapi.step_json`. | ||
|
@@ -1007,17 +1014,18 @@ def get_target(name: str) -> Commander: | |
return TestCase.g_tc.targets[name] | ||
|
||
|
||
def step(target: str, cmd: str) -> str: | ||
def step(target: str, cmd: str, output: bool = True) -> str: | ||
"""Execute a ``cmd`` on a ``target`` and return the output. | ||
|
||
Args: | ||
target: the target to execute the ``cmd`` on. | ||
cmd: string to execute on the target. | ||
output: if False, then DO NOT wait for output. Otherwise waits for ``cmd`` completion. | ||
|
||
Returns: | ||
Returns the ``str`` output of the ``cmd``. | ||
""" | ||
return TestCase.g_tc.step(target, cmd) | ||
return TestCase.g_tc.step(target, cmd, output) | ||
|
||
|
||
def step_json(target: str, cmd: str) -> Union[list, dict]: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
"""Test that out-of-order cmd execution is supported by step""" | ||
from munet.mutest.userapi import wait_step, section, step | ||
|
||
section("Test the no-output arg in step") | ||
|
||
step('r1', 'touch test-file1; sleep 1; mv test-file1 test-file2', output=False) | ||
|
||
wait_step('r1', 'ls', 'test-file1', 'Saw test-file1', 2, 0.1) | ||
wait_step('r1', 'ls', 'test-file2', 'Saw test-file2', 2, 0.1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand you're looking for a "fire-and-forget" command, I just wonder if this is the right way to do that.
I think that perhaps instead of
output
the new param should beno_wait=False
.I'm also wondering if we should explicitly set
stdout=subprocess.DEVNULL
andstderr=subprocess.DEVNULL
.