summaryrefslogtreecommitdiff
path: root/tests/loader
diff options
context:
space:
mode:
authorTristan Van Berkom <tristan.vanberkom@codethink.co.uk>2016-11-28 17:32:57 +0000
committerTristan Van Berkom <tristan.vanberkom@codethink.co.uk>2016-11-28 17:37:31 +0000
commit2fbcb9681f6720b3b141c1003d865a9080daa558 (patch)
tree8283026234ade0f47bc47b1eb3b057205487b2b0 /tests/loader
parent0cf884dbabcc039c0771456c55bcf086110ddb54 (diff)
downloadbuildstream-2fbcb9681f6720b3b141c1003d865a9080daa558.tar.gz
Added a ton of tests to test the Loader
o Tests for basic file loading o Tests for include directive functionality o Tests for resolution of arch conditionals o Tests for dependency resolution and detecting circular dependencies o Tests for variants, ensures that we have the correct variant conflict errors and that the correct variants are chosen in the correct cases o Tests for stacks, test that stacks with embedded elements unwrap properly into the concrete dependency tree, test for internal stack circular dependencies, test that arch conditionals and variant conditionals work inside stacks including with embedded elements Lots of tests
Diffstat (limited to 'tests/loader')
-rw-r--r--tests/loader/__init__.py0
-rw-r--r--tests/loader/arches.py169
-rw-r--r--tests/loader/arches/elements/simple-conditional.bst11
-rw-r--r--tests/loader/arches/elements/variant-arch-conditional.bst25
-rw-r--r--tests/loader/basics.py69
-rw-r--r--tests/loader/basics/onefile/elements/badfile.bst5
-rw-r--r--tests/loader/basics/onefile/elements/badreference.bst3
-rw-r--r--tests/loader/basics/onefile/elements/onefile.bst2
-rw-r--r--tests/loader/dependencies.py92
-rw-r--r--tests/loader/dependencies/elements/circular-firstdep.bst4
-rw-r--r--tests/loader/dependencies/elements/circular-seconddep.bst4
-rw-r--r--tests/loader/dependencies/elements/circulartarget.bst4
-rw-r--r--tests/loader/dependencies/elements/firstdep.bst2
-rw-r--r--tests/loader/dependencies/elements/invaliddep.bst4
-rw-r--r--tests/loader/dependencies/elements/shareddep.bst4
-rw-r--r--tests/loader/dependencies/elements/shareddeptarget.bst5
-rw-r--r--tests/loader/dependencies/elements/target.bst4
-rw-r--r--tests/loader/includes.py65
-rw-r--r--tests/loader/includes/elements/invalidinclude.bst4
-rw-r--r--tests/loader/includes/elements/missing.bst3
-rw-r--r--tests/loader/includes/elements/overwriting.bst3
-rw-r--r--tests/loader/includes/elements/target.bst3
-rw-r--r--tests/loader/includes/include/basicinclude.bst5
-rw-r--r--tests/loader/includes/include/invalidtype.bst4
-rw-r--r--tests/loader/includes/include/overwritekind.bst2
-rw-r--r--tests/loader/stacks.py421
-rw-r--r--tests/loader/stacks/elements/archstack.bst15
-rw-r--r--tests/loader/stacks/elements/circulardepstack.bst15
-rw-r--r--tests/loader/stacks/elements/element.bst4
-rw-r--r--tests/loader/stacks/elements/includingstack.bst10
-rw-r--r--tests/loader/stacks/elements/nestedarchstack.bst14
-rw-r--r--tests/loader/stacks/elements/nestedvariantstack.bst33
-rw-r--r--tests/loader/stacks/elements/stack.bst7
-rw-r--r--tests/loader/stacks/elements/stackdepends.bst9
-rw-r--r--tests/loader/stacks/elements/stackinstack.bst9
-rw-r--r--tests/loader/stacks/elements/variantstack.bst14
-rw-r--r--tests/loader/stacks/include/horse.bst2
-rw-r--r--tests/loader/stacks/include/pony.bst2
-rw-r--r--tests/loader/variants.py242
-rw-r--r--tests/loader/variants/elements/disagreement-one.bst6
-rw-r--r--tests/loader/variants/elements/disagreement-two.bst8
-rw-r--r--tests/loader/variants/elements/disagreement.bst9
-rw-r--r--tests/loader/variants/elements/indirect-dependency-variants.bst17
-rw-r--r--tests/loader/variants/elements/only-one-variant.bst8
-rw-r--r--tests/loader/variants/elements/simple-dependency-variants.bst13
-rw-r--r--tests/loader/variants/elements/simple-variant-compositing.bst12
-rw-r--r--tests/loader/variants/elements/simply-blue.bst4
-rw-r--r--tests/loader/variants/elements/simply-pink.bst4
-rw-r--r--tests/loader/variants/elements/tricky-first.bst14
-rw-r--r--tests/loader/variants/elements/tricky-second.bst11
-rw-r--r--tests/loader/variants/elements/tricky.bst15
-rw-r--r--tests/loader/variants/elements/unnamed-variant.bst5
-rw-r--r--tests/loader/variants/elements/variant-bad-name.bst9
-rw-r--r--tests/loader/variants/elements/variants-not-list.bst3
54 files changed, 1431 insertions, 0 deletions
diff --git a/tests/loader/__init__.py b/tests/loader/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/loader/__init__.py
diff --git a/tests/loader/arches.py b/tests/loader/arches.py
new file mode 100644
index 000000000..55415131e
--- /dev/null
+++ b/tests/loader/arches.py
@@ -0,0 +1,169 @@
+import os
+import pytest
+
+from buildstream import LoadError, LoadErrorReason
+from buildstream._loader import Loader
+from buildstream._metaelement import MetaElement
+
+DATA_DIR = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ 'arches',
+)
+
+##############################################################
+# Test Simple Arch Conditionals #
+##############################################################
+@pytest.mark.datafiles(DATA_DIR)
+def test_simple_conditional_nomatch(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/simple-conditional.bst', None, 'arm')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ # Did not provide any arch specific data for 'arm', number remains 5
+ assert(number == 5)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_simple_conditional_x86_64(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/simple-conditional.bst', None, 'x86_64')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ # x86_64 arch overrides the number to 6
+ assert(number == 6)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_simple_conditional_x86_32(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/simple-conditional.bst', None, 'x86_32')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ # x86_32 arch overrides the number to 7
+ assert(number == 7)
+
+##############################################################
+# Test Arch Conditionals inside Variants #
+##############################################################
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_arch_default(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variant-arch-conditional.bst', None, 'arm')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ # The default "pink" variant sets number to 6
+ assert(number == 6)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_arch_default_x86_64(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variant-arch-conditional.bst', None, 'x86_64')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ assert(number == 7)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_arch_default_x86_32(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variant-arch-conditional.bst', None, 'x86_32')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ assert(number == 8)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_arch_pink_pony(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variant-arch-conditional.bst', 'pink', 'arm')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ # The default "pink" variant sets number to 6
+ assert(number == 6)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_arch_pink_pony_x86_64(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variant-arch-conditional.bst', 'pink', 'x86_64')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ assert(number == 7)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_arch_pink_pony_x86_32(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variant-arch-conditional.bst', 'pink', 'x86_32')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ assert(number == 8)
+
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_arch_blue_pony(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variant-arch-conditional.bst', 'blue', 'arm')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ # The "blue" variant sets number to 4
+ assert(number == 4)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_arch_blue_pony_x86_64(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variant-arch-conditional.bst', 'blue', 'x86_64')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ assert(number == 3)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_arch_blue_pony_x86_32(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variant-arch-conditional.bst', 'blue', 'x86_32')
+
+ element = loader.load()
+ assert(isinstance(element, MetaElement))
+ number = element.config.get('number')
+
+ assert(number == 2)
diff --git a/tests/loader/arches/elements/simple-conditional.bst b/tests/loader/arches/elements/simple-conditional.bst
new file mode 100644
index 000000000..7d1c1e5d9
--- /dev/null
+++ b/tests/loader/arches/elements/simple-conditional.bst
@@ -0,0 +1,11 @@
+kind: pony
+description: An element with an arch conditional
+config:
+ number: 5
+arches:
+ x86_64:
+ config:
+ number: 6
+ x86_32:
+ config:
+ number: 7
diff --git a/tests/loader/arches/elements/variant-arch-conditional.bst b/tests/loader/arches/elements/variant-arch-conditional.bst
new file mode 100644
index 000000000..1171911d7
--- /dev/null
+++ b/tests/loader/arches/elements/variant-arch-conditional.bst
@@ -0,0 +1,25 @@
+kind: pony
+description: Test out arch conditionals nested inside variant declarations
+config:
+ number: 5
+variants:
+- variant: pink
+ config:
+ number: 6
+ arches:
+ x86_64:
+ config:
+ number: 7
+ x86_32:
+ config:
+ number: 8
+- variant: blue
+ config:
+ number: 4
+ arches:
+ x86_64:
+ config:
+ number: 3
+ x86_32:
+ config:
+ number: 2
diff --git a/tests/loader/basics.py b/tests/loader/basics.py
new file mode 100644
index 000000000..13824047b
--- /dev/null
+++ b/tests/loader/basics.py
@@ -0,0 +1,69 @@
+import os
+import pytest
+
+from buildstream import LoadError, LoadErrorReason
+from buildstream._loader import Loader
+from buildstream._metaelement import MetaElement
+
+DATA_DIR = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ 'basics',
+)
+
+##############################################################
+# Basics: Test behavior loading the simplest of projects #
+##############################################################
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'onefile'))
+def test_one_file(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/onefile.bst', None, None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'onefile'))
+def test_missing_file(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/missing.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.MISSING_FILE)
+
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'onefile'))
+def test_invalid_reference(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/badreference.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.INVALID_YAML)
+
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'onefile'))
+def test_invalid_yaml(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/badfile.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.INVALID_YAML)
+
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'onefile'))
+def test_fail_fullpath_target(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ fullpath = os.path.join(basedir, 'elements', 'onefile.bst')
+
+ with pytest.raises(LoadError) as exc:
+ loader = Loader(basedir, fullpath, None, None)
+
+ assert (exc.value.reason == LoadErrorReason.INVALID_DATA)
diff --git a/tests/loader/basics/onefile/elements/badfile.bst b/tests/loader/basics/onefile/elements/badfile.bst
new file mode 100644
index 000000000..df68dbf2a
--- /dev/null
+++ b/tests/loader/basics/onefile/elements/badfile.bst
@@ -0,0 +1,5 @@
+# This is just invalid YAML
+- |
+ this is malformed yaml.
+
+)
diff --git a/tests/loader/basics/onefile/elements/badreference.bst b/tests/loader/basics/onefile/elements/badreference.bst
new file mode 100644
index 000000000..9d320b2bf
--- /dev/null
+++ b/tests/loader/basics/onefile/elements/badreference.bst
@@ -0,0 +1,3 @@
+# This bad YAML file makes a reference to an undefined entity
+name: pony
+pony: *pony
diff --git a/tests/loader/basics/onefile/elements/onefile.bst b/tests/loader/basics/onefile/elements/onefile.bst
new file mode 100644
index 000000000..ae4950585
--- /dev/null
+++ b/tests/loader/basics/onefile/elements/onefile.bst
@@ -0,0 +1,2 @@
+kind: pony
+description: This is the pony
diff --git a/tests/loader/dependencies.py b/tests/loader/dependencies.py
new file mode 100644
index 000000000..77748249f
--- /dev/null
+++ b/tests/loader/dependencies.py
@@ -0,0 +1,92 @@
+import os
+import pytest
+
+from buildstream import LoadError, LoadErrorReason
+from buildstream._loader import Loader
+from buildstream._metaelement import MetaElement
+
+DATA_DIR = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ 'dependencies',
+)
+
+##############################################################
+# Basics: Test behavior loading projects with dependencies #
+##############################################################
+@pytest.mark.datafiles(DATA_DIR)
+def test_two_files(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/target.bst', None, None)
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ assert(len(element.dependencies) == 1)
+ firstdep = element.dependencies[0]
+ assert(isinstance(firstdep, MetaElement))
+ assert(firstdep.kind == 'thefirstdep')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_shared_dependency(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/shareddeptarget.bst', None, None)
+ element = loader.load()
+
+ # Toplevel is 'pony' with 2 dependencies
+ #
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+ assert(len(element.dependencies) == 2)
+
+ # The first specified dependency is 'thefirstdep'
+ #
+ firstdep = element.dependencies[0]
+ assert(isinstance(firstdep, MetaElement))
+ assert(firstdep.kind == 'thefirstdep')
+ assert(len(firstdep.dependencies) == 0)
+
+ # The second specified dependency is 'shareddep'
+ #
+ shareddep = element.dependencies[1]
+ assert(isinstance(shareddep, MetaElement))
+ assert(shareddep.kind == 'shareddep')
+ assert(len(shareddep.dependencies) == 1)
+
+ # The element which shareddep depends on is
+ # the same element in memory as firstdep
+ #
+ shareddepdep = shareddep.dependencies[0]
+ assert(isinstance(shareddepdep, MetaElement))
+
+ # Assert they are in fact the same LoadElement
+ #
+ # Note we must use 'is' to test that both variables
+ # refer to the same object in memory, not a regular
+ # equality test with '==' which is one of those operator
+ # overridable thingies.
+ #
+ assert(shareddepdep is firstdep)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_invalid_dependency_declaration(datafiles):
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/invaliddep.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.INVALID_DATA)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_circular_dependency(datafiles):
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/circulartarget.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.CIRCULAR_DEPENDENCY)
diff --git a/tests/loader/dependencies/elements/circular-firstdep.bst b/tests/loader/dependencies/elements/circular-firstdep.bst
new file mode 100644
index 000000000..92f6993a2
--- /dev/null
+++ b/tests/loader/dependencies/elements/circular-firstdep.bst
@@ -0,0 +1,4 @@
+kind: pony
+description: Depend on another dep which depends on the target
+depends:
+- elements/circular-seconddep.bst
diff --git a/tests/loader/dependencies/elements/circular-seconddep.bst b/tests/loader/dependencies/elements/circular-seconddep.bst
new file mode 100644
index 000000000..12a67ba75
--- /dev/null
+++ b/tests/loader/dependencies/elements/circular-seconddep.bst
@@ -0,0 +1,4 @@
+kind: pony
+description: Depend on the target, creating a circular dependency
+depends:
+- elements/circulartarget.bst
diff --git a/tests/loader/dependencies/elements/circulartarget.bst b/tests/loader/dependencies/elements/circulartarget.bst
new file mode 100644
index 000000000..14db24682
--- /dev/null
+++ b/tests/loader/dependencies/elements/circulartarget.bst
@@ -0,0 +1,4 @@
+kind: pony
+description: This is a main target which introduces a circular dependency
+depends:
+- elements/circular-firstdep.bst
diff --git a/tests/loader/dependencies/elements/firstdep.bst b/tests/loader/dependencies/elements/firstdep.bst
new file mode 100644
index 000000000..9b6a57824
--- /dev/null
+++ b/tests/loader/dependencies/elements/firstdep.bst
@@ -0,0 +1,2 @@
+kind: thefirstdep
+description: This is the first dependency
diff --git a/tests/loader/dependencies/elements/invaliddep.bst b/tests/loader/dependencies/elements/invaliddep.bst
new file mode 100644
index 000000000..65c43c60a
--- /dev/null
+++ b/tests/loader/dependencies/elements/invaliddep.bst
@@ -0,0 +1,4 @@
+kind: pony
+description: This is an invalid dependency
+depends:
+ more: it should be a list, not a dict
diff --git a/tests/loader/dependencies/elements/shareddep.bst b/tests/loader/dependencies/elements/shareddep.bst
new file mode 100644
index 000000000..cb98171f6
--- /dev/null
+++ b/tests/loader/dependencies/elements/shareddep.bst
@@ -0,0 +1,4 @@
+kind: shareddep
+description: This is the first dependency
+depends:
+- elements/firstdep.bst
diff --git a/tests/loader/dependencies/elements/shareddeptarget.bst b/tests/loader/dependencies/elements/shareddeptarget.bst
new file mode 100644
index 000000000..03982d69f
--- /dev/null
+++ b/tests/loader/dependencies/elements/shareddeptarget.bst
@@ -0,0 +1,5 @@
+kind: pony
+description: This is the main target
+depends:
+- elements/firstdep.bst
+- elements/shareddep.bst
diff --git a/tests/loader/dependencies/elements/target.bst b/tests/loader/dependencies/elements/target.bst
new file mode 100644
index 000000000..05c767956
--- /dev/null
+++ b/tests/loader/dependencies/elements/target.bst
@@ -0,0 +1,4 @@
+kind: pony
+description: This is the main target
+depends:
+- elements/firstdep.bst
diff --git a/tests/loader/includes.py b/tests/loader/includes.py
new file mode 100644
index 000000000..60b20d557
--- /dev/null
+++ b/tests/loader/includes.py
@@ -0,0 +1,65 @@
+import os
+import pytest
+
+from buildstream import LoadError, LoadErrorReason
+from buildstream._loader import Loader
+from buildstream._metaelement import MetaElement
+
+DATA_DIR = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ 'includes',
+)
+
+##############################################################
+# Test Basic Include Functionality #
+##############################################################
+@pytest.mark.datafiles(DATA_DIR)
+def test_basic_include(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/target.bst', None, None)
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ # Assert that the stuff from the include got into the element data
+ assert(element.config.get('pony') == 'Someone rides their pony')
+
+ thelist = element.config.get('list', None)
+ assert(isinstance(thelist, list))
+ assert(thelist[0] == 'Element 1')
+ assert(thelist[1] == 'Element 2')
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_invalid_type_include(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/invalidinclude.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.ILLEGAL_COMPOSITE)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_overwrite_kind_include(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/overwriting.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.ILLEGAL_COMPOSITE)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_missing_include(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/missing.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.MISSING_FILE)
diff --git a/tests/loader/includes/elements/invalidinclude.bst b/tests/loader/includes/elements/invalidinclude.bst
new file mode 100644
index 000000000..ea1cad06f
--- /dev/null
+++ b/tests/loader/includes/elements/invalidinclude.bst
@@ -0,0 +1,4 @@
+kind: pony
+description: This includes a file which tries to override a regular attribute with a dict
+include: include/invalidtype.bst
+somekey: pony
diff --git a/tests/loader/includes/elements/missing.bst b/tests/loader/includes/elements/missing.bst
new file mode 100644
index 000000000..aaaaf1712
--- /dev/null
+++ b/tests/loader/includes/elements/missing.bst
@@ -0,0 +1,3 @@
+kind: pony
+description: This is a missing include file that does not exist
+include: include/missinginclude.bst
diff --git a/tests/loader/includes/elements/overwriting.bst b/tests/loader/includes/elements/overwriting.bst
new file mode 100644
index 000000000..0f33473d4
--- /dev/null
+++ b/tests/loader/includes/elements/overwriting.bst
@@ -0,0 +1,3 @@
+kind: pony
+description: This includes a file which tries to override the 'kind', overwriting from an include is not allowed
+include: include/overwritekind.bst
diff --git a/tests/loader/includes/elements/target.bst b/tests/loader/includes/elements/target.bst
new file mode 100644
index 000000000..740af38c0
--- /dev/null
+++ b/tests/loader/includes/elements/target.bst
@@ -0,0 +1,3 @@
+kind: pony
+description: This is the main target, which includes another file
+include: include/basicinclude.bst
diff --git a/tests/loader/includes/include/basicinclude.bst b/tests/loader/includes/include/basicinclude.bst
new file mode 100644
index 000000000..a7e85e8eb
--- /dev/null
+++ b/tests/loader/includes/include/basicinclude.bst
@@ -0,0 +1,5 @@
+config:
+ pony: "Someone rides their pony"
+ list:
+ - "Element 1"
+ - "Element 2"
diff --git a/tests/loader/includes/include/invalidtype.bst b/tests/loader/includes/include/invalidtype.bst
new file mode 100644
index 000000000..f561c4705
--- /dev/null
+++ b/tests/loader/includes/include/invalidtype.bst
@@ -0,0 +1,4 @@
+pony: "Someone rides their pony"
+somekey:
+ this: "pony"
+ that: "foo"
diff --git a/tests/loader/includes/include/overwritekind.bst b/tests/loader/includes/include/overwritekind.bst
new file mode 100644
index 000000000..ee8df0ca1
--- /dev/null
+++ b/tests/loader/includes/include/overwritekind.bst
@@ -0,0 +1,2 @@
+# You cannot overwrite members specified in the including element
+kind: horse
diff --git a/tests/loader/stacks.py b/tests/loader/stacks.py
new file mode 100644
index 000000000..f71b78800
--- /dev/null
+++ b/tests/loader/stacks.py
@@ -0,0 +1,421 @@
+import os
+import pytest
+
+from buildstream import LoadError, LoadErrorReason
+from buildstream._loader import Loader
+from buildstream._metaelement import MetaElement
+
+DATA_DIR = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ 'stacks',
+)
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_basic(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ filename = os.path.join('elements', 'stack.bst')
+ loader = Loader(basedir, filename, None, 'x86_64')
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+
+ # Assert that the stuff from the include got into the element data,
+ # first check that we depend on both elements
+ assert(len(element.dependencies) == 2)
+
+ pony = element.dependencies[0]
+ assert(isinstance(pony, MetaElement))
+ assert(pony.kind == 'pony')
+
+ horse = element.dependencies[1]
+ assert(isinstance(horse, MetaElement))
+ assert(horse.kind == 'horsy')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_dependencies(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ filename = os.path.join('elements', 'stackdepends.bst')
+ loader = Loader(basedir, filename, None, 'x86_64')
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+
+ # Assert that the stuff from the include got into the element data,
+ # first check that we depend on both elements
+ assert(len(element.dependencies) == 3)
+
+ leaf = element.dependencies[0]
+ assert(isinstance(leaf, MetaElement))
+ assert(leaf.kind == 'element')
+
+ pony = element.dependencies[1]
+ assert(isinstance(pony, MetaElement))
+ assert(pony.kind == 'pony')
+ assert(len(pony.dependencies) == 1)
+
+ # By virtue of being embedded in a stack which
+ # depends on the leaf 'element', this element
+ # also depends on the leaf 'element'
+ ponyleaf = pony.dependencies[0]
+ assert(isinstance(ponyleaf, MetaElement))
+ assert(ponyleaf.kind == 'element')
+
+ horse = element.dependencies[2]
+ assert(isinstance(horse, MetaElement))
+ assert(horse.kind == 'horsy')
+ assert(len(horse.dependencies) == 1)
+
+ # By virtue of being embedded in a stack which
+ # depends on the leaf 'element', this element
+ # also depends on the leaf 'element'
+ horseleaf = horse.dependencies[0]
+ assert(isinstance(horseleaf, MetaElement))
+ assert(horseleaf.kind == 'element')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_includes(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/includingstack.bst', None, None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+
+ # Assert that the stuff from the include got into the element data,
+ # first check that we depend on both elements
+ assert(len(element.dependencies) == 2)
+
+ pony = element.dependencies[0]
+ assert(isinstance(pony, MetaElement))
+ assert(pony.kind == 'pony')
+
+ horse = element.dependencies[1]
+ assert(isinstance(horse, MetaElement))
+ assert(horse.kind == 'horsy')
+
+ # Now check that the config data from the includes made it in
+ assert(pony.config.get('pony') == 'Someone rides their pony')
+ assert(horse.config.get('horse') == 'Riding a horse')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_arch_default(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/archstack.bst', None, None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'archstack')
+
+ # Only one dependency, no known arch was selected
+ assert(len(element.dependencies) == 1)
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_arch_x86_64(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/archstack.bst', None, 'x86_64')
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'archstack')
+
+ # Two dependencies for x86_64
+ assert(len(element.dependencies) == 2)
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+
+ pony = element.dependencies[1]
+ assert(isinstance(pony, MetaElement))
+ assert(pony.kind == 'pony')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_arch_x86_32(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/archstack.bst', None, 'x86_32')
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'archstack')
+
+ # Two dependencies for x86_64
+ assert(len(element.dependencies) == 2)
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+
+ horse = element.dependencies[1]
+ assert(isinstance(horse, MetaElement))
+ assert(horse.kind == 'horsy')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_nested_arch_default(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/nestedarchstack.bst', None, None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'nestedarchstack')
+
+ # No specified arch, the color remains brown by default
+ assert(len(element.dependencies) == 1)
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+ assert(rider.config.get('color') == 'brown')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_nested_arch_x86_64(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/nestedarchstack.bst', None, 'x86_64')
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'nestedarchstack')
+
+ # x86_64, the color is now pink
+ assert(len(element.dependencies) == 1)
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+ assert(rider.config.get('color') == 'pink')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_nested_arch_x86_32(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/nestedarchstack.bst', None, 'x86_32')
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'nestedarchstack')
+
+ # x86_32, the color is now pink
+ assert(len(element.dependencies) == 1)
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+ assert(rider.config.get('color') == 'blue')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_variant_default(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variantstack.bst', None, None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'variantstack')
+
+ # No specified variant, we get a pony by default
+ assert(len(element.dependencies) == 2)
+
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+
+ pony = element.dependencies[1]
+ assert(isinstance(pony, MetaElement))
+ assert(pony.kind == 'pony')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_variant_pony(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variantstack.bst', 'pony', None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'variantstack')
+
+ # We asked for the pony variant, we get a pony
+ assert(len(element.dependencies) == 2)
+
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+
+ pony = element.dependencies[1]
+ assert(isinstance(pony, MetaElement))
+ assert(pony.kind == 'pony')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_variant_horse(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variantstack.bst', 'horse', None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'variantstack')
+
+ # We asked for the horse variant, we get a horse
+ assert(len(element.dependencies) == 2)
+
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+
+ horse = element.dependencies[1]
+ assert(isinstance(horse, MetaElement))
+ assert(horse.kind == 'horsy')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_nested_variant_default(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/nestedvariantstack.bst', None, None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'nestedvariantstack')
+
+ # No specified variant, we get a pony by default
+ assert(len(element.dependencies) == 3)
+
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+ assert(rider.config.get('number') == 6)
+
+ pony = element.dependencies[1]
+ assert(isinstance(pony, MetaElement))
+ assert(pony.kind == 'pony')
+ assert(pony.config.get('number') == 6)
+
+ horse = element.dependencies[2]
+ assert(isinstance(horse, MetaElement))
+ assert(horse.kind == 'horsy')
+ assert(horse.config.get('number') == 5)
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_nested_variant_pony(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/nestedvariantstack.bst', 'pony', None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'nestedvariantstack')
+
+ # We asked for a pony, we get a pony
+ assert(len(element.dependencies) == 3)
+
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+ assert(rider.config.get('number') == 6)
+
+ pony = element.dependencies[1]
+ assert(isinstance(pony, MetaElement))
+ assert(pony.kind == 'pony')
+ assert(pony.config.get('number') == 6)
+
+ horse = element.dependencies[2]
+ assert(isinstance(horse, MetaElement))
+ assert(horse.kind == 'horsy')
+ assert(horse.config.get('number') == 5)
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_nested_variant_horse(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/nestedvariantstack.bst', 'horse', None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'stack')
+ assert(element.name == 'nestedvariantstack')
+
+ # We asked for a horse, we get a horse
+ assert(len(element.dependencies) == 3)
+
+ rider = element.dependencies[0]
+ assert(isinstance(rider, MetaElement))
+ assert(rider.kind == 'rider')
+ assert(rider.config.get('number') == 7)
+
+ pony = element.dependencies[1]
+ assert(isinstance(pony, MetaElement))
+ assert(pony.kind == 'pony')
+ assert(pony.config.get('number') == 5)
+
+ horse = element.dependencies[2]
+ assert(isinstance(horse, MetaElement))
+ assert(horse.kind == 'horsy')
+ assert(horse.config.get('number') == 7)
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_internal_circular_dependency(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/circulardepstack.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.CIRCULAR_DEPENDENCY)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_stack_embedded_in_stack(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/stackinstack.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.INVALID_DATA)
diff --git a/tests/loader/stacks/elements/archstack.bst b/tests/loader/stacks/elements/archstack.bst
new file mode 100644
index 000000000..08239c345
--- /dev/null
+++ b/tests/loader/stacks/elements/archstack.bst
@@ -0,0 +1,15 @@
+kind: stack
+description: This is a stack, and it's elements include stuff
+embeds:
+- name: rider
+ kind: rider
+arches:
+ x86_64:
+ embeds:
+ - name: pony
+ kind: pony
+ x86_32:
+ embeds:
+ - name: horse
+ kind: horsy
+ \ No newline at end of file
diff --git a/tests/loader/stacks/elements/circulardepstack.bst b/tests/loader/stacks/elements/circulardepstack.bst
new file mode 100644
index 000000000..9a65ff485
--- /dev/null
+++ b/tests/loader/stacks/elements/circulardepstack.bst
@@ -0,0 +1,15 @@
+kind: stack
+description: This is a stack with an internal circular dependency
+embeds:
+- name: horse
+ kind: horsy
+ depends:
+ - rider
+- name: pony
+ kind: pony
+ depends:
+ - horse
+- name: rider
+ kind: rider
+ depends:
+ - pony
diff --git a/tests/loader/stacks/elements/element.bst b/tests/loader/stacks/elements/element.bst
new file mode 100644
index 000000000..366429eb1
--- /dev/null
+++ b/tests/loader/stacks/elements/element.bst
@@ -0,0 +1,4 @@
+kind: element
+description: This is just a leaf element
+config:
+ type: leaf
diff --git a/tests/loader/stacks/elements/includingstack.bst b/tests/loader/stacks/elements/includingstack.bst
new file mode 100644
index 000000000..79187e3ec
--- /dev/null
+++ b/tests/loader/stacks/elements/includingstack.bst
@@ -0,0 +1,10 @@
+kind: stack
+description: This is a stack, and it's elements include stuff
+embeds:
+- name: pony
+ kind: pony
+ include: include/pony.bst
+- name: horse
+ kind: horsy
+ include: include/horse.bst
+
diff --git a/tests/loader/stacks/elements/nestedarchstack.bst b/tests/loader/stacks/elements/nestedarchstack.bst
new file mode 100644
index 000000000..ddef648e4
--- /dev/null
+++ b/tests/loader/stacks/elements/nestedarchstack.bst
@@ -0,0 +1,14 @@
+kind: stack
+description: This is a stack whos embedded elements have arch conditionals
+embeds:
+- name: rider
+ kind: rider
+ config:
+ color: brown
+ arches:
+ x86_64:
+ config:
+ color: pink
+ x86_32:
+ config:
+ color: blue
diff --git a/tests/loader/stacks/elements/nestedvariantstack.bst b/tests/loader/stacks/elements/nestedvariantstack.bst
new file mode 100644
index 000000000..3f6879fde
--- /dev/null
+++ b/tests/loader/stacks/elements/nestedvariantstack.bst
@@ -0,0 +1,33 @@
+kind: stack
+description: This is a stack, and variants define how the embedded elements are configured
+embeds:
+- name: rider
+ kind: rider
+ config:
+ number: 5
+ variants:
+ - variant: pony
+ config:
+ number: 6
+ - variant: horse
+ config:
+ number: 7
+- name: pony
+ kind: pony
+ config:
+ number: 5
+ variants:
+ - variant: pony
+ config:
+ number: 6
+- name: horse
+ kind: horsy
+ config:
+ number: 5
+ variants:
+ - variant: horse
+ config:
+ number: 7
+variants:
+- variant: pony
+- variant: horse
diff --git a/tests/loader/stacks/elements/stack.bst b/tests/loader/stacks/elements/stack.bst
new file mode 100644
index 000000000..1900e389b
--- /dev/null
+++ b/tests/loader/stacks/elements/stack.bst
@@ -0,0 +1,7 @@
+kind: stack
+description: This is a stack, and it's elements include stuff
+embeds:
+- name: pony
+ kind: pony
+- name: horse
+ kind: horsy
diff --git a/tests/loader/stacks/elements/stackdepends.bst b/tests/loader/stacks/elements/stackdepends.bst
new file mode 100644
index 000000000..0d35f8464
--- /dev/null
+++ b/tests/loader/stacks/elements/stackdepends.bst
@@ -0,0 +1,9 @@
+kind: stack
+description: This is a stack, and it's elements include stuff
+depends:
+- elements/element.bst
+embeds:
+- name: pony
+ kind: pony
+- name: horse
+ kind: horsy
diff --git a/tests/loader/stacks/elements/stackinstack.bst b/tests/loader/stacks/elements/stackinstack.bst
new file mode 100644
index 000000000..5b91128d2
--- /dev/null
+++ b/tests/loader/stacks/elements/stackinstack.bst
@@ -0,0 +1,9 @@
+kind: stack
+description: This is a stack embedded in a stack
+embeds:
+- name: horse
+ kind: stack
+ embeds:
+ - name: impossible
+ kind: mission
+ description: You cannot embed stacks inside stacks
diff --git a/tests/loader/stacks/elements/variantstack.bst b/tests/loader/stacks/elements/variantstack.bst
new file mode 100644
index 000000000..6b8b2c8a6
--- /dev/null
+++ b/tests/loader/stacks/elements/variantstack.bst
@@ -0,0 +1,14 @@
+kind: stack
+description: This is a stack, and variants define what other elements to embed
+embeds:
+- name: rider
+ kind: rider
+variants:
+- variant: pony
+ embeds:
+ - name: pony
+ kind: pony
+- variant: horse
+ embeds:
+ - name: horse
+ kind: horsy
diff --git a/tests/loader/stacks/include/horse.bst b/tests/loader/stacks/include/horse.bst
new file mode 100644
index 000000000..1003c9073
--- /dev/null
+++ b/tests/loader/stacks/include/horse.bst
@@ -0,0 +1,2 @@
+config:
+ horse: "Riding a horse"
diff --git a/tests/loader/stacks/include/pony.bst b/tests/loader/stacks/include/pony.bst
new file mode 100644
index 000000000..3e33614b5
--- /dev/null
+++ b/tests/loader/stacks/include/pony.bst
@@ -0,0 +1,2 @@
+config:
+ pony: "Someone rides their pony"
diff --git a/tests/loader/variants.py b/tests/loader/variants.py
new file mode 100644
index 000000000..bdea0642f
--- /dev/null
+++ b/tests/loader/variants.py
@@ -0,0 +1,242 @@
+import os
+import pytest
+
+from buildstream import LoadError, LoadErrorReason
+from buildstream._loader import Loader
+from buildstream._metaelement import MetaElement
+
+DATA_DIR = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ 'variants',
+)
+
+##############################################################
+# Test Basic Failure Modes #
+##############################################################
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_not_list(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variants-not-list.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.INVALID_DATA)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_unnamed(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/unnamed-variant.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.INVALID_DATA)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_bad_name(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/variant-bad-name.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.INVALID_DATA)
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_only_one(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/only-one-variant.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.INVALID_DATA)
+
+##############################################################
+# Test Simple Variant Compositing #
+##############################################################
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_simple_composite_default(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/simple-variant-compositing.bst', None, None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ # Without specifying a variant, the default (first) should have been chosen
+ assert(element.config.get('somedata') == 5)
+ assert(element.config.get('pony-color') == 'pink')
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_simple_composite_pink_pony(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/simple-variant-compositing.bst', 'pink', None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ # We explicitly asked for the pink variation of this pony
+ assert(element.config.get('somedata') == 5)
+ assert(element.config.get('pony-color') == 'pink')
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_simple_composite_blue_pony(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/simple-variant-compositing.bst', 'blue', None)
+
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ # We explicitly asked for the blue variation of this pony,
+ # which has the side effect of overriding the value of 'somedata'
+ assert(element.config.get('somedata') == 6)
+ assert(element.config.get('pony-color') == 'blue')
+
+##############################################################
+# Test Variant Dependency Plotting #
+##############################################################
+
+# Convenience for asserting dependencies
+#
+def assert_dependency(element, index, name, key, value):
+
+ # Test that the dependency we got is the pink color by default
+ assert(len(element.dependencies) >= index + 1)
+ dep = element.dependencies[index]
+
+ assert(isinstance(dep, MetaElement))
+ assert(dep.name == name)
+ assert(isinstance(dep.config, dict))
+ assert(dep.config.get(key) == value)
+
+ return dep
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_simple_dependency_default(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/simple-dependency-variants.bst', None, None)
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ # Test that the default is a pink pony
+ assert_dependency(element, 0, 'simply-pink', 'color', 'pink')
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_simple_dependency_pink_pony(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/simple-dependency-variants.bst', 'pink', None)
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ # Test that the explicit pink dependency is correct
+ assert_dependency(element, 0, 'simply-pink', 'color', 'pink')
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_simple_dependency_blue_pony(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/simple-dependency-variants.bst', 'blue', None)
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ # Test that the explicit blue dependency is correct
+ assert_dependency(element, 0, 'simply-blue', 'color', 'blue')
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_indirect_dependency_default(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/indirect-dependency-variants.bst', None, None)
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ # Test that the default is a blue pony-color by default
+ simple = assert_dependency(element, 0, 'simple-dependency-variants', 'pony-color', 'blue')
+
+ # Test that the element we depend on now depends on the blue color
+ assert_dependency(simple, 0, 'simply-blue', 'color', 'blue')
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_indirect_dependency_blue_pony(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/indirect-dependency-variants.bst', 'blue', None)
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ # Test for a blue pony-color
+ simple = assert_dependency(element, 0, 'simple-dependency-variants', 'pony-color', 'blue')
+
+ # Test that the element we depend on now depends on the blue color
+ assert_dependency(simple, 0, 'simply-blue', 'color', 'blue')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_variant_indirect_dependency_pink_pony(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/indirect-dependency-variants.bst', 'pink', None)
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'pony')
+
+ # Test for a blue pony-color
+ simple = assert_dependency(element, 0, 'simple-dependency-variants', 'pony-color', 'pink')
+
+ # Test that the element we depend on now depends on the blue color
+ assert_dependency(simple, 0, 'simply-pink', 'color', 'pink')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_engine_resolve_agreement(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/tricky.bst', None, None)
+ element = loader.load()
+
+ assert(isinstance(element, MetaElement))
+ assert(element.kind == 'tricky')
+
+ # Test the first dependency
+ first = assert_dependency(element, 0, 'tricky-first', 'choice', 'second')
+ second = assert_dependency(element, 1, 'tricky-second', 'choice', 'second')
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_engine_disagreement(datafiles):
+
+ basedir = os.path.join(datafiles.dirname, datafiles.basename)
+ loader = Loader(basedir, 'elements/disagreement.bst', None, None)
+
+ with pytest.raises(LoadError) as exc:
+ element = loader.load()
+
+ assert (exc.value.reason == LoadErrorReason.VARIANT_DISAGREEMENT)
diff --git a/tests/loader/variants/elements/disagreement-one.bst b/tests/loader/variants/elements/disagreement-one.bst
new file mode 100644
index 000000000..37ab8e833
--- /dev/null
+++ b/tests/loader/variants/elements/disagreement-one.bst
@@ -0,0 +1,6 @@
+kind: color
+description: Something or other
+choice: pony
+depends:
+- filename: elements/disagreement-two.bst
+ variant: first
diff --git a/tests/loader/variants/elements/disagreement-two.bst b/tests/loader/variants/elements/disagreement-two.bst
new file mode 100644
index 000000000..e5cec1546
--- /dev/null
+++ b/tests/loader/variants/elements/disagreement-two.bst
@@ -0,0 +1,8 @@
+kind: color
+description: Something or other
+choice: None
+variants:
+- variant: first
+ choice: first
+- variant: second
+ choice: second
diff --git a/tests/loader/variants/elements/disagreement.bst b/tests/loader/variants/elements/disagreement.bst
new file mode 100644
index 000000000..b26c51c14
--- /dev/null
+++ b/tests/loader/variants/elements/disagreement.bst
@@ -0,0 +1,9 @@
+kind: disagreement
+description: |
+ This pipeline cannot be built because elements are in disagreement about
+ what variants to choose
+
+depends:
+- elements/disagreement-one.bst
+- filename: elements/disagreement-two.bst
+ variant: second
diff --git a/tests/loader/variants/elements/indirect-dependency-variants.bst b/tests/loader/variants/elements/indirect-dependency-variants.bst
new file mode 100644
index 000000000..81f227691
--- /dev/null
+++ b/tests/loader/variants/elements/indirect-dependency-variants.bst
@@ -0,0 +1,17 @@
+kind: pony
+description: |
+ Indirect dependency variants, depend on a different variant of the simple test,
+ depending on the selected variant
+variants:
+- variant: blue
+ config:
+ pony-color: blue
+ depends:
+ - filename: elements/simple-dependency-variants.bst
+ variant: blue
+- variant: pink
+ config:
+ pony-color: pink
+ depends:
+ - filename: elements/simple-dependency-variants.bst
+ variant: pink
diff --git a/tests/loader/variants/elements/only-one-variant.bst b/tests/loader/variants/elements/only-one-variant.bst
new file mode 100644
index 000000000..623bf2655
--- /dev/null
+++ b/tests/loader/variants/elements/only-one-variant.bst
@@ -0,0 +1,8 @@
+kind: pony
+description: |
+ Elements which declare variants must declare a minimum of two variants, even
+ if the declared variant does not augment the element in anyway. This is because
+ every variant of every element must be addressable by name.
+variants:
+- variant: pink
+ pony-color: pink
diff --git a/tests/loader/variants/elements/simple-dependency-variants.bst b/tests/loader/variants/elements/simple-dependency-variants.bst
new file mode 100644
index 000000000..721be88f3
--- /dev/null
+++ b/tests/loader/variants/elements/simple-dependency-variants.bst
@@ -0,0 +1,13 @@
+kind: pony
+description: Simple dependency variants, different variants depend on different elements
+variants:
+- variant: pink
+ config:
+ pony-color: pink
+ depends:
+ - elements/simply-pink.bst
+- variant: blue
+ config:
+ pony-color: blue
+ depends:
+ - elements/simply-blue.bst
diff --git a/tests/loader/variants/elements/simple-variant-compositing.bst b/tests/loader/variants/elements/simple-variant-compositing.bst
new file mode 100644
index 000000000..33c6571f2
--- /dev/null
+++ b/tests/loader/variants/elements/simple-variant-compositing.bst
@@ -0,0 +1,12 @@
+kind: pony
+description: Simple test of variant compositing, without fancy dependencies
+config:
+ somedata: 5
+variants:
+- variant: pink
+ config:
+ pony-color: pink
+- variant: blue
+ config:
+ pony-color: blue
+ somedata: 6
diff --git a/tests/loader/variants/elements/simply-blue.bst b/tests/loader/variants/elements/simply-blue.bst
new file mode 100644
index 000000000..2565d762c
--- /dev/null
+++ b/tests/loader/variants/elements/simply-blue.bst
@@ -0,0 +1,4 @@
+kind: color
+description: A color dependency for variant tests
+config:
+ color: blue
diff --git a/tests/loader/variants/elements/simply-pink.bst b/tests/loader/variants/elements/simply-pink.bst
new file mode 100644
index 000000000..b51a07f7b
--- /dev/null
+++ b/tests/loader/variants/elements/simply-pink.bst
@@ -0,0 +1,4 @@
+kind: color
+description: A color dependency for variant tests
+config:
+ color: pink
diff --git a/tests/loader/variants/elements/tricky-first.bst b/tests/loader/variants/elements/tricky-first.bst
new file mode 100644
index 000000000..fdc14f75f
--- /dev/null
+++ b/tests/loader/variants/elements/tricky-first.bst
@@ -0,0 +1,14 @@
+kind: color
+description: Something or other
+config:
+ choice: None
+variants:
+- variant: first
+ config:
+ choice: first
+ depends:
+ - filename: elements/tricky-second.bst
+ variant: first
+- variant: second
+ config:
+ choice: second
diff --git a/tests/loader/variants/elements/tricky-second.bst b/tests/loader/variants/elements/tricky-second.bst
new file mode 100644
index 000000000..f386eaff4
--- /dev/null
+++ b/tests/loader/variants/elements/tricky-second.bst
@@ -0,0 +1,11 @@
+kind: color
+description: Something or other
+config:
+ choice: None
+variants:
+- variant: first
+ config:
+ choice: first
+- variant: second
+ config:
+ choice: second
diff --git a/tests/loader/variants/elements/tricky.bst b/tests/loader/variants/elements/tricky.bst
new file mode 100644
index 000000000..06596cb1d
--- /dev/null
+++ b/tests/loader/variants/elements/tricky.bst
@@ -0,0 +1,15 @@
+kind: tricky
+description: |
+ This element depends ambivalently on tricky-first, then specifically
+ on the second variant of tricky-second. The default variant of tricky-first
+ depends explicitly on the first variant of tricky-second.
+
+ This forces the engine to make a choice and resolve the tree, we're expecting
+ the tree to end up with:
+ o tricky
+ o tricky-first(second)
+ o tricky-second(second)
+depends:
+- elements/tricky-first.bst
+- filename: elements/tricky-second.bst
+ variant: second
diff --git a/tests/loader/variants/elements/unnamed-variant.bst b/tests/loader/variants/elements/unnamed-variant.bst
new file mode 100644
index 000000000..18767e95c
--- /dev/null
+++ b/tests/loader/variants/elements/unnamed-variant.bst
@@ -0,0 +1,5 @@
+kind: pony
+description: This has variants but they dont specify the 'variant' name
+variants:
+- pony: 4
+- horse: Hello
diff --git a/tests/loader/variants/elements/variant-bad-name.bst b/tests/loader/variants/elements/variant-bad-name.bst
new file mode 100644
index 000000000..aefcfcf4b
--- /dev/null
+++ b/tests/loader/variants/elements/variant-bad-name.bst
@@ -0,0 +1,9 @@
+kind: pony
+description: These variants dont have string types for their name
+variants:
+- variant:
+ - pony
+ - horse
+ horse: Hello
+- variant: 5
+ pony: 4
diff --git a/tests/loader/variants/elements/variants-not-list.bst b/tests/loader/variants/elements/variants-not-list.bst
new file mode 100644
index 000000000..9d5399939
--- /dev/null
+++ b/tests/loader/variants/elements/variants-not-list.bst
@@ -0,0 +1,3 @@
+kind: pony
+description: This has variants but not a list of them
+variants: This is not a list