diff options
author | Klaus Aehlig <klaus.aehlig@huawei.com> | 2022-02-22 17:03:21 +0100 |
---|---|---|
committer | Klaus Aehlig <klaus.aehlig@huawei.com> | 2022-02-22 17:03:21 +0100 |
commit | 619def44c1cca9f3cdf63544d5f24f2c7a7d9b77 (patch) | |
tree | 01868de723cb82c86842f33743fa7b14e24c1fa3 /test/buildtool/execution_api/local/local_execution.test.cpp | |
download | justbuild-619def44c1cca9f3cdf63544d5f24f2c7a7d9b77.tar.gz |
Initial self-hosting commit
This is the initial version of our tool that is able to
build itself. In can be bootstrapped by
./bin/bootstrap.py
Co-authored-by: Oliver Reiche <oliver.reiche@huawei.com>
Co-authored-by: Victor Moreno <victor.moreno1@huawei.com>
Diffstat (limited to 'test/buildtool/execution_api/local/local_execution.test.cpp')
-rwxr-xr-x | test/buildtool/execution_api/local/local_execution.test.cpp | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/test/buildtool/execution_api/local/local_execution.test.cpp b/test/buildtool/execution_api/local/local_execution.test.cpp new file mode 100755 index 00000000..6c38c669 --- /dev/null +++ b/test/buildtool/execution_api/local/local_execution.test.cpp @@ -0,0 +1,274 @@ +#include <chrono> +#include <string> +#include <vector> + +#include "catch2/catch.hpp" +#include "src/buildtool/common/artifact_factory.hpp" +#include "src/buildtool/execution_api/local/local_api.hpp" +#include "test/utils/hermeticity/local.hpp" + +namespace { + +[[nodiscard]] auto GetTestDir() -> std::filesystem::path { + auto* tmp_dir = std::getenv("TEST_TMPDIR"); + if (tmp_dir != nullptr) { + return tmp_dir; + } + return FileSystemManager::GetCurrentDirectory() / + "test/buildtool/execution_api/local"; +} + +} // namespace + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalExecution: No input, no output", + "[execution_api]") { + auto api = LocalApi{}; + + std::string test_content("test"); + std::vector<std::string> const cmdline = {"echo", "-n", test_content}; + auto action = + api.CreateAction(*api.UploadTree({}), cmdline, {}, {}, {}, {}); + REQUIRE(action); + + SECTION("Cache execution result in action cache") { + // run execution + action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput); + auto output = action->Execute(nullptr); + REQUIRE(output); + + // verify result + CHECK_FALSE(output->IsCached()); + CHECK(output->StdOut() == test_content); + + output = action->Execute(nullptr); + REQUIRE(output); + CHECK(output->IsCached()); + } + + SECTION("Do not cache execution result in action cache") { + // run execution + action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput); + auto output = action->Execute(nullptr); + REQUIRE(output); + + // verify result + CHECK_FALSE(output->IsCached()); + CHECK(output->StdOut() == test_content); + + // ensure result IS STILL NOT in cache + output = action->Execute(nullptr); + REQUIRE(output); + CHECK_FALSE(output->IsCached()); + } +} + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalExecution: No input, no output, env variables used", + "[execution_api]") { + auto api = LocalApi{}; + + std::string test_content("test from env var"); + std::vector<std::string> const cmdline = { + "/bin/sh", "-c", "set -e\necho -n ${MYCONTENT}"}; + auto action = api.CreateAction(*api.UploadTree({}), + cmdline, + {}, + {}, + {{"MYCONTENT", test_content}}, + {}); + REQUIRE(action); + + SECTION("Cache execution result in action cache") { + // run execution + action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput); + auto output = action->Execute(nullptr); + REQUIRE(output); + + // verify result + CHECK_FALSE(output->IsCached()); + CHECK(output->StdOut() == test_content); + + // ensure result IS in cache + output = action->Execute(nullptr); + REQUIRE(output); + CHECK(output->IsCached()); + } + + SECTION("Do not cache execution result in action cache") { + // run execution + action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput); + auto output = action->Execute(nullptr); + REQUIRE(output); + + // verify result + CHECK_FALSE(output->IsCached()); + CHECK(output->StdOut() == test_content); + + // ensure result IS STILL NOT in cache + output = action->Execute(nullptr); + REQUIRE(output); + CHECK_FALSE(output->IsCached()); + } +} + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalExecution: No input, create output", + "[execution_api]") { + auto api = LocalApi{}; + + std::string test_content("test"); + auto test_digest = ArtifactDigest::Create(test_content); + + std::string output_path{"output_file"}; + std::vector<std::string> const cmdline = { + "/bin/sh", + "-c", + "set -e\necho -n " + test_content + " > " + output_path}; + + auto action = api.CreateAction( + *api.UploadTree({}), cmdline, {output_path}, {}, {}, {}); + REQUIRE(action); + + SECTION("Cache execution result in action cache") { + // run execution + action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput); + auto output = action->Execute(nullptr); + REQUIRE(output); + + // verify result + CHECK_FALSE(output->IsCached()); + auto artifacts = output->Artifacts(); + REQUIRE(artifacts.contains(output_path)); + CHECK(artifacts.at(output_path).digest == test_digest); + + // ensure result IS in cache + output = action->Execute(nullptr); + REQUIRE(output); + CHECK(output->IsCached()); + } + + SECTION("Do not cache execution result in action cache") { + // run execution + action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput); + auto output = action->Execute(nullptr); + REQUIRE(output); + + // verify result + CHECK_FALSE(output->IsCached()); + auto artifacts = output->Artifacts(); + REQUIRE(artifacts.contains(output_path)); + CHECK(artifacts.at(output_path).digest == test_digest); + + // ensure result IS STILL NOT in cache + output = action->Execute(nullptr); + REQUIRE(output); + CHECK_FALSE(output->IsCached()); + } +} + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalExecution: One input copied to output", + "[execution_api]") { + auto api = LocalApi{}; + + std::string test_content("test"); + auto test_digest = ArtifactDigest::Create(test_content); + REQUIRE(api.Upload(BlobContainer{{BazelBlob{test_digest, test_content}}}, + false)); + + std::string input_path{"dir/subdir/input"}; + std::string output_path{"output_file"}; + + std::vector<std::string> const cmdline = {"cp", input_path, output_path}; + + auto local_artifact_opt = + ArtifactFactory::FromDescription(ArtifactFactory::DescribeKnownArtifact( + test_digest.hash(), test_digest.size(), ObjectType::File)); + REQUIRE(local_artifact_opt); + auto local_artifact = + DependencyGraph::ArtifactNode{std::move(*local_artifact_opt)}; + + auto action = + api.CreateAction(*api.UploadTree({{input_path, &local_artifact}}), + cmdline, + {output_path}, + {}, + {}, + {}); + REQUIRE(action); + + SECTION("Cache execution result in action cache") { + // run execution + action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput); + auto output = action->Execute(nullptr); + REQUIRE(output); + + // verify result + CHECK_FALSE(output->IsCached()); + auto artifacts = output->Artifacts(); + REQUIRE(artifacts.contains(output_path)); + CHECK(artifacts.at(output_path).digest == test_digest); + + // ensure result IS in cache + output = action->Execute(nullptr); + REQUIRE(output); + CHECK(output->IsCached()); + } + + SECTION("Do not cache execution result in action cache") { + // run execution + action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput); + auto output = action->Execute(nullptr); + REQUIRE(output); + + // verify result + CHECK_FALSE(output->IsCached()); + auto artifacts = output->Artifacts(); + REQUIRE(artifacts.contains(output_path)); + CHECK(artifacts.at(output_path).digest == test_digest); + + // ensure result IS STILL NOT in cache + output = action->Execute(nullptr); + REQUIRE(output); + CHECK_FALSE(output->IsCached()); + } +} + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalExecution: Cache failed action's result", + "[execution_api]") { + auto api = LocalApi{}; + + auto flag = GetTestDir() / "flag"; + std::vector<std::string> const cmdline = { + "sh", "-c", fmt::format("[ -f '{}' ]", flag.string())}; + + auto action = + api.CreateAction(*api.UploadTree({}), cmdline, {}, {}, {}, {}); + REQUIRE(action); + + action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput); + + // run failed action + auto failed = action->Execute(nullptr); + REQUIRE(failed); + CHECK_FALSE(failed->IsCached()); + CHECK(failed->ExitCode() != 0); + + REQUIRE(FileSystemManager::CreateFile(flag)); + + // run success action (should rerun and overwrite) + auto success = action->Execute(nullptr); + REQUIRE(success); + CHECK_FALSE(success->IsCached()); + CHECK(success->ExitCode() == 0); + + // rerun success action (should be served from cache) + auto cached = action->Execute(nullptr); + REQUIRE(cached); + CHECK(cached->IsCached()); + CHECK(cached->ExitCode() == 0); + + CHECK(FileSystemManager::RemoveFile(flag)); +} |