import os import pytest import shutil from tests.testutils import cli, cli_integration, create_artifact_share from tests.testutils.site import HAVE_BWRAP, IS_LINUX from buildstream._exceptions import ErrorDomain pytestmark = pytest.mark.integration DATA_DIR = os.path.join( os.path.dirname(os.path.realpath(__file__)), "project" ) @pytest.mark.datafiles(DATA_DIR) @pytest.mark.skipif(IS_LINUX and not HAVE_BWRAP, reason='Only available with bubblewrap on Linux') def test_buildtree_staged(cli_integration, tmpdir, datafiles): # We can only test the non interacitve case # The non interactive case defaults to not using buildtrees # for `bst shell --build` project = os.path.join(datafiles.dirname, datafiles.basename) element_name = 'build-shell/buildtree.bst' res = cli_integration.run(project=project, args=['build', element_name]) res.assert_success() res = cli_integration.run(project=project, args=[ 'shell', '--build', element_name, '--', 'cat', 'test' ]) res.assert_shell_error() @pytest.mark.datafiles(DATA_DIR) @pytest.mark.skipif(IS_LINUX and not HAVE_BWRAP, reason='Only available with bubblewrap on Linux') def test_buildtree_staged_forced_true(cli_integration, tmpdir, datafiles): # Test that if we ask for a build tree it is there. project = os.path.join(datafiles.dirname, datafiles.basename) element_name = 'build-shell/buildtree.bst' res = cli_integration.run(project=project, args=['build', element_name]) res.assert_success() res = cli_integration.run(project=project, args=[ 'shell', '--build', '--use-buildtree', 'always', element_name, '--', 'cat', 'test' ]) res.assert_success() assert 'Hi' in res.output @pytest.mark.datafiles(DATA_DIR) @pytest.mark.skipif(IS_LINUX and not HAVE_BWRAP, reason='Only available with bubblewrap on Linux') def test_buildtree_staged_if_available(cli_integration, tmpdir, datafiles): # Test that a build tree can be correctly detected. project = os.path.join(datafiles.dirname, datafiles.basename) element_name = 'build-shell/buildtree.bst' res = cli_integration.run(project=project, args=['build', element_name]) res.assert_success() res = cli_integration.run(project=project, args=[ 'shell', '--build', '--use-buildtree', 'try', element_name, '--', 'cat', 'test' ]) res.assert_success() assert 'Hi' in res.output @pytest.mark.datafiles(DATA_DIR) @pytest.mark.skipif(IS_LINUX and not HAVE_BWRAP, reason='Only available with bubblewrap on Linux') def test_buildtree_staged_forced_false(cli_integration, tmpdir, datafiles): # Test that if we ask not to have a build tree it is not there project = os.path.join(datafiles.dirname, datafiles.basename) element_name = 'build-shell/buildtree.bst' res = cli_integration.run(project=project, args=['build', element_name]) res.assert_success() res = cli_integration.run(project=project, args=[ 'shell', '--build', '--use-buildtree', 'never', element_name, '--', 'cat', 'test' ]) res.assert_shell_error() assert 'Hi' not in res.output @pytest.mark.datafiles(DATA_DIR) @pytest.mark.skipif(IS_LINUX and not HAVE_BWRAP, reason='Only available with bubblewrap on Linux') def test_buildtree_from_failure(cli_integration, tmpdir, datafiles): # Test that we can use a build tree after a failure project = os.path.join(datafiles.dirname, datafiles.basename) element_name = 'build-shell/buildtree-fail.bst' res = cli_integration.run(project=project, args=['build', element_name]) res.assert_main_error(ErrorDomain.STREAM, None) # Assert that file has expected contents res = cli_integration.run(project=project, args=[ 'shell', '--build', element_name, '--use-buildtree', 'always', '--', 'cat', 'test' ]) res.assert_success() assert "Warning: using a buildtree from a failed build" in res.output assert 'Hi' in res.output # Check that build shells work when pulled from a remote cache # This is to roughly simulate remote execution @pytest.mark.datafiles(DATA_DIR) @pytest.mark.skipif(IS_LINUX and not HAVE_BWRAP, reason='Only available with bubblewrap on Linux') def test_buildtree_pulled(cli, tmpdir, datafiles): project = os.path.join(datafiles.dirname, datafiles.basename) element_name = 'build-shell/buildtree.bst' with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare')) as share: # Build the element to push it to cache cli.configure({ 'artifacts': {'url': share.repo, 'push': True} }) result = cli.run(project=project, args=['build', element_name]) result.assert_success() assert cli.get_element_state(project, element_name) == 'cached' # Discard the cache cli.configure({ 'artifacts': {'url': share.repo, 'push': True}, 'artifactdir': os.path.join(cli.directory, 'artifacts2') }) assert cli.get_element_state(project, element_name) != 'cached' # Pull from cache, ensuring cli options is set to pull the buildtree result = cli.run(project=project, args=['--pull-buildtrees', 'artifact', 'pull', '--deps', 'all', element_name]) result.assert_success() # Check it's using the cached build tree res = cli.run(project=project, args=[ 'shell', '--build', element_name, '--use-buildtree', 'always', '--', 'cat', 'test' ]) res.assert_success() # This test checks for correct behaviour if a buildtree is not present. @pytest.mark.datafiles(DATA_DIR) @pytest.mark.skipif(IS_LINUX and not HAVE_BWRAP, reason='Only available with bubblewrap on Linux') def test_buildtree_options(cli, tmpdir, datafiles): project = os.path.join(datafiles.dirname, datafiles.basename) element_name = 'build-shell/buildtree.bst' with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare')) as share: # Build the element to push it to cache cli.configure({ 'artifacts': {'url': share.repo, 'push': True} }) result = cli.run(project=project, args=['build', element_name]) result.assert_success() assert cli.get_element_state(project, element_name) == 'cached' # Discard the cache cli.configure({ 'artifacts': {'url': share.repo, 'push': True}, 'artifactdir': os.path.join(cli.directory, 'artifacts2') }) assert cli.get_element_state(project, element_name) != 'cached' # Pull from cache, but do not include buildtrees. result = cli.run(project=project, args=['artifact', 'pull', '--deps', 'all', element_name]) result.assert_success() # The above is the simplest way I know to create a local cache without any buildtrees. # Check it's not using the cached build tree res = cli.run(project=project, args=[ 'shell', '--build', element_name, '--use-buildtree', 'never', '--', 'cat', 'test' ]) res.assert_shell_error() assert 'Hi' not in res.output # Check it's not correctly handling the lack of buildtree res = cli.run(project=project, args=[ 'shell', '--build', element_name, '--use-buildtree', 'try', '--', 'cat', 'test' ]) res.assert_shell_error() assert 'Hi' not in res.output # Check it's not using the cached build tree, default is to ask, and fall back to not # for non interactive behavior res = cli.run(project=project, args=[ 'shell', '--build', element_name, '--', 'cat', 'test' ]) res.assert_shell_error() assert 'Hi' not in res.output # Check it's using the cached build tree res = cli.run(project=project, args=[ 'shell', '--build', element_name, '--use-buildtree', 'always', '--', 'cat', 'test' ]) res.assert_main_error(ErrorDomain.PROG_NOT_FOUND, None) assert 'Hi' not in res.output