-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Cathy J. Fitzpatrick <[email protected]> Signed-off-by: Sean Whitton <[email protected]>
- Loading branch information
Showing
1 changed file
with
223 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
#!/usr/bin/env bash | ||
# SPDX-FileCopyrightText: Copyright 2023 Cathy J. Fitzpatrick <[email protected]> | ||
# SPDX-License-Identifier: GPL-2.0-or-later | ||
set -efuC -o pipefail | ||
shopt -s inherit_errexit | ||
|
||
# Unlike the main git-remote-gcrypt program, this testing script requires bash | ||
# (rather than POSIX sh) and also depends on various common system utilities | ||
# that the git-remote-gcrypt carefully avoids using (such as mktemp(1)). | ||
# | ||
# The test proceeds by setting up a new repository, making some large commits | ||
# with random data into the repository, pushing the repository to another | ||
# remote using git-remote-gcrypt over the gitception protocol, and then cloning | ||
# the second repository and ensuring that the data it contains is correct. | ||
# | ||
# The random data is obtained from /dev/urandom. This script won't work | ||
# on systems that don't provide /dev/urandom. | ||
# | ||
# The following settings specify the parameters to be used for the test. | ||
num_commits=5 | ||
files_per_commit=3 | ||
random_source="/dev/urandom" | ||
random_data_per_file=5242880 # 5 MiB | ||
default_branch="main" | ||
test_user_name="git-remote-gcrypt" | ||
test_user_email="[email protected]" | ||
pack_size_limit="12m" # If this variable is unset, there is no size limit. | ||
|
||
readonly num_commits files_per_commit random_source random_data_per_file \ | ||
default_branch test_user_name test_user_email pack_size_limit | ||
|
||
# Pipe text into this function to indent it with four spaces. This is used | ||
# to make the output of this script prettier. | ||
indent() { | ||
sed 's/^\(.*\)$/ \1/' | ||
} | ||
|
||
section_break() { | ||
echo | ||
printf '*%.0s' {1..70} | ||
echo $'\n' | ||
} | ||
|
||
assert() { | ||
(set +e; [[ -n ${show_command:-} ]] && set -x; "${@}") | ||
local -r status=${?} | ||
{ [[ ${status} -eq 0 ]] && echo "Verification succeeded."; } || \ | ||
echo "Verification failed." | ||
return "${status}" | ||
} | ||
|
||
fastfail() { | ||
"$@" || kill -- "-$$" | ||
} | ||
|
||
umask 077 | ||
tempdir=$(mktemp -d) | ||
readonly tempdir | ||
# shellcheck disable=SC2064 | ||
trap "rm -Rf -- '${tempdir}'" EXIT | ||
|
||
# Set up the PATH to favor the version of git-remote-gcrypt from the repository | ||
# rather than a version that might already be installed on the user's system. | ||
PATH=$(git rev-parse --show-toplevel):${PATH} | ||
readonly PATH | ||
export PATH | ||
|
||
# Unset any GIT_ environment variables to prevent them from affecting the test. | ||
git_env=$(env | sed -n 's/^\(GIT_[^=]*\)=.*$/\1/p') | ||
# shellcheck disable=SC2086 | ||
IFS=$'\n' unset ${git_env} | ||
|
||
# Ensure a predictable gpg configuration. | ||
export GNUPGHOME="${tempdir}/gpg" | ||
mkdir "${GNUPGHOME}" | ||
# Use a wrapper for gpg(1) to avoid cluttering the test output with unnecessary | ||
# warnings about the obsolete `--secret-keyring` option. These warnings are | ||
# caused by git-remote-gcrypt passing an option to gpg(1) that only makes sense | ||
# for ancient versions of gpg(1), but addressing that (if it should be | ||
# addressed at all) is a task best left for another day. | ||
cat << 'EOF' > "${GNUPGHOME}/gpg" | ||
#!/usr/bin/env bash | ||
set -efuC -o pipefail; shopt -s inherit_errexit | ||
args=( "${@}" ) | ||
for ((i = 0; i < ${#}; ++i)); do | ||
if [[ ${args[${i}]} = "--secret-keyring" ]]; then | ||
unset "args[${i}]" "args[$(( i + 1 ))]" | ||
break | ||
fi | ||
done | ||
exec gpg "${args[@]}" | ||
EOF | ||
chmod +x "${GNUPGHOME}/gpg" | ||
|
||
# Ensure a predictable git configuration. | ||
export GIT_CONFIG_SYSTEM=/dev/null | ||
export GIT_CONFIG_GLOBAL="${tempdir}/gitconfig" | ||
mkdir "${tempdir}/template" # Intentionally empty template directory. | ||
git config --global init.defaultBranch "${default_branch}" | ||
git config --global user.name "${test_user_name}" | ||
git config --global user.email "${test_user_email}" | ||
git config --global init.templateDir "${tempdir}/template" | ||
git config --global gpg.program "${GNUPGHOME}/gpg" | ||
[[ -n ${pack_size_limit:-} ]] && \ | ||
git config --global pack.packSizeLimit "${pack_size_limit}" | ||
|
||
# Prepare the random data that we'll be writing to the repository. | ||
total_files=$(( num_commits * files_per_commit )) | ||
random_data_size=$(( total_files * random_data_per_file )) | ||
random_data_file="${tempdir}/data" | ||
head -c "${random_data_size}" "${random_source}" > "${random_data_file}" | ||
|
||
# Create gpg key and subkey. | ||
echo "Step 1: Creating a new GPG key and subkey to use for testing:" | ||
( | ||
set -x | ||
gpg --batch --passphrase "" --quick-generate-key \ | ||
"${test_user_name} <${test_user_email}>" | ||
gpg -K | ||
) 2>&1 | indent | ||
|
||
### | ||
section_break | ||
|
||
echo "Step 2: Creating new repository with random data:" | ||
{ | ||
git init -- "${tempdir}/first" | ||
cd "${tempdir}/first" | ||
for ((i = 0; i < num_commits; ++i)); do | ||
for ((j = 0; j < files_per_commit; ++j)); do | ||
file_index=$(( i * files_per_commit + j )) | ||
random_data_index=$(( file_index * random_data_per_file )) | ||
# shellcheck disable=SC2016 | ||
echo "Writing random file $((file_index + 1))/${total_files}:" \ | ||
'${tempdir}'/"first/$(( file_index )).data " | ||
head -c "${random_data_per_file}" > "$(( file_index )).data" < \ | ||
<(tail -c "+${random_data_index}" "${random_data_file}" || :) | ||
if command -v base64 > /dev/null; then | ||
# shellcheck disable=SC2312 | ||
echo "First 24 bytes in base64:" \ | ||
"$(fastfail head -c 24 "$(( file_index )).data" | \ | ||
fastfail base64)" | indent | ||
fi | ||
done | ||
git add -- "${tempdir}/first" | ||
git commit -m "Commit #${i}" | ||
done | ||
|
||
echo | ||
echo "For reference, here is the commit log for the repository:" | ||
git log --format=oneline | indent | ||
} | indent | ||
|
||
### | ||
section_break | ||
|
||
echo "Step 3: Creating an empty bare repository to receive pushed data:" | ||
git init --bare -- "${tempdir}/second.git" | indent | ||
|
||
|
||
### | ||
section_break | ||
|
||
echo "Step 4: Pushing the first repository to the second one using gitception:" | ||
{ | ||
# Note that when pushing to a bare local repository, git-remote-gcrypt uses | ||
# gitception, rather than treating the remote as a local repository. | ||
( | ||
set -x | ||
cd "${tempdir}/first" | ||
git push -f "gcrypt::${tempdir}/second.git#${default_branch}" \ | ||
"${default_branch}" | ||
) 2>&1 | ||
|
||
if command -v tree > /dev/null; then | ||
echo | ||
echo "For reference, here is the directory tree of second.git:" | ||
tree "${tempdir}/second.git" | ||
fi | ||
|
||
echo | ||
echo "Here is the size of each object file in second.git:" | ||
( | ||
cd "${tempdir}/second.git/objects" | ||
find . -type f -exec du -sh {} + | ||
) | indent | ||
|
||
echo | ||
echo "Note that git-pack-objects(1) will try to ensure that each object is" | ||
echo "smaller than pack.packSizeLimit (${pack_size_limit:-unlimited}" \ | ||
"here) but this isn't always" | ||
echo "possible because each object contains at least one of our random" | ||
echo "files, and each random file has a certain minimum size. As a result," | ||
echo "pack.packSizeLimit is more of a suggestion than a hard limit." | ||
} | indent | ||
|
||
### | ||
section_break | ||
|
||
echo "Step 5: Cloning the second repository using gitception:" | ||
{ | ||
( | ||
set -x | ||
git clone -b "${default_branch}" \ | ||
"gcrypt::${tempdir}/second.git#${default_branch}" -- \ | ||
"${tempdir}/third" | ||
) 2>&1 | ||
|
||
echo | ||
echo "Verifying that the first and third repositories have the same" | ||
echo "commit log as each other:" | ||
# shellcheck disable=SC2312 | ||
assert diff \ | ||
<(fastfail cd "${tempdir}/first"; fastfail git log --oneline) \ | ||
<(fastfail cd "${tempdir}/third"; fastfail git log --oneline) \ | ||
2>&1 | indent | ||
|
||
echo | ||
echo "Verifying that the first and third repositories have the same" | ||
echo "files in their respective working directories:" | ||
show_command=1 assert diff -r --exclude ".git" -- \ | ||
"${tempdir}/first" "${tempdir}/third" 2>&1 | indent | ||
} | indent |