# Copyright 2022-2025 The Ramble Authors
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
import pytest
import ramble.expander
import ramble.renderer
import ramble.software_environments
import ramble.workspace
from ramble.main import RambleCommand
pytestmark = pytest.mark.usefixtures(
"mutable_config",
"mutable_mock_workspace_path",
"mutable_mock_apps_repo",
)
workspace = RambleCommand("workspace")
def _get_package_manager(pm_name: str = "spack"):
return ramble.repository.get(pm_name, ramble.repository.ObjectTypes.package_managers).copy()
[docs]
def test_basic_software_environment(request, mutable_mock_workspace_path):
ws_name = request.node.name
workspace("create", ws_name)
assert ws_name in workspace("list")
with ramble.workspace.read(ws_name) as ws:
software_dict = ws.get_software_dict()
software_dict["packages"] = {}
software_dict["packages"]["basic"] = {"pkg_spec": "basic@1.1"}
software_dict["environments"] = {"basic": {"packages": ["basic"]}}
software_environments = ramble.software_environments.SoftwareEnvironments(ws)
assert "basic" in software_environments._environment_templates
assert "basic" in software_environments._package_templates
variables = {}
env_expander = ramble.expander.Expander(variables, None)
rendered_env = software_environments.render_environment(
"basic", env_expander, _get_package_manager()
)
assert rendered_env.name == "basic"
pkg_found = False
for pkg in rendered_env._packages:
if pkg.name == "basic":
pkg_found = True
assert pkg_found
[docs]
def test_software_environments_no_packages(request, mutable_mock_workspace_path):
ws_name = request.node.name
workspace("create", ws_name)
assert ws_name in workspace("list")
with ramble.workspace.read(ws_name) as ws:
software_dict = ws.get_software_dict()
software_dict["packages"] = {}
software_dict["environments"] = {"basic-{env_test}": {"packages": [""]}}
software_environments = ramble.software_environments.SoftwareEnvironments(ws)
assert "basic-{env_test}" in software_environments._environment_templates
variables = {
"env_test": "environment",
}
env_expander = ramble.expander.Expander(variables, None)
rendered_env = software_environments.render_environment(
"basic-environment", env_expander, _get_package_manager()
)
assert rendered_env.name == "basic-environment"
[docs]
def test_software_environments_no_rendered_packages(request, mutable_mock_workspace_path):
ws_name = request.node.name
workspace("create", ws_name)
assert ws_name in workspace("list")
with ramble.workspace.read(ws_name) as ws:
software_dict = ws.get_software_dict()
software_dict["packages"] = {}
software_dict["environments"] = {"basic-{env_test}": {"packages": ["{var_pkg_name}"]}}
software_environments = ramble.software_environments.SoftwareEnvironments(ws)
assert "basic-{env_test}" in software_environments._environment_templates
variables = {"env_test": "environment", "var_pkg_name": ""}
env_expander = ramble.expander.Expander(variables, None)
rendered_env = software_environments.render_environment(
"basic-environment", env_expander, _get_package_manager()
)
assert rendered_env.name == "basic-environment"
[docs]
def test_template_software_environments(request, mutable_mock_workspace_path):
ws_name = request.node.name
workspace("create", ws_name)
assert ws_name in workspace("list")
with ramble.workspace.read(ws_name) as ws:
software_dict = ws.get_software_dict()
software_dict["packages"] = {}
software_dict["packages"]["basic-{pkg_test}"] = {"pkg_spec": "basic@1.1"}
software_dict["environments"] = {"basic-{env_test}": {"packages": ["basic-{pkg_test}"]}}
software_environments = ramble.software_environments.SoftwareEnvironments(ws)
assert "basic-{env_test}" in software_environments._environment_templates
assert "basic-{pkg_test}" in software_environments._package_templates
variables = {
"env_test": "environment",
"pkg_test": "package",
}
env_expander = ramble.expander.Expander(variables, None)
rendered_env = software_environments.render_environment(
"basic-environment", env_expander, _get_package_manager()
)
assert rendered_env.name == "basic-environment"
pkg_found = False
for pkg in rendered_env._packages:
if pkg.name == "basic-package":
pkg_found = True
assert pkg_found
[docs]
def test_multi_template_software_environments(request, mutable_mock_workspace_path):
ws_name = request.node.name
workspace("create", ws_name)
assert ws_name in workspace("list")
with ramble.workspace.read(ws_name) as ws:
software_dict = ws.get_software_dict()
software_dict["packages"] = {}
software_dict["packages"]["basic1-{pkg_test}"] = {"pkg_spec": "basic@1.1"}
software_dict["packages"]["basic2-{pkg_test}"] = {"pkg_spec": "basic@1.1"}
software_dict["environments"] = {
"all-basic-{env_test}": {"packages": ["basic1-{pkg_test}", "basic2-{pkg_test}"]},
"basic1-{env_test}": {"packages": ["basic1-{pkg_test}"]},
"basic2-{env_test}": {"packages": ["basic2-{pkg_test}"]},
}
software_environments = ramble.software_environments.SoftwareEnvironments(ws)
assert "all-basic-{env_test}" in software_environments._environment_templates
assert "basic1-{env_test}" in software_environments._environment_templates
assert "basic2-{env_test}" in software_environments._environment_templates
assert "basic1-{pkg_test}" in software_environments._package_templates
assert "basic2-{pkg_test}" in software_environments._package_templates
variables = {
"env_test": "environment",
"pkg_test": "package",
}
env_expander = ramble.expander.Expander(variables, None)
env_tests = {
"all-basic-environment": ["basic1-package", "basic2-package"],
"basic1-environment": ["basic1-package"],
"basic2-environment": ["basic2-package"],
}
for env_name, env_packages in env_tests.items():
rendered_env = software_environments.render_environment(
env_name, env_expander, _get_package_manager()
)
assert rendered_env.name == env_name
assert len(rendered_env._packages) == len(env_packages)
for pkg_name in env_packages:
pkg_found = False
for pkg in rendered_env._packages:
if pkg.name == pkg_name:
pkg_found = True
assert pkg_found
[docs]
def test_undefined_package_errors(request, mutable_mock_workspace_path):
ws_name = request.node.name
workspace("create", ws_name)
assert ws_name in workspace("list")
with ramble.workspace.read(ws_name) as ws:
software_dict = ws.get_software_dict()
software_dict["packages"] = {}
software_dict["packages"]["basic-{pkg_test}"] = {"pkg_spec": "basic@{pkg_ver}"}
software_dict["environments"] = {
"all-basic-{env_test}": {"packages": ["foo-basic-{pkg_test}"]}
}
software_environments = ramble.software_environments.SoftwareEnvironments(ws)
variables = {"env_test": "environment"}
env_expander = ramble.expander.Expander(variables, None)
with pytest.raises(ramble.software_environments.RambleSoftwareEnvironmentError) as pkg_err:
software_environments.render_environment(
"all-basic-environment", env_expander, _get_package_manager()
)
err_str = (
"Environment template all-basic-{env_test} references undefined "
+ "package foo-basic-{pkg_test}"
)
assert err_str in str(pkg_err)
[docs]
def test_invalid_packages_error(request, mutable_mock_workspace_path):
ws_name = request.node.name
workspace("create", ws_name)
assert ws_name in workspace("list")
with ramble.workspace.read(ws_name) as ws:
software_dict = ws.get_software_dict()
software_dict["packages"] = {}
software_dict["packages"]["basic-{pkg_test}"] = {"pkg_spec": "basic@{pkg_ver}"}
software_dict["environments"] = {
"all-basic-{env_test}": {"packages": ["basic-{pkg_test}"]}
}
software_environments = ramble.software_environments.SoftwareEnvironments(ws)
assert "all-basic-{env_test}" in software_environments._environment_templates
assert "basic-{pkg_test}" in software_environments._package_templates
variables = {
"env_test": "environment",
"pkg_test": "package",
"pkg_ver": "1.1",
}
env_expander = ramble.expander.Expander(variables, None)
_ = software_environments.render_environment(
"all-basic-environment", env_expander, _get_package_manager()
)
with pytest.raises(ramble.software_environments.RambleSoftwareEnvironmentError) as pkg_err:
variables = {
"env_test": "environment",
"pkg_test": "package",
"pkg_ver": "1.4",
}
env_expander = ramble.expander.Expander(variables, None)
software_environments.render_environment(
"all-basic-environment", env_expander, _get_package_manager()
)
assert "Package basic-package defined multiple times" in str(pkg_err)
[docs]
def test_invalid_environment_error(request, mutable_mock_workspace_path):
ws_name = request.node.name
workspace("create", ws_name)
assert ws_name in workspace("list")
with ramble.workspace.read(ws_name) as ws:
software_dict = ws.get_software_dict()
software_dict["packages"] = {}
software_dict["packages"]["basic1-{pkg_test}"] = {"pkg_spec": "basic@1.1"}
software_dict["packages"]["basic2-{pkg_test}"] = {"pkg_spec": "basic@1.1"}
software_dict["environments"] = {
"all-basic-{env_test}": {"packages": ["basic1-{pkg_test}", "basic2-{pkg_test}"]}
}
software_environments = ramble.software_environments.SoftwareEnvironments(ws)
assert "all-basic-{env_test}" in software_environments._environment_templates
assert "basic1-{pkg_test}" in software_environments._package_templates
assert "basic2-{pkg_test}" in software_environments._package_templates
variables = {
"env_test": "environment",
"pkg_test": "package",
}
env_expander = ramble.expander.Expander(variables, None)
_ = software_environments.render_environment(
"all-basic-environment", env_expander, _get_package_manager()
)
variables = {"env_test": "environment", "pkg_test": "other-package"}
env_expander = ramble.expander.Expander(variables, None)
with pytest.raises(ramble.software_environments.RambleSoftwareEnvironmentError) as env_err:
software_environments.render_environment(
"all-basic-environment", env_expander, _get_package_manager()
)
assert "Environment all-basic-environment defined multiple times" in str(env_err)
[docs]
def test_undefined_compiler_errors(request, mutable_mock_workspace_path):
ws_name = request.node.name
workspace("create", ws_name)
assert ws_name in workspace("list")
with ramble.workspace.read(ws_name) as ws:
software_dict = ws.get_software_dict()
software_dict["packages"] = {}
software_dict["packages"]["basic"] = {"pkg_spec": "basic@1.1", "compiler": "foo_comp"}
software_dict["environments"] = {"basic": {"packages": ["basic"]}}
software_environments = ramble.software_environments.SoftwareEnvironments(ws)
assert "basic" in software_environments._environment_templates
assert "basic" in software_environments._package_templates
variables = {}
env_expander = ramble.expander.Expander(variables, None)
with pytest.raises(
ramble.software_environments.RambleSoftwareEnvironmentError,
match="Compiler foo_comp used, but not defined",
):
software_environments.render_environment("basic", env_expander, _get_package_manager())
[docs]
def test_compiler_in_environment_warns(request, mutable_mock_workspace_path, capsys):
ws_name = request.node.name
workspace("create", ws_name)
assert ws_name in workspace("list")
with ramble.workspace.read(ws_name) as ws:
software_dict = ws.get_software_dict()
software_dict["packages"] = {}
software_dict["packages"]["test_comp"] = {"pkg_spec": "comp@2.1"}
software_dict["packages"]["basic"] = {"pkg_spec": "basic@1.1", "compiler": "test_comp"}
software_dict["environments"] = {"basic": {"packages": ["basic", "test_comp"]}}
software_environments = ramble.software_environments.SoftwareEnvironments(ws)
assert "basic" in software_environments._environment_templates
assert "basic" in software_environments._package_templates
variables = {}
env_expander = ramble.expander.Expander(variables, None)
_ = software_environments.render_environment("basic", env_expander, _get_package_manager())
captured = capsys.readouterr()
assert "Environment basic contains packages and their compilers" in captured.err
assert "Package: basic, Compiler: test_comp" in captured.err