summaryrefslogtreecommitdiff
path: root/test/buildtool/file_system
diff options
context:
space:
mode:
authorPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2024-04-08 16:32:14 +0200
committerPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2024-04-10 15:25:45 +0200
commit5a1497b2040d2c6774996e5171bc434cbe69d81a (patch)
tree03c9ea3860bf47d0fd1eb4f6fd9b2f69759f10c4 /test/buildtool/file_system
parent327b74ed6a94f3eb69a6b49bac3395b7203ce580 (diff)
downloadjustbuild-5a1497b2040d2c6774996e5171bc434cbe69d81a.tar.gz
Add test for resolve_symlinks_map
Diffstat (limited to 'test/buildtool/file_system')
-rw-r--r--test/buildtool/file_system/TARGETS25
-rw-r--r--test/buildtool/file_system/resolve_symlinks_map.test.cpp227
2 files changed, 252 insertions, 0 deletions
diff --git a/test/buildtool/file_system/TARGETS b/test/buildtool/file_system/TARGETS
index e63bb06d..512eb175 100644
--- a/test/buildtool/file_system/TARGETS
+++ b/test/buildtool/file_system/TARGETS
@@ -128,6 +128,30 @@
]
, "stage": ["test", "buildtool", "file_system"]
}
+, "resolve_symlinks_map":
+ { "type": ["@", "rules", "CC/test", "test"]
+ , "name": ["resolve_symlinks_map"]
+ , "srcs": ["resolve_symlinks_map.test.cpp"]
+ , "data": ["test_data"]
+ , "private-deps":
+ [ ["@", "catch2", "", "catch2"]
+ , ["", "catch-main"]
+ , ["@", "fmt", "", "fmt"]
+ , ["@", "src", "src/buildtool/file_system", "file_system_manager"]
+ , ["@", "src", "src/buildtool/file_system", "git_cas"]
+ , ["@", "src", "src/buildtool/file_system", "git_repo"]
+ , ["@", "src", "src/buildtool/file_system", "object_type"]
+ , ["@", "src", "src/buildtool/file_system/symlinks_map", "pragma_special"]
+ , [ "@"
+ , "src"
+ , "src/buildtool/file_system/symlinks_map"
+ , "resolve_symlinks_map"
+ ]
+ , ["@", "src", "src/buildtool/multithreading", "task_system"]
+ , ["utils", "shell_quoting"]
+ ]
+ , "stage": ["test", "buildtool", "file_system"]
+ }
, "TESTS":
{ "type": "install"
, "tainted": ["test"]
@@ -138,6 +162,7 @@
, "git_tree"
, "directory_entries"
, "git_repo"
+ , "resolve_symlinks_map"
]
}
}
diff --git a/test/buildtool/file_system/resolve_symlinks_map.test.cpp b/test/buildtool/file_system/resolve_symlinks_map.test.cpp
new file mode 100644
index 00000000..2cf05ead
--- /dev/null
+++ b/test/buildtool/file_system/resolve_symlinks_map.test.cpp
@@ -0,0 +1,227 @@
+// Copyright 2024 Huawei Cloud Computing Technology Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <atomic>
+#include <cstdlib>
+#include <filesystem>
+#include <optional>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include "catch2/catch_test_macros.hpp"
+#include "fmt/core.h"
+#include "src/buildtool/file_system/file_system_manager.hpp"
+#include "src/buildtool/file_system/git_cas.hpp"
+#include "src/buildtool/file_system/git_repo.hpp"
+#include "src/buildtool/file_system/object_type.hpp"
+#include "src/buildtool/file_system/symlinks_map/pragma_special.hpp"
+#include "src/buildtool/file_system/symlinks_map/resolve_symlinks_map.hpp"
+#include "src/buildtool/multithreading/task_system.hpp"
+#include "test/utils/shell_quoting.hpp"
+
+namespace {
+
+// see create_fs_test_git_bundle_symlinks.sh
+auto const kBundleSymPath =
+ std::string{"test/buildtool/file_system/data/test_repo_symlinks.bundle"};
+auto const kTreeSymId = std::string{"18770dacfe14c15d88450c21c16668e13ab0e7f9"};
+auto const kFooId = std::string{"19102815663d23f8b75a47e7a01965dcdc96468c"};
+auto const kBarId = std::string{"ba0e162e1c47469e3fe4b393a8bf8c569f302116"};
+auto const kBazLinkId = std::string{"3f9538666251333f5fa519e01eb267d371ca9c78"};
+auto const kBazSymId = std::string{"1868f82682c290f0b1db3cacd092727eef1fa57f"};
+auto const kBazBarLinkId =
+ std::string{"ba0e162e1c47469e3fe4b393a8bf8c569f302116"};
+auto const kFooLinkId = std::string{"b24736f10d3c60015386047ebc98b4ab63056041"};
+
+// see create_fs_test_git_bundle.sh
+auto const kBundlePath =
+ std::string{"test/buildtool/file_system/data/test_repo.bundle"};
+auto const kBazId = std::string{"27b32561185c2825150893774953906c6daa6798"};
+
+[[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/file_system";
+}
+
+[[nodiscard]] auto CreateTestRepo(bool is_bare = false)
+ -> std::optional<std::filesystem::path> {
+ static std::atomic<int> counter{};
+ auto repo_path =
+ GetTestDir() / "test_repo" /
+ std::filesystem::path{std::to_string(counter++)}.filename();
+ auto cmd = fmt::format("git clone {}{} {}",
+ is_bare ? "--bare " : "",
+ QuoteForShell(kBundlePath),
+ QuoteForShell(repo_path.string()));
+ if (std::system(cmd.c_str()) == 0) {
+ return repo_path;
+ }
+ return std::nullopt;
+}
+
+[[nodiscard]] auto CreateTestRepoSymlinks(bool is_bare = false)
+ -> std::optional<std::filesystem::path> {
+ static std::atomic<int> counter{};
+ auto repo_path =
+ GetTestDir() / "test_repo_symlinks" /
+ std::filesystem::path{std::to_string(counter++)}.filename();
+ auto cmd = fmt::format("git clone {}{} {}",
+ is_bare ? "--bare " : "",
+ QuoteForShell(kBundleSymPath),
+ QuoteForShell(repo_path.string()));
+ if (std::system(cmd.c_str()) == 0) {
+ return repo_path;
+ }
+ return std::nullopt;
+}
+
+// The checkout will make the content available, as well as the HEAD ref
+[[nodiscard]] auto CreateTestRepoSymlinksWithCheckout(
+ bool is_bare = false) noexcept -> std::optional<std::filesystem::path> {
+ auto repo_path = CreateTestRepoSymlinks(is_bare);
+ REQUIRE(repo_path);
+ auto cmd =
+ fmt::format("git --git-dir={} --work-tree={} checkout master",
+ QuoteForShell(is_bare ? repo_path->string()
+ : (*repo_path / ".git").string()),
+ QuoteForShell(repo_path->string()));
+ if (std::system(cmd.c_str()) == 0) {
+ return *repo_path;
+ }
+ return std::nullopt;
+}
+
+} // namespace
+
+TEST_CASE("Resolve symlinks", "[resolve_symlinks_map]") {
+ // non-bare repo with symlinks as source
+ auto source_repo_path = CreateTestRepoSymlinksWithCheckout();
+ REQUIRE(source_repo_path);
+ auto source_cas = GitCAS::Open(*source_repo_path);
+ REQUIRE(source_cas);
+
+ auto resolve_symlinks_map = CreateResolveSymlinksMap();
+
+ SECTION("Source repo is target repo") {
+ constexpr auto NUM_CASES = 3;
+ std::vector<ResolvedGitObject> expected = {
+ {kFooId, ObjectType::File, "baz/foo"},
+ {kBazBarLinkId, ObjectType::Symlink, "bar_l"},
+ {kBazId, ObjectType::Tree, "."}};
+
+ auto error = false;
+ auto error_msg = std::string("NONE");
+ {
+ TaskSystem ts;
+ resolve_symlinks_map.ConsumeAfterKeysReady(
+ &ts,
+ {GitObjectToResolve(kTreeSymId,
+ "foo_l",
+ PragmaSpecial::ResolveCompletely,
+ /*known_info=*/std::nullopt,
+ source_cas,
+ source_cas),
+ GitObjectToResolve(kBazSymId,
+ "bar_l",
+ PragmaSpecial::ResolvePartially,
+ /*known_info=*/std::nullopt,
+ source_cas,
+ source_cas),
+ GitObjectToResolve(kBazSymId,
+ ".",
+ PragmaSpecial::Ignore,
+ /*known_info=*/std::nullopt,
+ source_cas,
+ source_cas)},
+ [&expected, &source_cas](auto const& values) {
+ for (auto i = 0; i < NUM_CASES; ++i) {
+ auto const& res = ResolvedGitObject{*values[i]};
+ CHECK(res.id == expected[i].id);
+ CHECK(res.type == expected[i].type);
+ CHECK(res.path == expected[i].path);
+ // the object needs to be present in target repo
+ CHECK(
+ source_cas->ReadHeader(res.id, /*is_hex_id=*/true));
+ }
+ },
+ [&error, &error_msg](std::string const& msg, bool /*unused*/) {
+ error = true;
+ error_msg = msg;
+ });
+ }
+ CHECK_FALSE(error);
+ CHECK(error_msg == "NONE");
+ }
+
+ SECTION("Bare target repo") {
+ auto target_repo_path = CreateTestRepo(true);
+ REQUIRE(target_repo_path);
+ auto target_cas = GitCAS::Open(*target_repo_path);
+ REQUIRE(target_cas);
+
+ constexpr auto NUM_CASES = 3;
+ std::vector<ResolvedGitObject> expected = {
+ {kFooId, ObjectType::File, "baz/foo"},
+ {kBazBarLinkId, ObjectType::Symlink, "bar_l"},
+ {kBazId, ObjectType::Tree, "."}};
+
+ auto error = false;
+ auto error_msg = std::string("NONE");
+ {
+ TaskSystem ts;
+ resolve_symlinks_map.ConsumeAfterKeysReady(
+ &ts,
+ {GitObjectToResolve(kTreeSymId,
+ "foo_l",
+ PragmaSpecial::ResolveCompletely,
+ /*known_info=*/std::nullopt,
+ source_cas,
+ target_cas),
+ GitObjectToResolve(kBazSymId,
+ "bar_l",
+ PragmaSpecial::ResolvePartially,
+ /*known_info=*/std::nullopt,
+ source_cas,
+ target_cas),
+ GitObjectToResolve(kBazSymId,
+ ".",
+ PragmaSpecial::Ignore,
+ /*known_info=*/std::nullopt,
+ source_cas,
+ target_cas)},
+ [&expected, &target_cas](auto const& values) {
+ for (auto i = 0; i < NUM_CASES; ++i) {
+ auto const& res = ResolvedGitObject{*values[i]};
+ CHECK(res.id == expected[i].id);
+ CHECK(res.type == expected[i].type);
+ CHECK(res.path == expected[i].path);
+ // the object needs to be present in target repo
+ CHECK(
+ target_cas->ReadHeader(res.id, /*is_hex_id=*/true));
+ }
+ },
+ [&error, &error_msg](std::string const& msg, bool /*unused*/) {
+ error = true;
+ error_msg = msg;
+ });
+ }
+ CHECK_FALSE(error);
+ CHECK(error_msg == "NONE");
+ }
+}