Skip to content

Commit

Permalink
New integration test for gitception
Browse files Browse the repository at this point in the history
Signed-off-by: Cathy J. Fitzpatrick <[email protected]>
Signed-off-by: Sean Whitton <[email protected]>
  • Loading branch information
cathyjf authored and spwhitton committed Dec 29, 2024
1 parent ceba115 commit 2138270
Showing 1 changed file with 223 additions and 0 deletions.
223 changes: 223 additions & 0 deletions tests/system-test.sh
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

0 comments on commit 2138270

Please sign in to comment.