| # Pylint doesn't play well with fixtures and dependency injection from pytest |
| # pylint: disable=redefined-outer-name |
| |
| import os |
| |
| import pytest |
| from buildstream.testing import create_repo |
| from buildstream.testing import cli # pylint: disable=unused-import |
| from buildstream import _yaml |
| |
| # Project directory |
| DATA_DIR = os.path.join( |
| os.path.dirname(os.path.realpath(__file__)), |
| "project", |
| ) |
| |
| |
| # create_element() |
| # |
| # Args: |
| # project (str): The project directory where testing is happening |
| # name (str): The element name to create |
| # dependencies (list): The list of dependencies to dump into YAML format |
| # |
| # Returns: |
| # (Repo): The corresponding git repository created for the element |
| def create_element(project, name, dependencies): |
| dev_files_path = os.path.join(project, 'files', 'dev-files') |
| element_path = os.path.join(project, 'elements') |
| repo = create_repo('git', project, "{}-repo".format(name)) |
| ref = repo.create(dev_files_path) |
| |
| element = { |
| 'kind': 'import', |
| 'sources': [ |
| repo.source_config(ref=ref) |
| ], |
| 'depends': dependencies |
| } |
| _yaml.dump(element, os.path.join(element_path, name)) |
| |
| return repo |
| |
| |
| # This tests a variety of scenarios and checks that the order in |
| # which things are processed remains stable. |
| # |
| # This is especially important in order to ensure that our |
| # depth sorting and optimization of which elements should be |
| # processed first is doing it's job right, and that we are |
| # promoting elements to the build queue as soon as possible |
| # |
| # Parameters: |
| # targets (target elements): The targets to invoke bst with |
| # template (dict): The project template dictionary, for create_element() |
| # expected (list): A list of element names in the expected order |
| # |
| @pytest.mark.datafiles(os.path.join(DATA_DIR)) |
| @pytest.mark.parametrize("target,template,expected", [ |
| # First simple test |
| ('3.bst', { |
| '0.bst': ['1.bst'], |
| '1.bst': [], |
| '2.bst': ['0.bst'], |
| '3.bst': ['0.bst', '1.bst', '2.bst'] |
| }, ['1.bst', '0.bst', '2.bst', '3.bst']), |
| |
| # A more complicated test with build of build dependencies |
| ('target.bst', { |
| 'a.bst': [], |
| 'base.bst': [], |
| 'timezones.bst': [], |
| 'middleware.bst': [{'filename': 'base.bst', 'type': 'build'}], |
| 'app.bst': [{'filename': 'middleware.bst', 'type': 'build'}], |
| 'target.bst': ['a.bst', 'base.bst', 'middleware.bst', 'app.bst', 'timezones.bst'] |
| }, ['base.bst', 'middleware.bst', 'a.bst', 'app.bst', 'timezones.bst', 'target.bst']), |
| ]) |
| @pytest.mark.parametrize("operation", [('show'), ('fetch'), ('build')]) |
| def test_order(cli, datafiles, operation, target, template, expected): |
| project = str(datafiles) |
| |
| # Configure to only allow one fetcher at a time, make it easy to |
| # determine what is being planned in what order. |
| cli.configure({ |
| 'scheduler': { |
| 'fetchers': 1, |
| 'builders': 1 |
| } |
| }) |
| |
| # Build the project from the template, make import elements |
| # all with the same repo |
| # |
| for element, dependencies in template.items(): |
| create_element(project, element, dependencies) |
| |
| # Run test and collect results |
| if operation == 'show': |
| result = cli.run(args=['show', '--deps', 'plan', '--format', '%{name}', target], project=project, silent=True) |
| result.assert_success() |
| results = result.output.splitlines() |
| else: |
| if operation == 'fetch': |
| result = cli.run(args=['source', 'fetch', target], project=project, silent=True) |
| else: |
| result = cli.run(args=[operation, target], project=project, silent=True) |
| result.assert_success() |
| results = result.get_start_order(operation) |
| |
| # Assert the order |
| print("Expected order: {}".format(expected)) |
| print("Observed result order: {}".format(results)) |
| assert results == expected |