Stand-alone tests: disallow re-using an alias (#25881)

It can be frustrating to successfully run `spack test run --alias <name>` only to find you cannot get the results because you already use `<name>` in some previous stand-alone test execution.  This PR prevents that from happening.
This commit is contained in:
Tamara Dahlgren 2021-10-14 15:08:00 -07:00 committed by GitHub
parent beb8a36792
commit 41d375f6a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 8 deletions

View File

@ -137,6 +137,12 @@ def test_run(args):
If no specs are listed, run tests for all packages in the current If no specs are listed, run tests for all packages in the current
environment or all installed packages if there is no active environment. environment or all installed packages if there is no active environment.
""" """
if args.alias:
suites = spack.install_test.get_named_test_suites(args.alias)
if suites:
tty.die('Test suite "{0}" already exists. Try another alias.'
.format(args.alias))
# cdash help option # cdash help option
if args.help_cdash: if args.help_cdash:
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(

View File

@ -64,18 +64,33 @@ def valid_stage(d):
return test_suites return test_suites
def get_test_suite(name): def get_named_test_suites(name):
assert name, "Cannot search for empty test name or 'None'" """Return a list of the names of any test suites with that name."""
if not name:
raise TestSuiteNameError('Test suite name is required.')
test_suites = get_all_test_suites() test_suites = get_all_test_suites()
names = [ts for ts in test_suites return [ts for ts in test_suites if ts.name == name]
if ts.name == name]
assert len(names) < 2, "alias shadows test suite hash"
def get_test_suite(name):
names = get_named_test_suites(name)
if len(names) > 1:
raise TestSuiteNameError(
'Too many suites named "{0}". May shadow hash.'.format(name)
)
if not names: if not names:
return None return None
return names[0] return names[0]
def write_test_suite_file(suite):
"""Write the test suite to its lock file."""
with open(suite.stage.join(test_suite_filename), 'w') as f:
sjson.dump(suite.to_dict(), stream=f)
class TestSuite(object): class TestSuite(object):
def __init__(self, specs, alias=None): def __init__(self, specs, alias=None):
# copy so that different test suites have different package objects # copy so that different test suites have different package objects
@ -250,8 +265,7 @@ def write_reproducibility_data(self):
except spack.repo.UnknownPackageError: except spack.repo.UnknownPackageError:
pass # not all virtuals have package files pass # not all virtuals have package files
with open(self.stage.join(test_suite_filename), 'w') as f: write_test_suite_file(self)
sjson.dump(self.to_dict(), stream=f)
def to_dict(self): def to_dict(self):
specs = [s.to_dict() for s in self.specs] specs = [s.to_dict() for s in self.specs]
@ -310,3 +324,7 @@ def __init__(self, num_failures):
class TestSuiteSpecError(spack.error.SpackError): class TestSuiteSpecError(spack.error.SpackError):
"""Raised when there is an issue associated with the spec being tested.""" """Raised when there is an issue associated with the spec being tested."""
class TestSuiteNameError(spack.error.SpackError):
"""Raised when there is an issue with the naming of the test suite."""

View File

@ -39,11 +39,29 @@ def test_test_dirty_flag(arguments, expected):
assert args.dirty == expected assert args.dirty == expected
def test_test_dup_alias(
mock_test_stage, mock_packages, mock_archive, mock_fetch,
install_mockery_mutable_config, capfd):
"""Ensure re-using an alias fails with suggestion to change."""
install('libdwarf')
# Run the tests with the alias once
out = spack_test('run', '--alias', 'libdwarf', 'libdwarf')
assert "Spack test libdwarf" in out
# Try again with the alias but don't let it fail on the error
with capfd.disabled():
out = spack_test(
'run', '--alias', 'libdwarf', 'libdwarf', fail_on_error=False)
assert "already exists" in out
def test_test_output(mock_test_stage, mock_packages, mock_archive, mock_fetch, def test_test_output(mock_test_stage, mock_packages, mock_archive, mock_fetch,
install_mockery_mutable_config): install_mockery_mutable_config):
"""Ensure output printed from pkgs is captured by output redirection.""" """Ensure output printed from pkgs is captured by output redirection."""
install('printing-package') install('printing-package')
spack_test('run', 'printing-package') spack_test('run', '--alias', 'printpkg', 'printing-package')
stage_files = os.listdir(mock_test_stage) stage_files = os.listdir(mock_test_stage)
assert len(stage_files) == 1 assert len(stage_files) == 1

View File

@ -119,3 +119,35 @@ def test_test_spec_run_once(mock_packages, install_mockery, mock_test_stage):
with pytest.raises(spack.install_test.TestSuiteFailure): with pytest.raises(spack.install_test.TestSuiteFailure):
test_suite() test_suite()
def test_get_test_suite():
assert not spack.install_test.get_test_suite('nothing')
def test_get_test_suite_no_name(mock_packages, mock_test_stage):
with pytest.raises(spack.install_test.TestSuiteNameError) as exc_info:
spack.install_test.get_test_suite('')
assert 'name is required' in str(exc_info)
def test_get_test_suite_too_many(mock_packages, mock_test_stage):
test_suites = []
name = 'duplicate-alias'
def add_suite(package):
spec = spack.spec.Spec(package).concretized()
suite = spack.install_test.TestSuite([spec], name)
suite.ensure_stage()
spack.install_test.write_test_suite_file(suite)
test_suites.append(suite)
add_suite('libdwarf')
suite = spack.install_test.get_test_suite(name)
assert suite.alias == name
add_suite('libelf')
with pytest.raises(spack.install_test.TestSuiteNameError) as exc_info:
spack.install_test.get_test_suite(name)
assert 'many suites named' in str(exc_info)