diff options
Diffstat (limited to 'tests/format/junctions.py')
-rw-r--r-- | tests/format/junctions.py | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/tests/format/junctions.py b/tests/format/junctions.py new file mode 100644 index 000000000..d97c9f702 --- /dev/null +++ b/tests/format/junctions.py @@ -0,0 +1,310 @@ +import os +import pytest +import shutil + +from buildstream import _yaml, ElementError +from buildstream._exceptions import ErrorDomain, LoadErrorReason +from tests.testutils import cli, create_repo +from tests.testutils.site import HAVE_GIT + + +DATA_DIR = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + 'junctions', +) + + +def copy_subprojects(project, datafiles, subprojects): + for subproject in subprojects: + shutil.copytree(os.path.join(str(datafiles), subproject), os.path.join(str(project), subproject)) + + +@pytest.mark.datafiles(DATA_DIR) +def test_simple_pipeline(cli, datafiles): + project = os.path.join(str(datafiles), 'foo') + copy_subprojects(project, datafiles, ['base']) + + # Check that the pipeline includes the subproject element + element_list = cli.get_pipeline(project, ['target.bst']) + assert 'base.bst:target.bst' in element_list + + +@pytest.mark.datafiles(DATA_DIR) +def test_simple_build(cli, tmpdir, datafiles): + project = os.path.join(str(datafiles), 'foo') + copy_subprojects(project, datafiles, ['base']) + + checkoutdir = os.path.join(str(tmpdir), "checkout") + + # Build, checkout + result = cli.run(project=project, args=['build', 'target.bst']) + result.assert_success() + result = cli.run(project=project, args=['checkout', 'target.bst', checkoutdir]) + result.assert_success() + + # Check that the checkout contains the expected files from both projects + assert(os.path.exists(os.path.join(checkoutdir, 'base.txt'))) + assert(os.path.exists(os.path.join(checkoutdir, 'foo.txt'))) + + +@pytest.mark.datafiles(DATA_DIR) +def test_build_of_same_junction_used_twice(cli, tmpdir, datafiles): + project = os.path.join(str(datafiles), 'inconsistent-names') + + # Check we can build a project that contains the same junction + # that is used twice, but named differently + result = cli.run(project=project, args=['build', 'target.bst']) + result.assert_success() + + +@pytest.mark.datafiles(DATA_DIR) +def test_nested_simple(cli, tmpdir, datafiles): + foo = os.path.join(str(datafiles), 'foo') + copy_subprojects(foo, datafiles, ['base']) + + project = os.path.join(str(datafiles), 'nested') + copy_subprojects(project, datafiles, ['foo']) + + checkoutdir = os.path.join(str(tmpdir), "checkout") + + # Build, checkout + result = cli.run(project=project, args=['build', 'target.bst']) + result.assert_success() + result = cli.run(project=project, args=['checkout', 'target.bst', checkoutdir]) + result.assert_success() + + # Check that the checkout contains the expected files from all subprojects + assert(os.path.exists(os.path.join(checkoutdir, 'base.txt'))) + assert(os.path.exists(os.path.join(checkoutdir, 'foo.txt'))) + + +@pytest.mark.datafiles(DATA_DIR) +def test_nested_double(cli, tmpdir, datafiles): + foo = os.path.join(str(datafiles), 'foo') + copy_subprojects(foo, datafiles, ['base']) + + bar = os.path.join(str(datafiles), 'bar') + copy_subprojects(bar, datafiles, ['base']) + + project = os.path.join(str(datafiles), 'toplevel') + copy_subprojects(project, datafiles, ['base', 'foo', 'bar']) + + checkoutdir = os.path.join(str(tmpdir), "checkout") + + # Build, checkout + result = cli.run(project=project, args=['build', 'target.bst']) + result.assert_success() + result = cli.run(project=project, args=['checkout', 'target.bst', checkoutdir]) + result.assert_success() + + # Check that the checkout contains the expected files from all subprojects + assert(os.path.exists(os.path.join(checkoutdir, 'base.txt'))) + assert(os.path.exists(os.path.join(checkoutdir, 'foo.txt'))) + assert(os.path.exists(os.path.join(checkoutdir, 'bar.txt'))) + + +@pytest.mark.datafiles(DATA_DIR) +def test_nested_conflict(cli, datafiles): + foo = os.path.join(str(datafiles), 'foo') + copy_subprojects(foo, datafiles, ['base']) + + bar = os.path.join(str(datafiles), 'bar') + copy_subprojects(bar, datafiles, ['base']) + + project = os.path.join(str(datafiles), 'conflict') + copy_subprojects(project, datafiles, ['foo', 'bar']) + + result = cli.run(project=project, args=['build', 'target.bst']) + result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.CONFLICTING_JUNCTION) + + +# Test that we error correctly when the junction element itself is missing +@pytest.mark.datafiles(DATA_DIR) +def test_missing_junction(cli, datafiles): + project = os.path.join(str(datafiles), 'invalid') + + result = cli.run(project=project, args=['build', 'missing.bst']) + result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.MISSING_FILE) + + +# Test that we error correctly when an element is not found in the subproject +@pytest.mark.datafiles(DATA_DIR) +def test_missing_subproject_element(cli, datafiles): + project = os.path.join(str(datafiles), 'invalid') + copy_subprojects(project, datafiles, ['base']) + + result = cli.run(project=project, args=['build', 'missing-element.bst']) + result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.MISSING_FILE) + + +# Test that we error correctly when a junction itself has dependencies +@pytest.mark.datafiles(DATA_DIR) +def test_invalid_with_deps(cli, datafiles): + project = os.path.join(str(datafiles), 'invalid') + copy_subprojects(project, datafiles, ['base']) + + result = cli.run(project=project, args=['build', 'junction-with-deps.bst']) + result.assert_main_error(ErrorDomain.ELEMENT, 'element-forbidden-depends') + + +# Test that we error correctly when a junction is directly depended on +@pytest.mark.datafiles(DATA_DIR) +def test_invalid_junction_dep(cli, datafiles): + project = os.path.join(str(datafiles), 'invalid') + copy_subprojects(project, datafiles, ['base']) + + result = cli.run(project=project, args=['build', 'junction-dep.bst']) + result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.INVALID_DATA) + + +@pytest.mark.datafiles(DATA_DIR) +def test_options_default(cli, tmpdir, datafiles): + project = os.path.join(str(datafiles), 'options-default') + copy_subprojects(project, datafiles, ['options-base']) + + checkoutdir = os.path.join(str(tmpdir), "checkout") + + # Build, checkout + result = cli.run(project=project, args=['build', 'target.bst']) + result.assert_success() + result = cli.run(project=project, args=['checkout', 'target.bst', checkoutdir]) + result.assert_success() + + assert(os.path.exists(os.path.join(checkoutdir, 'pony.txt'))) + assert(not os.path.exists(os.path.join(checkoutdir, 'horsy.txt'))) + + +@pytest.mark.datafiles(DATA_DIR) +def test_options(cli, tmpdir, datafiles): + project = os.path.join(str(datafiles), 'options') + copy_subprojects(project, datafiles, ['options-base']) + + checkoutdir = os.path.join(str(tmpdir), "checkout") + + # Build, checkout + result = cli.run(project=project, args=['build', 'target.bst']) + result.assert_success() + result = cli.run(project=project, args=['checkout', 'target.bst', checkoutdir]) + result.assert_success() + + assert(not os.path.exists(os.path.join(checkoutdir, 'pony.txt'))) + assert(os.path.exists(os.path.join(checkoutdir, 'horsy.txt'))) + + +@pytest.mark.datafiles(DATA_DIR) +def test_options_inherit(cli, tmpdir, datafiles): + project = os.path.join(str(datafiles), 'options-inherit') + copy_subprojects(project, datafiles, ['options-base']) + + checkoutdir = os.path.join(str(tmpdir), "checkout") + + # Build, checkout + result = cli.run(project=project, args=['build', 'target.bst']) + result.assert_success() + result = cli.run(project=project, args=['checkout', 'target.bst', checkoutdir]) + result.assert_success() + + assert(not os.path.exists(os.path.join(checkoutdir, 'pony.txt'))) + assert(os.path.exists(os.path.join(checkoutdir, 'horsy.txt'))) + + +@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available") +@pytest.mark.datafiles(DATA_DIR) +def test_git_show(cli, tmpdir, datafiles): + project = os.path.join(str(datafiles), 'foo') + checkoutdir = os.path.join(str(tmpdir), "checkout") + + # Create the repo from 'base' subdir + repo = create_repo('git', str(tmpdir)) + ref = repo.create(os.path.join(str(datafiles), 'base')) + + # Write out junction element with git source + element = { + 'kind': 'junction', + 'sources': [ + repo.source_config(ref=ref) + ] + } + _yaml.dump(element, os.path.join(project, 'base.bst')) + + # Verify that bst show does not implicitly fetch subproject + result = cli.run(project=project, args=['show', 'target.bst']) + result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.SUBPROJECT_FETCH_NEEDED) + + # Explicitly fetch subproject + result = cli.run(project=project, args=['source', 'fetch', 'base.bst']) + result.assert_success() + + # Check that bst show succeeds now and the pipeline includes the subproject element + element_list = cli.get_pipeline(project, ['target.bst']) + assert 'base.bst:target.bst' in element_list + + +@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available") +@pytest.mark.datafiles(DATA_DIR) +def test_git_build(cli, tmpdir, datafiles): + project = os.path.join(str(datafiles), 'foo') + checkoutdir = os.path.join(str(tmpdir), "checkout") + + # Create the repo from 'base' subdir + repo = create_repo('git', str(tmpdir)) + ref = repo.create(os.path.join(str(datafiles), 'base')) + + # Write out junction element with git source + element = { + 'kind': 'junction', + 'sources': [ + repo.source_config(ref=ref) + ] + } + _yaml.dump(element, os.path.join(project, 'base.bst')) + + # Build (with implicit fetch of subproject), checkout + result = cli.run(project=project, args=['build', 'target.bst']) + result.assert_success() + result = cli.run(project=project, args=['checkout', 'target.bst', checkoutdir]) + result.assert_success() + + # Check that the checkout contains the expected files from both projects + assert(os.path.exists(os.path.join(checkoutdir, 'base.txt'))) + assert(os.path.exists(os.path.join(checkoutdir, 'foo.txt'))) + + +@pytest.mark.datafiles(DATA_DIR) +def test_cross_junction_names(cli, tmpdir, datafiles): + project = os.path.join(str(datafiles), 'foo') + copy_subprojects(project, datafiles, ['base']) + + element_list = cli.get_pipeline(project, ['base.bst:target.bst']) + assert 'base.bst:target.bst' in element_list + + +@pytest.mark.datafiles(DATA_DIR) +def test_build_git_cross_junction_names(cli, tmpdir, datafiles): + project = os.path.join(str(datafiles), 'foo') + checkoutdir = os.path.join(str(tmpdir), "checkout") + + # Create the repo from 'base' subdir + repo = create_repo('git', str(tmpdir)) + ref = repo.create(os.path.join(str(datafiles), 'base')) + + # Write out junction element with git source + element = { + 'kind': 'junction', + 'sources': [ + repo.source_config(ref=ref) + ] + } + _yaml.dump(element, os.path.join(project, 'base.bst')) + + print(element) + print(cli.get_pipeline(project, ['base.bst'])) + + # Build (with implicit fetch of subproject), checkout + result = cli.run(project=project, args=['build', 'base.bst:target.bst']) + result.assert_success() + result = cli.run(project=project, args=['checkout', 'base.bst:target.bst', checkoutdir]) + result.assert_success() + + # Check that the checkout contains the expected files from both projects + assert(os.path.exists(os.path.join(checkoutdir, 'base.txt'))) |