diff options
Diffstat (limited to 'tests/integration/workspace.py')
-rw-r--r-- | tests/integration/workspace.py | 157 |
1 files changed, 153 insertions, 4 deletions
diff --git a/tests/integration/workspace.py b/tests/integration/workspace.py index 7e84b690b..a2ea4841a 100644 --- a/tests/integration/workspace.py +++ b/tests/integration/workspace.py @@ -8,6 +8,9 @@ from buildstream import _yaml from buildstream.testing import cli_integration as cli # pylint: disable=unused-import from buildstream.testing._utils.site import HAVE_SANDBOX from buildstream.exceptions import ErrorDomain +from buildstream.utils import BST_ARBITRARY_TIMESTAMP + +from tests.testutils import wait_for_cache_granularity pytestmark = pytest.mark.integration @@ -62,7 +65,6 @@ def test_workspace_mount_on_read_only_directory(cli, datafiles): @pytest.mark.datafiles(DATA_DIR) @pytest.mark.skipif(not HAVE_SANDBOX, reason="Only available with a functioning sandbox") -@pytest.mark.xfail(reason="Incremental builds are currently incompatible with workspace source plugin.") def test_workspace_commanddir(cli, datafiles): project = str(datafiles) workspace = os.path.join(cli.directory, "workspace") @@ -74,8 +76,16 @@ def test_workspace_commanddir(cli, datafiles): res = cli.run(project=project, args=["build", element_name]) assert res.exit_code == 0 - assert os.path.exists(os.path.join(cli.directory, "workspace")) - assert os.path.exists(os.path.join(cli.directory, "workspace", "build")) + # Check that the object file was created in the command-subdir `build` + # using the cached buildtree. + res = cli.run( + project=project, + args=["shell", "--build", element_name, "--use-buildtree", "always", "--", "find", "..", "-mindepth", "1",], + ) + res.assert_success() + + files = res.output.splitlines() + assert "../build/hello.o" in files @pytest.mark.datafiles(DATA_DIR) @@ -274,7 +284,7 @@ def test_incremental_configure_commands_run_only_once(cli, datafiles): # Then we build, and check whether the configure step succeeded res = cli.run(project=project, args=["--cache-buildtrees", "always", "build", element_name]) res.assert_success() - # check that the workspace was not configured + # check that the workspace was not configured outside the sandbox assert not os.path.exists(os.path.join(workspace, "prepared")) # the configure should have been run in the sandbox, so check the buildtree @@ -288,6 +298,10 @@ def test_incremental_configure_commands_run_only_once(cli, datafiles): assert "./prepared" in files assert not "./prepared-again" in files + # Add file to workspace to trigger an (incremental) build + with open(os.path.join(workspace, "newfile"), "w"): + pass + # When we build again, the configure commands should not be # called, and we should therefore exit cleanly (the configure # commands are set to always fail after the first run) @@ -365,3 +379,138 @@ def test_workspace_failed_logs(cli, datafiles): fail_str = "FAILURE {}: Running build-commands".format(element_name) batch_fail_str = "FAILURE {}: Running commands".format(element_name) assert fail_str in log or batch_fail_str in log + + +def get_buildtree_file_contents(cli, project, element_name, filename): + res = cli.run( + project=project, args=["shell", "--build", element_name, "--use-buildtree", "always", "--", "cat", filename,], + ) + res.assert_success() + return res.output + + +@pytest.mark.datafiles(DATA_DIR) +@pytest.mark.skipif(not HAVE_SANDBOX, reason="Only available with a functioning sandbox") +def test_incremental(cli, datafiles): + project = str(datafiles) + workspace = os.path.join(cli.directory, "workspace") + element_path = os.path.join(project, "elements") + element_name = "workspace/incremental.bst" + + element = { + "kind": "manual", + "depends": [{"filename": "base.bst", "type": "build"}], + "sources": [{"kind": "local", "path": "files/workspace-incremental"}], + "config": {"build-commands": ["make"]}, + } + _yaml.roundtrip_dump(element, os.path.join(element_path, element_name)) + + # We open a workspace on the above element + res = cli.run(project=project, args=["workspace", "open", "--directory", workspace, element_name]) + res.assert_success() + + # Initial (non-incremental) build of the workspace + res = cli.run(project=project, args=["build", element_name]) + res.assert_success() + + # Save the random hash + random_hash = get_buildtree_file_contents(cli, project, element_name, "random") + + # Verify the expected output file of the initial build + assert get_buildtree_file_contents(cli, project, element_name, "copy") == "1" + + wait_for_cache_granularity() + + # Replace source file contents with '2' + with open(os.path.join(workspace, "source"), "w") as f: + f.write("2") + + # Perform incremental build of the workspace + res = cli.run(project=project, args=["build", element_name]) + res.assert_success() + + # Verify that this was an incremental build by comparing the random hash + assert get_buildtree_file_contents(cli, project, element_name, "random") == random_hash + + # Verify that the output file matches the new source file + assert get_buildtree_file_contents(cli, project, element_name, "copy") == "2" + + wait_for_cache_granularity() + + # Replace source file contents with '3', however, set an old mtime such + # that `make` will not pick up the change + with open(os.path.join(workspace, "source"), "w") as f: + f.write("3") + os.utime(os.path.join(workspace, "source"), (BST_ARBITRARY_TIMESTAMP, BST_ARBITRARY_TIMESTAMP)) + + # Perform incremental build of the workspace + res = cli.run(project=project, args=["build", element_name]) + res.assert_success() + + # Verify that this was an incremental build by comparing the random hash + assert get_buildtree_file_contents(cli, project, element_name, "random") == random_hash + + # Verify that the output file still matches the previous content '2' + assert get_buildtree_file_contents(cli, project, element_name, "copy") == "2" + + +# Test incremental build after partial build / build failure +@pytest.mark.datafiles(DATA_DIR) +@pytest.mark.skipif(not HAVE_SANDBOX, reason="Only available with a functioning sandbox") +def test_incremental_partial(cli, datafiles): + project = str(datafiles) + workspace = os.path.join(cli.directory, "workspace") + element_path = os.path.join(project, "elements") + element_name = "workspace/incremental.bst" + + element = { + "kind": "manual", + "depends": [{"filename": "base.bst", "type": "build"}], + "sources": [{"kind": "local", "path": "files/workspace-partial"}], + "config": {"build-commands": ["make random", "make copy1", "make copy2"]}, + } + _yaml.roundtrip_dump(element, os.path.join(element_path, element_name)) + + # We open a workspace on the above element + res = cli.run(project=project, args=["workspace", "open", "--directory", workspace, element_name]) + res.assert_success() + + # Initial (non-incremental) build of the workspace + res = cli.run(project=project, args=["build", element_name]) + res.assert_success() + + # Save the random hash + random_hash = get_buildtree_file_contents(cli, project, element_name, "random") + + # Verify the expected output files of the initial build + assert get_buildtree_file_contents(cli, project, element_name, "copy1") == "1" + assert get_buildtree_file_contents(cli, project, element_name, "copy2") == "1" + + wait_for_cache_granularity() + + # Delete source1 and replace source2 file contents with '2' + os.unlink(os.path.join(workspace, "source1")) + with open(os.path.join(workspace, "source2"), "w") as f: + f.write("2") + + # Perform incremental build of the workspace + # This should fail because of the missing source1 file. + res = cli.run(project=project, args=["build", element_name]) + res.assert_main_error(ErrorDomain.STREAM, None) + + wait_for_cache_granularity() + + # Recreate source1 file + with open(os.path.join(workspace, "source1"), "w") as f: + f.write("2") + + # Perform incremental build of the workspace + res = cli.run(project=project, args=["build", element_name]) + res.assert_success() + + # Verify that this was an incremental build by comparing the random hash + assert get_buildtree_file_contents(cli, project, element_name, "random") == random_hash + + # Verify that both files got rebuilt + assert get_buildtree_file_contents(cli, project, element_name, "copy1") == "2" + assert get_buildtree_file_contents(cli, project, element_name, "copy2") == "2" |