diff --git a/lib/spack/spack/test/util/module_cmd.py b/lib/spack/spack/test/util/module_cmd.py index d348a1bf4503d9..b47b9f7fcd2341 100644 --- a/lib/spack/spack/test/util/module_cmd.py +++ b/lib/spack/spack/test/util/module_cmd.py @@ -38,6 +38,22 @@ def mock_module(*args, **kwargs): assert "test_module:test_module_2" in os.environ["LOADEDMODULES"] +@pytest.mark.not_on_windows("Module files are not supported on Windows") +def test_load_module_already_loaded(monkeypatch, working_env): + """Test that loading an already-loaded module succeeds without reloading it.""" + + os.environ["LOADEDMODULES"] = "test_module" + + def mock_module(*args, **kwargs): + if args[0] == "show": + return "" + pytest.fail("load should not be called for an already-loaded module") + + monkeypatch.setattr(spack.util.module_cmd, "module", mock_module) + + spack.util.module_cmd.load_module("test_module") + + @pytest.mark.not_on_windows("Module files are not supported on Windows") def test_load_module_failure(monkeypatch, working_env): """Test that load_module raises an exception when a module load fails.""" diff --git a/lib/spack/spack/util/module_cmd.py b/lib/spack/spack/util/module_cmd.py index 3294b1bb053916..3a3b5f97fe9433 100644 --- a/lib/spack/spack/util/module_cmd.py +++ b/lib/spack/spack/util/module_cmd.py @@ -106,6 +106,12 @@ def load_module(mod): # Store the LOADEDMODULES before trying to load the new module loaded_modules_before = os.environ.get("LOADEDMODULES", "") + # Loading a module that is already loaded is a successful no-op for + # module systems such as Lmod. In that case LOADEDMODULES is unchanged, + # so treating an unchanged value below as a failure would be incorrect. + if mod in loaded_modules_before.split(":"): + return + # Load the module now that there are no conflicts # Some module systems use stdout and some use stderr module("load", mod)