summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/end-to-end/just-mr/TARGETS14
-rw-r--r--test/end-to-end/just-mr/create_test_archives.cpp32
-rw-r--r--test/end-to-end/just-mr/install-roots-symlinks.sh230
-rw-r--r--test/end-to-end/just-mr/install-roots.sh35
-rw-r--r--test/end-to-end/just-mr/just-mr.test.sh67
5 files changed, 336 insertions, 42 deletions
diff --git a/test/end-to-end/just-mr/TARGETS b/test/end-to-end/just-mr/TARGETS
index 2f44f962..7cdc9ba5 100644
--- a/test/end-to-end/just-mr/TARGETS
+++ b/test/end-to-end/just-mr/TARGETS
@@ -60,6 +60,13 @@
, "deps":
[["end-to-end", "mr-tool-under-test"], ["end-to-end", "tool-under-test"]]
}
+, "install-roots-symlinks":
+ { "type": ["@", "rules", "shell/test", "script"]
+ , "name": ["install-roots-symlinks"]
+ , "test": ["install-roots-symlinks.sh"]
+ , "deps":
+ [["end-to-end", "mr-tool-under-test"], ["end-to-end", "tool-under-test"]]
+ }
, "TESTS":
{ "type": "install"
, "tainted": ["test"]
@@ -71,7 +78,12 @@
, { "type": "if"
, "cond": {"type": "var", "name": "TEST_BOOTSTRAP_JUST_MR"}
, "then": []
- , "else": ["just_mr_mp", "git-tree-verbosity", "defaults"]
+ , "else":
+ [ "install-roots-symlinks"
+ , "just_mr_mp"
+ , "git-tree-verbosity"
+ , "defaults"
+ ]
}
]
}
diff --git a/test/end-to-end/just-mr/create_test_archives.cpp b/test/end-to-end/just-mr/create_test_archives.cpp
index 2f4327b7..3fa6759a 100644
--- a/test/end-to-end/just-mr/create_test_archives.cpp
+++ b/test/end-to-end/just-mr/create_test_archives.cpp
@@ -35,16 +35,27 @@ Structure of content tree:
+--root
+--bar
+--foo
+ +--foo_l
+ +--baz_l
+--baz
+--bar
+--foo
+ +--foo_l
+
+foo_l is symlink "baz/foo_l" [non-upwards, pointing to file]
+baz_l is symlink "baz" [non-upwards, pointing to tree]
+baz/foo_l is symlink "../foo_l" [upwards & confined, pointing to symlink]
*/
-auto const kExpected = filetree_t{{"root", {"", ObjectType::Tree}},
- {"root/foo", {"foo", ObjectType::File}},
- {"root/bar", {"bar", ObjectType::File}},
- {"root/baz", {"", ObjectType::Tree}},
- {"root/baz/foo", {"foo", ObjectType::File}},
- {"root/baz/bar", {"bar", ObjectType::File}}};
+auto const kExpected =
+ filetree_t{{"root", {"", ObjectType::Tree}},
+ {"root/foo", {"foo", ObjectType::File}},
+ {"root/bar", {"bar", ObjectType::File}},
+ {"root/baz", {"", ObjectType::Tree}},
+ {"root/baz_l", {"baz", ObjectType::Symlink}},
+ {"root/foo_l", {"foo", ObjectType::Symlink}},
+ {"root/baz/foo", {"foo", ObjectType::File}},
+ {"root/baz/bar", {"bar", ObjectType::File}},
+ {"root/baz/foo_l", {"../foo_l", ObjectType::Symlink}}};
void create_files(std::filesystem::path const& destDir = ".") {
for (auto const& [path, file] : kExpected) {
@@ -66,6 +77,15 @@ void create_files(std::filesystem::path const& destDir = ".") {
std::exit(1);
};
} break;
+ case ObjectType::Symlink: {
+ if (not FileSystemManager::CreateSymlink(content,
+ destDir / path)) {
+ Logger::Log(LogLevel::Error,
+ "Could not create test symlink at path {}",
+ (destDir / path).string());
+ std::exit(1);
+ };
+ } break;
default: {
Logger::Log(LogLevel::Error,
"File system failure in creating test archive");
diff --git a/test/end-to-end/just-mr/install-roots-symlinks.sh b/test/end-to-end/just-mr/install-roots-symlinks.sh
new file mode 100644
index 00000000..aa3ae836
--- /dev/null
+++ b/test/end-to-end/just-mr/install-roots-symlinks.sh
@@ -0,0 +1,230 @@
+#!/bin/sh
+# Copyright 2023 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.
+
+
+###
+# This test extends install-roots-basic with 'special' pragma use-cases
+##
+
+set -eu
+
+readonly JUST="${PWD}/bin/tool-under-test"
+readonly JUST_MR="${PWD}/bin/mr-tool-under-test"
+readonly DISTDIR="${TEST_TMPDIR}/distfiles"
+readonly LBR="${TEST_TMPDIR}/local-build-root"
+
+readonly INSTALL_DIR_RESOLVED="${TEST_TMPDIR}/installation-target-resolved"
+readonly INSTALL_DIR_UNRESOLVED="${TEST_TMPDIR}/installation-target-unresolved"
+readonly INSTALL_DIR_SPECIAL_IGNORE="${TEST_TMPDIR}/installation-target-special-ignore"
+readonly INSTALL_DIR_SPECIAL_PARTIAL="${TEST_TMPDIR}/installation-target-special-partial"
+readonly INSTALL_DIR_SPECIAL_COMPLETE="${TEST_TMPDIR}/installation-target-special-complete"
+
+readonly TEST_DATA="The content of the data file in foo"
+readonly TEST_DIRS="bar/baz"
+readonly DATA_PATH="bar/baz/data.txt"
+readonly NON_UPWARDS_LINK_PATH="bar/baz/nonupwards"
+readonly NON_UPWARDS_LINK_TARGET="data.txt"
+readonly UPWARDS_LINK_PATH="bar/upwards"
+readonly UPWARDS_LINK_TARGET="../bar/baz"
+readonly INDIRECT_LINK_PATH="bar/indirect"
+readonly INDIRECT_LINK_TARGET="upwards/data.txt"
+
+mkdir -p "${DISTDIR}"
+
+###
+# Set up sample archives
+##
+
+mkdir -p "foo/${TEST_DIRS}"
+echo {} > foo/TARGETS
+echo -n "${TEST_DATA}" > "foo/${DATA_PATH}"
+
+# add resolvable non-upwards symlink
+ln -s "${NON_UPWARDS_LINK_TARGET}" "foo/${NON_UPWARDS_LINK_PATH}"
+tar cf "${DISTDIR}/foo-1.2.3_v1.tar" foo \
+ --sort=name --owner=root:0 --group=root:0 --mtime='UTC 1970-01-01' 2>&1
+foocontent_v1=$(git hash-object "${DISTDIR}/foo-1.2.3_v1.tar")
+echo "Foo archive v1 has content ${foocontent_v1}"
+
+# get Git-tree of foo subdir with only non-upwards symlinks
+cd foo
+(
+ git init \
+ && git config user.email "nobody@example.org" \
+ && git config user.name "Nobody" \
+ && git add . \
+ && git commit -m "test" --date="1970-01-01T00:00Z"
+)
+UNRESOLVED_TREE=$(git log -n 1 --format='%T')
+echo "Foo archive v1 has unresolved tree ${UNRESOLVED_TREE}"
+rm -rf .git
+cd ..
+
+# now add also a resolvable upwards symlink
+ln -s "${UPWARDS_LINK_TARGET}" "foo/${UPWARDS_LINK_PATH}"
+# ...and a resolvable non-upwards symlink pointing to it
+ln -s "${INDIRECT_LINK_TARGET}" "foo/${INDIRECT_LINK_PATH}"
+tar cf "${DISTDIR}/foo-1.2.3_v2.tar" foo \
+ --sort=name --owner=root:0 --group=root:0 --mtime='UTC 1970-01-01' 2>&1
+foocontent_v2=$(git hash-object "${DISTDIR}/foo-1.2.3_v2.tar")
+echo "Foo archive v2 has content ${foocontent_v2}"
+rm -rf foo
+
+###
+# Setup sample repository config
+##
+
+touch ROOT
+cat > repos.json <<EOF
+{ "repositories":
+ { "foo_v1_resolved":
+ { "repository":
+ { "type": "archive"
+ , "content": "${foocontent_v1}"
+ , "fetch": "http://non-existent.example.org/foo-1.2.3_v1.tar"
+ , "subdir": "foo"
+ , "pragma": {"special": "resolve-completely"}
+ }
+ }
+ , "foo_v2_ignore_special":
+ { "repository":
+ { "type": "archive"
+ , "content": "${foocontent_v2}"
+ , "fetch": "http://non-existent.example.org/foo-1.2.3_v2.tar"
+ , "subdir": "foo"
+ , "pragma": {"special": "ignore"}
+ }
+ }
+ , "foo_v2_resolve_partially":
+ { "repository":
+ { "type": "archive"
+ , "content": "${foocontent_v2}"
+ , "fetch": "http://non-existent.example.org/foo-1.2.3_v2.tar"
+ , "subdir": "foo"
+ , "pragma": {"special": "resolve-partially"}
+ }
+ }
+ , "foo_v2_resolve_completely":
+ { "repository":
+ { "type": "archive"
+ , "content": "${foocontent_v2}"
+ , "fetch": "http://non-existent.example.org/foo-1.2.3_v2.tar"
+ , "subdir": "foo"
+ , "pragma": {"special": "resolve-completely"}
+ }
+ }
+ , "":
+ { "repository": {"type": "file", "path": "."}
+ , "bindings":
+ { "foo_v1_resolved": "foo_v1_resolved"
+ , "foo_v2_ignore_special": "foo_v2_ignore_special"
+ , "foo_v2_resolve_partially": "foo_v2_resolve_partially"
+ , "foo_v2_resolve_completely": "foo_v2_resolve_completely"
+ }
+ }
+ }
+}
+EOF
+
+# Compute the repository configuration
+CONF=$("${JUST_MR}" --norc --local-build-root "${LBR}" --distdir "${DISTDIR}" setup)
+cat "${CONF}"
+echo
+
+
+###
+# Test archives with non-upwards symlinks
+##
+
+echo === root with non-upwards symlinks ===
+
+# Read tree from repository configuration
+TREE=$(jq -r '.repositories.foo_v1_resolved.workspace_root[1]' "${CONF}")
+echo Tree is "${TREE}"
+
+# As the tree is known to just (in the git CAS), we should be able to install
+# it with install-cas
+"${JUST}" install-cas --local-build-root "${LBR}" -o "${INSTALL_DIR_RESOLVED}" \
+ "${TREE}::t" 2>&1
+test "$(cat "${INSTALL_DIR_RESOLVED}/${DATA_PATH}")" = "${TEST_DATA}"
+# non-upwards symlink is resolved
+test "$(cat "${INSTALL_DIR_RESOLVED}/${NON_UPWARDS_LINK_PATH}")" = "${TEST_DATA}"
+
+# A resolved tree should add to CAS also its unresolved version; in our case,
+# the unresolved tree has only non-upwards symlinks, so it can be installed
+"${JUST}" install-cas --local-build-root "${LBR}" -o "${INSTALL_DIR_UNRESOLVED}" \
+ "${UNRESOLVED_TREE}::t" 2>&1
+test "$(cat "${INSTALL_DIR_UNRESOLVED}/${DATA_PATH}")" = "${TEST_DATA}"
+test "$(readlink "${INSTALL_DIR_UNRESOLVED}/${NON_UPWARDS_LINK_PATH}")" = "${NON_UPWARDS_LINK_TARGET}"
+
+
+###
+# Test archives with confined symlinks (upwards and non-upwards)
+##
+
+echo === root with ignored special entries ===
+
+# Read tree from repository configuration
+TREE=$(jq -r '.repositories.foo_v2_ignore_special.workspace_root[1]' "${CONF}")
+echo Tree is "${TREE}"
+
+# As the tree is known to just (in the git CAS), we should be able to install
+# it with install-cas
+"${JUST}" install-cas --local-build-root "${LBR}" -o "${INSTALL_DIR_SPECIAL_IGNORE}" \
+ "${TREE}::t" 2>&1
+test "$(cat "${INSTALL_DIR_SPECIAL_IGNORE}/${DATA_PATH}")" = "${TEST_DATA}"
+[ ! -e "${INSTALL_DIR_SPECIAL_IGNORE}/${NON_UPWARDS_LINK_PATH}" ] # symlink should be missing
+[ ! -e "${INSTALL_DIR_SPECIAL_IGNORE}/${UPWARDS_LINK_PATH}" ] # symlink should be missing
+[ ! -e "${INSTALL_DIR_SPECIAL_IGNORE}/${INDIRECT_LINK_PATH}" ] # symlink should be missing
+
+
+echo === root with partially resolved symlinks ===
+
+# Read tree from repository configuration
+TREE=$(jq -r '.repositories.foo_v2_resolve_partially.workspace_root[1]' "${CONF}")
+echo Tree is "${TREE}"
+
+# As the tree is known to just (in the git CAS), we should be able to install
+# it with install-cas
+"${JUST}" install-cas --local-build-root "${LBR}" -o "${INSTALL_DIR_SPECIAL_PARTIAL}" \
+ "${TREE}::t" 2>&1
+test "$(cat "${INSTALL_DIR_SPECIAL_PARTIAL}/${DATA_PATH}")" = "${TEST_DATA}"
+# non-upwards link remains as-is
+test "$(readlink "${INSTALL_DIR_SPECIAL_PARTIAL}/${NON_UPWARDS_LINK_PATH}")" = "${NON_UPWARDS_LINK_TARGET}"
+# upwards link is resolved, in this case to a tree
+[ -d "${INSTALL_DIR_SPECIAL_PARTIAL}/${UPWARDS_LINK_PATH}" ]
+test "$(cat "${INSTALL_DIR_SPECIAL_PARTIAL}/${UPWARDS_LINK_PATH}/data.txt")" = "${TEST_DATA}"
+# indirect link is non-upwards, so it should remain as-is
+test "$(readlink "${INSTALL_DIR_SPECIAL_PARTIAL}/${INDIRECT_LINK_PATH}")" = "${INDIRECT_LINK_TARGET}"
+
+
+echo === root with fully resolved symlinks ===
+
+# Read tree from repository configuration
+TREE=$(jq -r '.repositories.foo_v2_resolve_completely.workspace_root[1]' "${CONF}")
+echo Tree is "${TREE}"
+
+# As the tree is known to just (in the git CAS), we should be able to install
+# it with install-cas
+"${JUST}" install-cas --local-build-root "${LBR}" -o "${INSTALL_DIR_SPECIAL_COMPLETE}" \
+ "${TREE}::t" 2>&1
+test "$(cat "${INSTALL_DIR_SPECIAL_COMPLETE}/${DATA_PATH}")" = "${TEST_DATA}"
+# all links get resolved
+test "$(cat "${INSTALL_DIR_SPECIAL_COMPLETE}/${NON_UPWARDS_LINK_PATH}")" = "${TEST_DATA}"
+[ -d "${INSTALL_DIR_SPECIAL_COMPLETE}/${UPWARDS_LINK_PATH}" ]
+test "$(cat "${INSTALL_DIR_SPECIAL_COMPLETE}/${UPWARDS_LINK_PATH}/data.txt")" = "${TEST_DATA}"
+test "$(cat "${INSTALL_DIR_SPECIAL_COMPLETE}/${INDIRECT_LINK_PATH}")" = "${TEST_DATA}"
+
+echo OK
diff --git a/test/end-to-end/just-mr/install-roots.sh b/test/end-to-end/just-mr/install-roots.sh
index aab0c90b..6ff66401 100644
--- a/test/end-to-end/just-mr/install-roots.sh
+++ b/test/end-to-end/just-mr/install-roots.sh
@@ -20,8 +20,7 @@ readonly JUST="${PWD}/bin/tool-under-test"
readonly JUST_MR="${PWD}/bin/mr-tool-under-test"
readonly DISTDIR="${TEST_TMPDIR}/distfiles"
readonly LBR="${TEST_TMPDIR}/local-build-root"
-readonly INSTALL_DIR_1="${TEST_TMPDIR}/installation-target-1"
-readonly INSTALL_DIR_2="${TEST_TMPDIR}/installation-target-2"
+readonly INSTALL_DIR="${TEST_TMPDIR}/installation-target"
readonly TEST_DATA="The content of the data file in foo"
readonly TEST_PATH="bar/baz"
@@ -51,18 +50,9 @@ cat > repos.json <<EOF
, "subdir": "foo"
}
}
- , "foo_ignore_special":
- { "repository":
- { "type": "archive"
- , "content": "${foocontent}"
- , "fetch": "http://non-existent.example.org/foo-1.2.3.tar"
- , "subdir": "foo"
- , "pragma": {"special": "ignore"}
- }
- }
, "":
{ "repository": {"type": "file", "path": "."}
- , "bindings": {"foo": "foo", "foo_ignore_special": "foo_ignore_special"}
+ , "bindings": {"foo": "foo"}
}
}
}
@@ -73,30 +63,15 @@ CONF=$("${JUST_MR}" --norc --local-build-root "${LBR}" --distdir "${DISTDIR}" se
cat "${CONF}"
echo
-echo === regular root ===
-
# Read tree from repository configuration
TREE=$(jq -r '.repositories.foo.workspace_root[1]' "${CONF}")
echo Tree is "${TREE}"
# As the tree is known to just (in the git CAS), we should be able to install
# it with install-cas
-"${JUST}" install-cas --local-build-root "${LBR}" -o "${INSTALL_DIR_1}" \
- "${TREE}::t" 2>&1
-test "$(cat "${INSTALL_DIR_1}/${TEST_PATH}/data.txt")" = "${TEST_DATA}"
-test "$(readlink "${INSTALL_DIR_1}/${TEST_PATH}/link")" = "${LINK_TARGET}"
-
-echo === ignore_special root ===
-
-# Read tree from repository configuration
-TREE=$(jq -r '.repositories.foo_ignore_special.workspace_root[1]' "${CONF}")
-echo Tree is "${TREE}"
-
-# As the tree is known to just (in the git CAS), we should be able to install
-# it with install-cas
-"${JUST}" install-cas --local-build-root "${LBR}" -o "${INSTALL_DIR_2}" \
+"${JUST}" install-cas --local-build-root "${LBR}" -o "${INSTALL_DIR}" \
"${TREE}::t" 2>&1
-test "$(cat "${INSTALL_DIR_2}/${TEST_PATH}/data.txt")" = "${TEST_DATA}"
-[ ! -e "${INSTALL_DIR_2}/${TEST_PATH}/link" ] # symlink should be missing
+test "$(cat "${INSTALL_DIR}/${TEST_PATH}/data.txt")" = "${TEST_DATA}"
+test "$(readlink "${INSTALL_DIR}/${TEST_PATH}/link")" = "${LINK_TARGET}"
echo OK
diff --git a/test/end-to-end/just-mr/just-mr.test.sh b/test/end-to-end/just-mr/just-mr.test.sh
index cdd0ace4..d82e5309 100644
--- a/test/end-to-end/just-mr/just-mr.test.sh
+++ b/test/end-to-end/just-mr/just-mr.test.sh
@@ -53,10 +53,15 @@ readonly TGZ_REPO_SHA256=$(sha256sum tgz_repo.tar.gz | awk '{print $1}')
readonly TGZ_REPO_SHA512=$(sha512sum tgz_repo.tar.gz | awk '{print $1}')
echo "Set up file repos"
+# add files
mkdir -p "${FILE_ROOT}/test_dir1"
echo test > "${FILE_ROOT}/test_dir1/test_file"
mkdir -p "${FILE_ROOT}/test_dir2/test_dir3"
echo test > "${FILE_ROOT}/test_dir2/test_dir3/test_file"
+# add resolvable non-upwards symlink
+ln -s test_file "${FILE_ROOT}/test_dir1/nonupwards"
+# add resolvable upwards symlink
+ln -s ../test_dir3/test_file "${FILE_ROOT}/test_dir2/test_dir3/upwards"
echo "Set up local git repo"
# NOTE: Libgit2 has no support for Git bundles yet
@@ -67,6 +72,7 @@ mkdir -p foo/bar
echo foo > foo.txt
echo bar > foo/bar.txt
echo baz > foo/bar/baz.txt
+ln -s dummy foo/link
EOF
# set up git repo
(
@@ -122,6 +128,20 @@ cat > test-repos.json <<EOF
, "sha256": "${ZIP_REPO_SHA256}"
, "sha512": "${ZIP_REPO_SHA512}"
, "subdir": "root"
+ , "pragma": {"special": "resolve-partially"}
+ }
+ , "bindings": {"tgz_repo": "tgz_repo", "distdir_repo": "distdir_repo"}
+ }
+ , "zip_repo_resolved":
+ { "repository":
+ { "type": "zip"
+ , "content": "${ZIP_REPO_CONTENT}"
+ , "distfile": "zip_repo.zip"
+ , "fetch": "http://127.0.0.1:${port_num}/zip_repo.zip"
+ , "sha256": "${ZIP_REPO_SHA256}"
+ , "sha512": "${ZIP_REPO_SHA512}"
+ , "subdir": "root"
+ , "pragma": {"special": "resolve-completely"}
}
, "bindings": {"tgz_repo": "tgz_repo", "distdir_repo": "distdir_repo"}
}
@@ -134,6 +154,7 @@ cat > test-repos.json <<EOF
, "sha256": "${TGZ_REPO_SHA256}"
, "sha512": "${TGZ_REPO_SHA512}"
, "subdir": "root/baz"
+ , "pragma": {"special": "ignore"}
}
, "bindings": {"git_repo": "git_repo"}
}
@@ -146,6 +167,16 @@ cat > test-repos.json <<EOF
, "subdir": "foo"
}
}
+ , "git_repo_ignore_special":
+ { "repository":
+ { "type": "git"
+ , "repository": "${GIT_ROOT}"
+ , "branch": "test"
+ , "commit": "${GIT_REPO_COMMIT}"
+ , "subdir": "foo"
+ , "pragma": {"special": "ignore"}
+ }
+ }
, "git_tree_repo":
{ "repository":
{ "type": "git tree"
@@ -153,26 +184,52 @@ cat > test-repos.json <<EOF
, "cmd": ["sh", "${SERVER_ROOT}/bin/git_dir_setup.sh"]
}
}
+ , "git_tree_repo_ignore_special":
+ { "repository":
+ { "type": "git tree"
+ , "id": "${GIT_TREE_ID}"
+ , "cmd": ["sh", "${SERVER_ROOT}/bin/git_dir_setup.sh"]
+ , "pragma": {"special": "ignore"}
+ }
+ }
, "file_repo1":
{ "repository":
{ "type": "file"
, "path": "${FILE_ROOT}/test_dir1"
+ , "pragma": {"to_git": true}
}
}
- , "file_repo2":
+ , "file_repo2_ignore_special":
{ "repository":
{ "type": "file"
, "path": "${FILE_ROOT}/test_dir2"
- , "pragma": {"to_git": true}
+ , "pragma": {"special": "ignore"}
+ }
+ }
+ , "file_repo2_resolve_partially":
+ { "repository":
+ { "type": "file"
+ , "path": "${FILE_ROOT}/test_dir2"
+ , "pragma": {"special": "resolve_partially"}
+ }
+ }
+ , "file_repo2_resolve_completely":
+ { "repository":
+ { "type": "file"
+ , "path": "${FILE_ROOT}/test_dir2"
+ , "pragma": {"special": "resolve_completely"}
}
- , "bindings": {"file_repo1": "file_repo1"}
}
, "distdir_repo":
{ "repository":
{ "type": "distdir"
- , "repositories": ["git_repo", "zip_repo", "file_repo2"]
+ , "repositories": ["git_repo", "zip_repo", "file_repo1"]
+ }
+ , "bindings":
+ { "file_repo2_ignore_special": "file_repo2_ignore_special"
+ , "file_repo2_resolve_partially": "file_repo2_resolve_partially"
+ , "file_repo2_resolve_completely": "file_repo2_resolve_completely"
}
- , "bindings": {"file_repo1": "file_repo1"}
}
}
}