Skip to content
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

release EasyBuild v4.5.1 #3916

Merged
merged 57 commits into from
Dec 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
3683bb1
Also dump environment to reprod directory
Jun 29, 2020
ba3347a
Add test
Jun 29, 2020
428def9
Only do a simple process on easyconfig for dumping
Jun 29, 2020
a19b15a
Fix env duping and make silent
Jun 29, 2020
acdb965
Refactor dump_env_script rather than create new easyblock instance
Jun 30, 2020
d66b0cc
Remove unused import
Jun 30, 2020
4a023f0
Missed a kwarg in use of refactored function
Jun 30, 2020
e0033da
Correct name on test
Jun 30, 2020
1fe810d
Add an additional test for the contents of the dumped env script in t…
Jun 30, 2020
a048a7e
Merge branch 'develop' into dumpenv_reprod
boegel Jul 4, 2020
8d1730f
remove duplicate (merge conflict due to #3375 was not resolved correc…
boegel Jul 4, 2020
1a20092
Merge branch 'develop' into dumpenv_reprod
Jul 6, 2020
78d24d7
Do the environment dump after the easyblock was used
Jul 6, 2020
c2d4361
Add test for dumping of buildenv (to check if it includes module load…
Jul 6, 2020
31affca
Merge branch 'develop' into dumpenv_reprod
Sep 17, 2021
fdd13a4
Restore edited comment
Sep 17, 2021
d41ce1c
bump version to 4.5.1dev
boegel Oct 29, 2021
ef9a1d4
Merge pull request #3887 from boegel/develop
Micket Oct 29, 2021
4baee22
only remove lock if it was created in the same EasyBuild session (not…
boegel Oct 30, 2021
ec6b1ab
determine which extensions can be skipped in parallel (if EasyBuild i…
boegel Oct 31, 2021
40fa1c5
check expected output lines one by one when testing skipping extensio…
boegel Oct 31, 2021
ce9b66f
Merge pull request #3374 from ocaisa/dumpenv_reprod
akesandgren Nov 2, 2021
2937c91
take into account that repositorypath could specify remote repository…
boegel Nov 7, 2021
770b8ce
Merge pull request #3893 from boegel/remote_repositorypath
akesandgren Nov 8, 2021
e8c5f96
fix typo in Agreement
bedroge Nov 8, 2021
6cde2f9
fix typo in Agreement
bedroge Nov 8, 2021
cac8c65
Merge pull request #3894 from bedroge/fix_agreement_typo
branfosj Nov 8, 2021
7333b4b
Merge pull request #3890 from boegel/skip_extensions_parallel
branfosj Nov 10, 2021
450d7bb
Merge pull request #3889 from boegel/fix_remove_lock
branfosj Nov 11, 2021
8de5b7d
don't try to ensure absolute path for path part of repositorypath
boegel Nov 18, 2021
d68e31f
fix broken tests now that repositorypath is a list (again), rather th…
boegel Nov 18, 2021
6b9a88f
Merge pull request #3899 from boegel/repositorypath_abs_path
bartoldeman Nov 19, 2021
007edeb
fix builddir value when --sanity-check-only is used and buildininstal…
boegel Nov 19, 2021
bc5cdec
fix broken test for buildininstalldir
boegel Nov 20, 2021
5ac3339
also show download progress bar when using --inject-checksums
boegel Nov 27, 2021
7c04252
return None if required dependencies for an extension could not be de…
boegel Nov 27, 2021
fd4dfc4
Merge pull request #3905 from boegel/inject_checksums_progress
smoors Nov 29, 2021
d008310
pick up custom extract_cmd specified for extension
boegel Nov 30, 2021
ff98040
fix broken test_toy_exts_parallel with Python 2 by testing last with …
boegel Dec 3, 2021
7575509
make test_run_cmd_async more robust against fluke failures
boegel Dec 4, 2021
4454f71
Merge pull request #3906 from boegel/required_deps_None
branfosj Dec 4, 2021
d0d6d1a
Merge pull request #3908 from boegel/robust_test_run_cmd_async
branfosj Dec 4, 2021
eace8e3
extend test_sanity_check_only to also check whether build_in_installd…
boegel Dec 4, 2021
9623629
introduce post_init method to ensure that builddir EasyBlock variable…
boegel Dec 4, 2021
1d4e454
improve error message for unknown file extensions, add comment to cla…
boegel Dec 4, 2021
30d8763
Merge branch 'develop' of https://github.com/easybuilders/easybuild-f…
Dec 4, 2021
f1f421b
Merge pull request #3907 from boegel/ext_extract_cmd
smoors Dec 4, 2021
e4344d0
clean up included toy easyblock in test_sanity_check_only
boegel Dec 4, 2021
d0a759e
fix broken test_buildininstalldir by calling also post_init method af…
boegel Dec 7, 2021
7066e03
correctly undo included toy toolchain in test_sanity_check_only
boegel Dec 7, 2021
77f63e0
Merge pull request #3900 from boegel/fix_builddir_sanity_check_only
branfosj Dec 7, 2021
18b0499
allow oversubscription in sanity check for OpenMPI-based toolchains
boegel Dec 7, 2021
fd2b6a0
fix check to see whether toolchain includes OpenMPI
boegel Dec 8, 2021
0c1a642
Merge pull request #3909 from boegel/openmpi_oversubscription
migueldiascosta Dec 8, 2021
28c2905
prepare release notes for EasyBuild v4.5.1 + bump version to 4.5.1
migueldiascosta Dec 10, 2021
313e5e8
tweak release notes for v4.5.1 release
boegel Dec 11, 2021
9ea450b
Merge pull request #3913 from migueldiascosta/eb451
boegel Dec 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions RELEASE_NOTES
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ For more detailed information, please see the git log.
These release notes can also be consulted at https://easybuild.readthedocs.io/en/latest/Release_notes.html.


v4.5.1 (December 13th 2021)
---------------------------

update/bugfix release

- various enhancements, including:
- also dump environment to reprod directory (#3374)
- determine which extensions can be skipped in parallel (if --parallel-extensions-install is enabled) (#3890)
- fall back to sequential installation for extensions with unknown dependencies when using --parallel-extensions-install (#3906)
- allow oversubscription in sanity check for OpenMPI-based toolchains (#3909)
- various bug fixes, including:
- don't try to ensure absolute path for path part of repositorypath (#3893, #3899)
- fix typo in EULA agreement error message (#3894)
- only remove lock if it was created in the same EasyBuild session (not if it existed already) (#3889)
- introduce EasyBlock.post_init method to correctly define builddir variable when build-in-installdir mode is enabled in easyconfig or easyblock (#3900)
- also show download progress bar when using --inject-checksums (#3905)
- pick up custom extract_cmd specified for extension (#3907)
- make test_run_cmd_async more robust against fluke failures (#3908)


v4.5.0 (October 29th 2021)
--------------------------

Expand Down
165 changes: 141 additions & 24 deletions easybuild/framework/easyblock.py

Large diffs are not rendered by default.

66 changes: 41 additions & 25 deletions easybuild/framework/easyconfig/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,45 @@ def review_pr(paths=None, pr=None, colored=True, branch='develop', testing=False
return '\n'.join(lines)


def dump_env_easyblock(app, orig_env=None, ec_path=None, script_path=None, silent=False):
if orig_env is None:
orig_env = copy.deepcopy(os.environ)
if ec_path is None:
raise EasyBuildError("The path to the easyconfig relevant to this environment dump is required")
if script_path is None:
# Assume we are placing it alongside the easyconfig path
script_path = '%s.env' % os.path.splitext(ec_path)[0]
# Compose script
ecfile = os.path.basename(ec_path)
script_lines = [
"#!/bin/bash",
"# script to set up build environment as defined by EasyBuild v%s for %s" % (EASYBUILD_VERSION, ecfile),
"# usage: source %s" % os.path.basename(script_path),
]

script_lines.extend(['', "# toolchain & dependency modules"])
if app.toolchain.modules:
script_lines.extend(["module load %s" % mod for mod in app.toolchain.modules])
else:
script_lines.append("# (no modules loaded)")

script_lines.extend(['', "# build environment"])
if app.toolchain.vars:
env_vars = sorted(app.toolchain.vars.items())
script_lines.extend(["export %s='%s'" % (var, val.replace("'", "\\'")) for (var, val) in env_vars])
else:
script_lines.append("# (no build environment defined)")

write_file(script_path, '\n'.join(script_lines))
msg = "Script to set up build environment for %s dumped to %s" % (ecfile, script_path)
if silent:
_log.info(msg)
else:
print_msg(msg, prefix=False)

restore_env(orig_env)


def dump_env_script(easyconfigs):
"""
Dump source scripts that set up build environment for specified easyconfigs.
Expand Down Expand Up @@ -591,31 +630,8 @@ def dump_env_script(easyconfigs):
app.check_readiness_step()
app.prepare_step(start_dir=False)

# compose script
ecfile = os.path.basename(ec.path)
script_lines = [
"#!/bin/bash",
"# script to set up build environment as defined by EasyBuild v%s for %s" % (EASYBUILD_VERSION, ecfile),
"# usage: source %s" % os.path.basename(script_path),
]

script_lines.extend(['', "# toolchain & dependency modules"])
if app.toolchain.modules:
script_lines.extend(["module load %s" % mod for mod in app.toolchain.modules])
else:
script_lines.append("# (no modules loaded)")

script_lines.extend(['', "# build environment"])
if app.toolchain.vars:
env_vars = sorted(app.toolchain.vars.items())
script_lines.extend(["export %s='%s'" % (var, val.replace("'", "\\'")) for (var, val) in env_vars])
else:
script_lines.append("# (no build environment defined)")

write_file(script_path, '\n'.join(script_lines))
print_msg("Script to set up build environment for %s dumped to %s" % (ecfile, script_path), prefix=False)

restore_env(orig_env)
# create the environment dump
dump_env_easyblock(app, orig_env=orig_env, ec_path=ec.path, script_path=script_path)


def categorize_files_by_type(paths):
Expand Down
4 changes: 3 additions & 1 deletion easybuild/framework/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def __init__(self, mself, ext, extra_params=None):

# list of source/patch files: we use an empty list as default value like in EasyBlock
self.src = resolve_template(self.ext.get('src', []), self.cfg.template_values)
self.src_extract_cmd = self.ext.get('extract_cmd', None)
self.patches = resolve_template(self.ext.get('patches', []), self.cfg.template_values)
self.options = resolve_template(copy.deepcopy(self.ext.get('options', {})), self.cfg.template_values)

Expand Down Expand Up @@ -225,7 +226,8 @@ def async_cmd_check(self):
@property
def required_deps(self):
"""Return list of required dependencies for this extension."""
raise NotImplementedError("Don't know how to determine required dependencies for extension '%s'" % self.name)
self.log.info("Don't know how to determine required dependencies for extension '%s'", self.name)
return None

@property
def toolchain(self):
Expand Down
2 changes: 1 addition & 1 deletion easybuild/framework/extensioneasyblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def run(self, unpack_src=False):
if unpack_src:
targetdir = os.path.join(self.master.builddir, remove_unwanted_chars(self.name))
self.ext_dir = extract_file(self.src, targetdir, extra_options=self.unpack_options,
change_into_dir=False)
change_into_dir=False, cmd=self.src_extract_cmd)

# setting start dir must be done from unpacked source directory for extension,
# because start_dir value is usually a relative path (if it is set)
Expand Down
3 changes: 2 additions & 1 deletion easybuild/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,8 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
dump_env_script(easyconfigs)

elif options.inject_checksums:
inject_checksums(ordered_ecs, options.inject_checksums)
with rich_live_cm():
inject_checksums(ordered_ecs, options.inject_checksums)

# cleanup and exit after dry run, searching easyconfigs or submitting regression test
stop_options = [options.check_conflicts, dry_run_mode, options.dump_env_script, options.inject_checksums]
Expand Down
13 changes: 9 additions & 4 deletions easybuild/tools/filetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,11 +456,14 @@ def extract_file(fn, dest, cmd=None, extra_options=None, overwrite=False, forced
_log.debug("Unpacking %s in directory %s", fn, abs_dest)
cwd = change_dir(abs_dest)

if not cmd:
cmd = extract_cmd(fn, overwrite=overwrite)
else:
if cmd:
# complete command template with filename
cmd = cmd % fn
_log.debug("Using specified command to unpack %s: %s", fn, cmd)
else:
cmd = extract_cmd(fn, overwrite=overwrite)
_log.debug("Using command derived from file extension to unpack %s: %s", fn, cmd)

if not cmd:
raise EasyBuildError("Can't extract file %s with unknown filetype", fn)

Expand Down Expand Up @@ -1366,7 +1369,7 @@ def find_extension(filename):
if res:
ext = res.group('ext')
else:
raise EasyBuildError('Unknown file type for file %s', filename)
raise EasyBuildError("%s has unknown file extension", filename)

return ext

Expand All @@ -1379,7 +1382,9 @@ def extract_cmd(filepath, overwrite=False):
ext = find_extension(filename)
target = filename[:-len(ext)]

# find_extension will either return an extension listed in EXTRACT_CMDS, or raise an error
cmd_tmpl = EXTRACT_CMDS[ext.lower()]

if overwrite:
if 'unzip -qq' in cmd_tmpl:
cmd_tmpl = cmd_tmpl.replace('unzip -qq', 'unzip -qq -o')
Expand Down
22 changes: 10 additions & 12 deletions easybuild/tools/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ def _postprocess_checks(self):

def get_cfg_opt_abs_path(self, opt_name, path):
"""Get path value of configuration option as absolute path."""
if os.path.isabs(path):
if os.path.isabs(path) or path.startswith('git@'):
abs_path = path
else:
abs_path = os.path.abspath(path)
Expand All @@ -1092,22 +1092,20 @@ def _ensure_abs_path(self, opt_name):
def _postprocess_config(self):
"""Postprocessing of configuration options"""

# resolve relative paths for configuration options that specify a location;
# resolve relative paths for configuration options that specify a location,
# to avoid incorrect paths being used when EasyBuild changes the current working directory
# (see https://github.com/easybuilders/easybuild-framework/issues/3619);
# ensuring absolute paths for 'robot' is handled separately below,
# because we need to be careful with the argument pass to --robot
# because we need to be careful with the argument pass to --robot;
# note: repositorypath is purposely not listed here, because it's a special case:
# - the value could consist of a 2-tuple (<path>, <relative_subdir>);
# - the <path> could also specify the location of a *remote* (Git( repository,
# which can be done in variety of formats (git@<url>:<org>/<repo>), https://<url>, etc.)
# (see also https://github.com/easybuilders/easybuild-framework/issues/3892);
path_opt_names = ['buildpath', 'containerpath', 'git_working_dirs_path', 'installpath',
'installpath_modules', 'installpath_software', 'prefix', 'packagepath',
'robot_paths', 'sourcepath']

# repositorypath is a special case: only first part is a path;
# 2nd (optional) part is a relative subdir and should not be resolved to an absolute path!
repositorypath = self.options.repositorypath
if isinstance(repositorypath, (list, tuple)) and len(repositorypath) == 2:
abs_path = self.get_cfg_opt_abs_path('repositorypath', repositorypath[0])
self.options.repositorypath = (abs_path, repositorypath[1])
else:
path_opt_names.append('repositorypath')

for opt_name in path_opt_names:
self._ensure_abs_path(opt_name)

Expand Down
2 changes: 1 addition & 1 deletion easybuild/tools/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
# recent setuptools versions will *TRANSFORM* something like 'X.Y.Zdev' into 'X.Y.Z.dev0', with a warning like
# UserWarning: Normalizing '2.4.0dev' to '2.4.0.dev0'
# This causes problems further up the dependency chain...
VERSION = LooseVersion('4.5.0')
VERSION = LooseVersion('4.5.1')
UNKNOWN = 'UNKNOWN'


Expand Down
2 changes: 1 addition & 1 deletion test/framework/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ def test_generaloption_config_file(self):
self.assertEqual(install_path('mod'), installpath_modules), # via config file
self.assertEqual(source_paths(), [testpath2]) # via command line
self.assertEqual(build_path(), testpath1) # via config file
self.assertEqual(get_repositorypath(), (os.path.join(topdir, 'ebfiles_repo'), 'somesubdir')) # via config file
self.assertEqual(get_repositorypath(), [os.path.join(topdir, 'ebfiles_repo'), 'somesubdir']) # via config file

# hardcoded first entry
self.assertEqual(options.robot_paths[0], '/tmp/foo')
Expand Down
3 changes: 1 addition & 2 deletions test/framework/easyconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -1335,8 +1335,7 @@ def test_buildininstalldir(self):
self.prep()
ec = EasyConfig(self.eb_file)
eb = EasyBlock(ec)
eb.gen_builddir()
eb.gen_installdir()
eb.post_init()
eb.make_builddir()
eb.make_installdir()
self.assertEqual(eb.builddir, eb.installdir)
Expand Down
3 changes: 3 additions & 0 deletions test/framework/filetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ def test_extract_cmd(self):

self.assertEqual("unzip -qq -o test.zip", ft.extract_cmd('test.zip', True))

error_pattern = "test.foo has unknown file extension"
self.assertErrorRegex(EasyBuildError, error_pattern, ft.extract_cmd, 'test.foo')

def test_find_extension(self):
"""Test find_extension function."""
tests = [
Expand Down
74 changes: 70 additions & 4 deletions test/framework/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -4854,8 +4854,8 @@ def test_prefix_option(self):
expected = ['buildpath', 'containerpath', 'installpath', 'packagepath', 'prefix', 'repositorypath']
self.assertEqual(sorted(regex.findall(txt)), expected)

def test_dump_env_config(self):
"""Test for --dump-env-config."""
def test_dump_env_script(self):
"""Test for --dump-env-script."""

fftw = 'FFTW-3.3.7-gompic-2018a'
gcc = 'GCC-4.9.2'
Expand Down Expand Up @@ -6037,6 +6037,53 @@ def test_sanity_check_only(self):

stdout = self.mocked_main(args + ['--trace'], do_build=True, raise_error=True, testing=False)

# check whether %(builddir)s value is correct
# when buildininstalldir is enabled in easyconfig and --sanity-check-only is used
# (see https://github.com/easybuilders/easybuild-framework/issues/3895)
test_ec_txt += '\n' + '\n'.join([
"buildininstalldir = True",
"sanity_check_commands = [",
# build and install directory should be the same path
" 'test %(builddir)s = %(installdir)s',",
# build/install directory must exist (even though step that creates build dir was never run)
" 'test -d %(builddir)s',",
"]",
])
write_file(test_ec, test_ec_txt)
self.eb_main(args, do_build=True, raise_error=True)

# also check when using easyblock that enables build_in_installdir in its constructor
test_ebs = os.path.join(topdir, 'sandbox', 'easybuild', 'easyblocks')
toy_eb = os.path.join(test_ebs, 't', 'toy.py')
toy_eb_txt = read_file(toy_eb)

self.assertFalse('self.build_in_installdir = True' in toy_eb_txt)

regex = re.compile(r'^(\s+)(super\(EB_toy, self\).__init__.*)\n', re.M)
toy_eb_txt = regex.sub(r'\1\2\n\1self.build_in_installdir = True', toy_eb_txt)
self.assertTrue('self.build_in_installdir = True' in toy_eb_txt)

toy_eb = os.path.join(self.test_prefix, 'toy.py')
write_file(toy_eb, toy_eb_txt)

test_ec_txt = test_ec_txt.replace('buildininstalldir = True', '')
write_file(test_ec, test_ec_txt)

orig_local_sys_path = sys.path[:]
args.append('--include-easyblocks=%s' % toy_eb)
self.eb_main(args, do_build=True, raise_error=True)

# undo import of the toy easyblock, to avoid problems with other tests
del sys.modules['easybuild.easyblocks.toy']
sys.path = orig_local_sys_path
import easybuild.easyblocks
reload(easybuild.easyblocks)
import easybuild.easyblocks.toy
reload(easybuild.easyblocks.toy)
# need to reload toy_extension, which imports EB_toy, to ensure right EB_toy is picked up in later tests
import easybuild.easyblocks.generic.toy_extension
reload(easybuild.easyblocks.generic.toy_extension)

def test_skip_extensions(self):
"""Test use of --skip-extensions."""
topdir = os.path.abspath(os.path.dirname(__file__))
Expand Down Expand Up @@ -6242,7 +6289,7 @@ def test_accept_eula_for(self):

# by default, no EULAs are accepted at all
args = [test_ec, '--force']
error_pattern = r"The End User License Argreement \(EULA\) for toy is currently not accepted!"
error_pattern = r"The End User License Agreement \(EULA\) for toy is currently not accepted!"
self.assertErrorRegex(EasyBuildError, error_pattern, self.eb_main, args, do_build=True, raise_error=True)
toy_modfile = os.path.join(self.test_installpath, 'modules', 'all', 'toy', '0.0')
if get_module_syntax() == 'Lua':
Expand Down Expand Up @@ -6334,7 +6381,7 @@ def test_config_abs_path(self):
r"^containerpath\s+\(F\) = /.*/test_topdir/test_middle_dir$",
r"^installpath\s+\(E\) = /.*/test_topdir$",
r"^prefix\s+\(C\) = /.*/test_topdir/test_middle_dir$",
r"^repositorypath\s+\(F\) = \('/apps/easyconfigs_archive', ' somesubdir'\)$",
r"^repositorypath\s+\(F\) = /apps/easyconfigs_archive,\s+somesubdir$",
r"^sourcepath\s+\(C\) = /.*/test_topdir/test_middle_dir/test_subdir$",
r"^robot-paths\s+\(E\) = /.*/test_topdir$",
]
Expand All @@ -6361,6 +6408,25 @@ def test_config_abs_path(self):
regex = re.compile(pattern, re.M)
self.assertTrue(regex.search(txt), "Pattern '%s' should be found in: %s" % (pattern, txt))

def test_config_repositorypath(self):
"""Test how special repositorypath values are handled."""

repositorypath = 'git@github.com:boegel/my_easyconfigs.git'
args = [
'--repositorypath=%s' % repositorypath,
'--show-config',
]
txt, _ = self._run_mock_eb(args, do_build=True, raise_error=True, testing=False, strip=True)

regex = re.compile(r'repositorypath\s+\(C\) = %s' % repositorypath, re.M)
self.assertTrue(regex.search(txt), "Pattern '%s' should be found in: %s" % (regex.pattern, txt))

args[0] = '--repositorypath=%s,some/subdir' % repositorypath
txt, _ = self._run_mock_eb(args, do_build=True, raise_error=True, testing=False, strip=True)

regex = re.compile(r"repositorypath\s+\(C\) = %s, some/subdir" % repositorypath, re.M)
self.assertTrue(regex.search(txt), "Pattern '%s' should be found in: %s" % (regex.pattern, txt))

# end-to-end testing of unknown filename
def test_easystack_wrong_read(self):
"""Test for --easystack <easystack.yaml> when wrong name is provided"""
Expand Down
4 changes: 3 additions & 1 deletion test/framework/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,9 @@ def test_run_cmd_async(self):
self.assertEqual(res, {'done': False, 'exit_code': None, 'output': 'sleeping...\n'})

# 2nd check with default output size (1024) gets full output
res = check_async_cmd(*cmd_info, output=res['output'])
# (keep checking until command is fully done)
while not res['done']:
res = check_async_cmd(*cmd_info, output=res['output'])
self.assertEqual(res, {'done': True, 'exit_code': 0, 'output': 'sleeping...\ntest123\n'})

# check asynchronous running of failing command
Expand Down
Loading