summaryrefslogblamecommitdiff
path: root/lib/spack/spack/test/bootstrap.py
blob: dcc8bf6495e6bde1404a207314fb62520d7a4ccd (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                                                                         


                                                                         
 


                      

                             
                      
                        
                  
                      

 

                                                                   
                                                           


                 
                                
                                                                             
                                                                                                 
                                         
                                          
                                                  
                                                                               
                                                              

                                                                                
                                                                               








                                                                                                 
                                                                                  
                                                              
                                                                                

                                                                                    

 






                                                                                 
                                                                       


                                                                            
                                                               

                                                  

                                                                                


                                                   








                                                               

                                                                          
                                                    

                          
                                                 




                                                                 
                                               

                                           
                                                                                  
                                           

 
                                               
                                                                                       
                                                                      


                                                 
                                                                                                 
                                                                                            

 
                                




                                                                            

 
                                

                                                                  
                                                               
 

                                                               
                                                          



                                                                       

 

                                        






                                                                               

                                        
                                                                
                                              




                                                                    

 
                                
                                                                   
                              
                                                                             
 
                                                                
                                                          

                                                                    

 
                                
                                                                       

                                                                        
                                          
                                       

                     




                 



                        
     

                                                     
                                                                           


                                                              
                                                          



                                                       
                                     
                                                          
                                                 
                                                              

                                                     

 
                                                           
                                    
                                                                          
  

                                 
                            
                                                    

                        
                               
                                 
                                                                                         
     
                                                       
 
                                                           
                                      

 
                                

                                                                          
                                                                   



                                                                        
                                                             


                                                                       
                                                                             
                                   
                                                             
# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

import pytest

import spack.bootstrap
import spack.bootstrap.config
import spack.bootstrap.core
import spack.compilers
import spack.environment
import spack.store
import spack.util.path


@pytest.fixture
def active_mock_environment(mutable_config, mutable_mock_env_path):
    with spack.environment.create("bootstrap-test") as env:
        yield env


@pytest.mark.regression("22294")
def test_store_is_restored_correctly_after_bootstrap(mutable_config, tmpdir):
    """Tests that the store is correctly swapped during bootstrapping, and restored afterward."""
    user_path = str(tmpdir.join("store"))
    with spack.store.use_store(user_path):
        assert spack.store.STORE.root == user_path
        assert spack.config.CONFIG.get("config:install_tree:root") == user_path
        with spack.bootstrap.ensure_bootstrap_configuration():
            assert spack.store.STORE.root == spack.bootstrap.config.store_path()
        assert spack.store.STORE.root == user_path
        assert spack.config.CONFIG.get("config:install_tree:root") == user_path


@pytest.mark.regression("38963")
def test_store_padding_length_is_zero_during_bootstrapping(mutable_config, tmpdir):
    """Tests that, even though padded length is set in user config, the bootstrap store maintains
    a padded length of zero.
    """
    user_path = str(tmpdir.join("store"))
    with spack.store.use_store(user_path, extra_data={"padded_length": 512}):
        assert spack.config.CONFIG.get("config:install_tree:padded_length") == 512
        with spack.bootstrap.ensure_bootstrap_configuration():
            assert spack.store.STORE.root == spack.bootstrap.config.store_path()
            assert spack.config.CONFIG.get("config:install_tree:padded_length") == 0
        assert spack.config.CONFIG.get("config:install_tree:padded_length") == 512


@pytest.mark.regression("38963")
def test_install_tree_customization_is_respected(mutable_config, tmp_path):
    """Tests that a custom user store is respected when we exit the bootstrapping
    environment.
    """
    spack.store.reinitialize()
    store_dir = tmp_path / "store"
    spack.config.CONFIG.set("config:install_tree:root", str(store_dir))
    with spack.bootstrap.ensure_bootstrap_configuration():
        assert spack.store.STORE.root == spack.bootstrap.config.store_path()
        assert (
            spack.config.CONFIG.get("config:install_tree:root")
            == spack.bootstrap.config.store_path()
        )
        assert spack.config.CONFIG.get("config:install_tree:padded_length") == 0
    assert spack.config.CONFIG.get("config:install_tree:root") == str(store_dir)
    assert spack.store.STORE.root == str(store_dir)


@pytest.mark.parametrize(
    "config_value,expected",
    [
        # Absolute path without expansion
        ("/opt/spack/bootstrap", "/opt/spack/bootstrap/store"),
        # Path with placeholder
        ("$spack/opt/bootstrap", "$spack/opt/bootstrap/store"),
    ],
)
def test_store_path_customization(config_value, expected, mutable_config):
    # Set the current configuration to a specific value
    spack.config.set("bootstrap:root", config_value)

    # Check the store path
    current = spack.bootstrap.config.store_path()
    assert current == spack.util.path.canonicalize_path(expected)


def test_raising_exception_if_bootstrap_disabled(mutable_config):
    # Disable bootstrapping in config.yaml
    spack.config.set("bootstrap:enable", False)

    # Check the correct exception is raised
    with pytest.raises(RuntimeError, match="bootstrapping is currently disabled"):
        spack.bootstrap.config.store_path()


def test_raising_exception_module_importable():
    with pytest.raises(ImportError, match='cannot bootstrap the "asdf" Python module'):
        spack.bootstrap.core.ensure_module_importable_or_raise("asdf")


def test_raising_exception_executables_in_path():
    with pytest.raises(RuntimeError, match="cannot bootstrap any of the asdf, fdsa executables"):
        spack.bootstrap.core.ensure_executables_in_path_or_raise(["asdf", "fdsa"], "python")


@pytest.mark.regression("25603")
def test_bootstrap_deactivates_environments(active_mock_environment):
    assert spack.environment.active_environment() == active_mock_environment
    with spack.bootstrap.ensure_bootstrap_configuration():
        assert spack.environment.active_environment() is None
    assert spack.environment.active_environment() == active_mock_environment


@pytest.mark.regression("25805")
def test_bootstrap_disables_modulefile_generation(mutable_config):
    # Be sure to enable both lmod and tcl in modules.yaml
    spack.config.set("modules:default:enable", ["tcl", "lmod"])

    assert "tcl" in spack.config.get("modules:default:enable")
    assert "lmod" in spack.config.get("modules:default:enable")
    with spack.bootstrap.ensure_bootstrap_configuration():
        assert "tcl" not in spack.config.get("modules:default:enable")
        assert "lmod" not in spack.config.get("modules:default:enable")
    assert "tcl" in spack.config.get("modules:default:enable")
    assert "lmod" in spack.config.get("modules:default:enable")


@pytest.mark.regression("25992")
@pytest.mark.requires_executables("gcc")
def test_bootstrap_search_for_compilers_with_no_environment(no_compilers_yaml):
    assert not spack.compilers.all_compiler_specs(init_config=False)
    with spack.bootstrap.ensure_bootstrap_configuration():
        assert spack.compilers.all_compiler_specs(init_config=False)
    assert not spack.compilers.all_compiler_specs(init_config=False)


@pytest.mark.regression("25992")
@pytest.mark.requires_executables("gcc")
def test_bootstrap_search_for_compilers_with_environment_active(
    no_compilers_yaml, active_mock_environment
):
    assert not spack.compilers.all_compiler_specs(init_config=False)
    with spack.bootstrap.ensure_bootstrap_configuration():
        assert spack.compilers.all_compiler_specs(init_config=False)
    assert not spack.compilers.all_compiler_specs(init_config=False)


@pytest.mark.regression("26189")
def test_config_yaml_is_preserved_during_bootstrap(mutable_config):
    expected_dir = "/tmp/test"
    spack.config.set("config:test_stage", expected_dir, scope="command_line")

    assert spack.config.get("config:test_stage") == expected_dir
    with spack.bootstrap.ensure_bootstrap_configuration():
        assert spack.config.get("config:test_stage") == expected_dir
    assert spack.config.get("config:test_stage") == expected_dir


@pytest.mark.regression("26548")
def test_bootstrap_custom_store_in_environment(mutable_config, tmpdir):
    # Test that the custom store in an environment is taken into account
    # during bootstrapping
    spack_yaml = tmpdir.join("spack.yaml")
    install_root = tmpdir.join("store")
    spack_yaml.write(
        """
spack:
  specs:
  - libelf
  config:
    install_tree:
      root: {0}
""".format(
            install_root
        )
    )
    with spack.environment.Environment(str(tmpdir)):
        assert spack.environment.active_environment()
        assert spack.config.get("config:install_tree:root") == install_root
        # Don't trigger evaluation here
        with spack.bootstrap.ensure_bootstrap_configuration():
            pass
        assert str(spack.store.STORE.root) == install_root


def test_nested_use_of_context_manager(mutable_config):
    """Test nested use of the context manager"""
    user_config = spack.config.CONFIG
    with spack.bootstrap.ensure_bootstrap_configuration():
        assert spack.config.CONFIG != user_config
        with spack.bootstrap.ensure_bootstrap_configuration():
            assert spack.config.CONFIG != user_config
    assert spack.config.CONFIG == user_config


@pytest.mark.parametrize("expected_missing", [False, True])
def test_status_function_find_files(
    mutable_config, mock_executable, tmpdir, monkeypatch, expected_missing
):
    import spack.bootstrap.status

    if not expected_missing:
        mock_executable("foo", "echo Hello WWorld!")

    monkeypatch.setattr(
        spack.bootstrap.status,
        "_optional_requirements",
        lambda: [spack.bootstrap.status._required_system_executable("foo", "NOT FOUND")],
    )
    monkeypatch.setenv("PATH", str(tmpdir.join("bin")))

    _, missing = spack.bootstrap.status_message("optional")
    assert missing is expected_missing


@pytest.mark.regression("31042")
def test_source_is_disabled(mutable_config):
    # Get the configuration dictionary of the current bootstrapping source
    conf = next(iter(spack.bootstrap.core.bootstrapping_sources()))

    # The source is not explicitly enabled or disabled, so the following
    # call should raise to skip using it for bootstrapping
    with pytest.raises(ValueError):
        spack.bootstrap.core.source_is_enabled_or_raise(conf)

    # Try to explicitly disable the source and verify that the behavior
    # is the same as above
    spack.config.add("bootstrap:trusted:{0}:{1}".format(conf["name"], False))
    with pytest.raises(ValueError):
        spack.bootstrap.core.source_is_enabled_or_raise(conf)