-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from pvarki/shell_helper
Add shell helper
- Loading branch information
Showing
8 changed files
with
98 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
[bumpversion] | ||
current_version = 1.8.0 | ||
current_version = 1.9.0 | ||
commit = False | ||
tag = False | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
""" Common helpers like standard logging init """ | ||
__version__ = "1.8.0" # NOTE Use `bump2version --config-file patch` to bump versions correctly | ||
__version__ = "1.9.0" # NOTE Use `bump2version --config-file patch` to bump versions correctly |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
"""Shell related helpers""" | ||
from typing import Tuple | ||
import asyncio | ||
import logging | ||
|
||
LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
async def call_cmd(cmd: str, timeout: float = 2.5, *, stderr_warn: bool = True) -> Tuple[int, str, str]: | ||
"""Do the boilerplate for calling cmd and returning the exit code and output as strings""" | ||
LOGGER.debug("Calling create_subprocess_shell(({})".format(cmd)) | ||
process = await asyncio.create_subprocess_shell( | ||
cmd, | ||
stdout=asyncio.subprocess.PIPE, | ||
stderr=asyncio.subprocess.PIPE, | ||
) | ||
out, err = await asyncio.wait_for(process.communicate(), timeout=timeout) | ||
out_str = out.decode("utf-8") | ||
err_str = err.decode("utf-8") | ||
if err and stderr_warn: | ||
LOGGER.warning("{} stderr: {}".format(cmd, err_str)) | ||
LOGGER.info(out_str) | ||
assert isinstance(process.returncode, int) # at this point it is, keep mypy happy | ||
if process.returncode != 0: | ||
LOGGER.error("{} returned nonzero code: {} (process: {})".format(cmd, process.returncode, process)) | ||
LOGGER.error("{} stderr: {}".format(cmd, err_str)) | ||
LOGGER.error("{} stdout: {}".format(cmd, out_str)) | ||
|
||
return process.returncode, out_str, err_str |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
"""Test shell helpers""" | ||
import logging | ||
import asyncio | ||
|
||
import pytest | ||
|
||
from libpvarki.shell import call_cmd | ||
|
||
LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_true() -> None: | ||
"""Test that true exists with code 0""" | ||
code, stdout, stderr = await call_cmd("true") | ||
assert code == 0 | ||
assert stdout == "" | ||
assert stderr == "" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_false() -> None: | ||
"""Test that false exists with nonzero code""" | ||
code, stdout, stderr = await call_cmd("false") | ||
assert code != 0 | ||
assert stdout == "" | ||
assert stderr == "" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_stdout() -> None: | ||
"""Test that echo exists with code 0 and ouputs what we expect to stdout""" | ||
code, stdout, stderr = await call_cmd("echo 'hello world'") | ||
assert code == 0 | ||
assert stdout == "hello world\n" | ||
assert stderr == "" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_stderr() -> None: | ||
"""Test that echo exists with code 0 and ouputs what we expect to stderr""" | ||
code, stdout, stderr = await call_cmd("echo 'goodbye world' >&2") | ||
# FIXME: Capture log output and check for the warning | ||
assert code == 0 | ||
assert stdout == "" | ||
assert stderr == "goodbye world\n" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_stderr_nowarn() -> None: | ||
"""Test that echo exists with code 0 and ouputs what we expect to stderr""" | ||
code, stdout, stderr = await call_cmd("echo 'goodbye world' >&2", stderr_warn=False) | ||
# FIXME: Capture log output and check that there is no warning | ||
assert code == 0 | ||
assert stdout == "" | ||
assert stderr == "goodbye world\n" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_timeout() -> None: | ||
"""Test that long sleeps are aborted on timeout""" | ||
with pytest.raises(asyncio.TimeoutError): | ||
await call_cmd("sleep 5", timeout=1.0) |