From 71039fb9d562731ed700ef072b6fcb18e2478361 Mon Sep 17 00:00:00 2001 From: Clemens Buchacher Date: Sat, 7 Jan 2012 12:42:45 +0100 Subject: git-daemon: add tests The semantics of the git daemon tests are similar to the http transport tests. In fact, they are only a slightly modified copy of t5550, plus the newly added remote error tests. All git-daemon tests will be skipped unless the environment variable GIT_TEST_GIT_DAEMON is set. Signed-off-by: Clemens Buchacher Helped-by: Jeff King Signed-off-by: Junio C Hamano --- t/lib-git-daemon.sh | 53 ++++++++++++++++++ t/t5570-git-daemon.sh | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+) create mode 100644 t/lib-git-daemon.sh create mode 100755 t/t5570-git-daemon.sh diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh new file mode 100644 index 000000000..5e81a2594 --- /dev/null +++ b/t/lib-git-daemon.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +if test -z "$GIT_TEST_GIT_DAEMON" +then + skip_all="git-daemon testing disabled (define GIT_TEST_GIT_DAEMON to enable)" + test_done +fi + +LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-'8121'} + +GIT_DAEMON_PID= +GIT_DAEMON_DOCUMENT_ROOT_PATH="$PWD"/repo +GIT_DAEMON_URL=git://127.0.0.1:$LIB_GIT_DAEMON_PORT + +start_git_daemon() { + if test -n "$GIT_DAEMON_PID" + then + error "start_git_daemon already called" + fi + + mkdir -p "$GIT_DAEMON_DOCUMENT_ROOT_PATH" + + trap 'code=$?; stop_git_daemon; (exit $code); die' EXIT + + say >&3 "Starting git daemon ..." + git daemon --listen=127.0.0.1 --port="$LIB_GIT_DAEMON_PORT" \ + --reuseaddr --verbose \ + --base-path="$GIT_DAEMON_DOCUMENT_ROOT_PATH" \ + "$@" "$GIT_DAEMON_DOCUMENT_ROOT_PATH" \ + >&3 2>&4 & + GIT_DAEMON_PID=$! +} + +stop_git_daemon() { + if test -z "$GIT_DAEMON_PID" + then + return + fi + + trap 'die' EXIT + + # kill git-daemon child of git + say >&3 "Stopping git daemon ..." + kill "$GIT_DAEMON_PID" + wait "$GIT_DAEMON_PID" >&3 2>&4 + ret=$? + # expect exit with status 143 = 128+15 for signal TERM=15 + if test $ret -ne 143 + then + error "git daemon exited with status: $ret" + fi + GIT_DAEMON_PID= +} diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh new file mode 100755 index 000000000..7cbc9994a --- /dev/null +++ b/t/t5570-git-daemon.sh @@ -0,0 +1,148 @@ +#!/bin/sh + +test_description='test fetching over git protocol' +. ./test-lib.sh + +LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-5570} +. "$TEST_DIRECTORY"/lib-git-daemon.sh +start_git_daemon + +test_expect_success 'setup repository' ' + echo content >file && + git add file && + git commit -m one +' + +test_expect_success 'create git-accessible bare repository' ' + mkdir "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" && + (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" && + git --bare init && + : >git-daemon-export-ok + ) && + git remote add public "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" && + git push public master:master +' + +test_expect_success 'clone git repository' ' + git clone "$GIT_DAEMON_URL/repo.git" clone && + test_cmp file clone/file +' + +test_expect_success 'fetch changes via git protocol' ' + echo content >>file && + git commit -a -m two && + git push public && + (cd clone && git pull) && + test_cmp file clone/file +' + +test_expect_failure 'remote detects correct HEAD' ' + git push public master:other && + (cd clone && + git remote set-head -d origin && + git remote set-head -a origin && + git symbolic-ref refs/remotes/origin/HEAD > output && + echo refs/remotes/origin/master > expect && + test_cmp expect output + ) +' + +test_expect_success 'prepare pack objects' ' + cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git && + (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git && + git --bare repack -a -d + ) +' + +test_expect_success 'fetch notices corrupt pack' ' + cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git && + (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git && + p=`ls objects/pack/pack-*.pack` && + chmod u+w $p && + printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc + ) && + mkdir repo_bad1.git && + (cd repo_bad1.git && + git --bare init && + test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad1.git" && + test 0 = `ls objects/pack/pack-*.pack | wc -l` + ) +' + +test_expect_success 'fetch notices corrupt idx' ' + cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git && + (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git && + p=`ls objects/pack/pack-*.idx` && + chmod u+w $p && + printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc + ) && + mkdir repo_bad2.git && + (cd repo_bad2.git && + git --bare init && + test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad2.git" && + test 0 = `ls objects/pack | wc -l` + ) +' + +test_remote_error() +{ + do_export=YesPlease + while test $# -gt 0 + do + case $1 in + -x) + shift + chmod -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" + ;; + -n) + shift + do_export= + ;; + *) + break + esac + done + + if test $# -ne 3 + then + error "invalid number of arguments" + fi + + cmd=$1 + repo=$2 + msg=$3 + + if test -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo" + then + if test -n "$do_export" + then + : >"$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo/git-daemon-export-ok" + else + rm -f "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo/git-daemon-export-ok" + fi + fi + + test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" 2>output && + echo "fatal: remote error: $msg: /$repo" >expect && + test_cmp expect output + ret=$? + chmod +x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" + (exit $ret) +} + +msg="access denied or repository not exported" +test_expect_success 'clone non-existent' "test_remote_error clone nowhere.git '$msg'" +test_expect_success 'push disabled' "test_remote_error push repo.git '$msg'" +test_expect_success 'read access denied' "test_remote_error -x fetch repo.git '$msg'" +test_expect_success 'not exported' "test_remote_error -n fetch repo.git '$msg'" + +stop_git_daemon +start_git_daemon --informative-errors + +test_expect_success 'clone non-existent' "test_remote_error clone nowhere.git 'no such repository'" +test_expect_success 'push disabled' "test_remote_error push repo.git 'service not enabled'" +test_expect_success 'read access denied' "test_remote_error -x fetch repo.git 'no such repository'" +test_expect_success 'not exported' "test_remote_error -n fetch repo.git 'repository not exported'" + +stop_git_daemon +test_done -- cgit v1.2.1 From f6a34cfbb4314105c4dadd88eb42da26aef44dfd Mon Sep 17 00:00:00 2001 From: Clemens Buchacher Date: Sat, 7 Jan 2012 12:42:46 +0100 Subject: git-daemon: produce output when ready If a client tries to connect after git-daemon starts, but before it opens a listening socket, the connection will fail. Output "[PID] Ready to rumble]" after opening the socket successfully in order to inform the user that the daemon is now ready to receive connections. Signed-off-by: Clemens Buchacher Signed-off-by: Junio C Hamano --- daemon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/daemon.c b/daemon.c index 15ce918a2..ab21e66b2 100644 --- a/daemon.c +++ b/daemon.c @@ -1086,6 +1086,8 @@ static int serve(struct string_list *listen_addr, int listen_port, drop_privileges(cred); + loginfo("Ready to rumble"); + return service_loop(&socklist); } @@ -1270,10 +1272,8 @@ int main(int argc, char **argv) if (inetd_mode || serve_mode) return execute(); - if (detach) { + if (detach) daemonize(); - loginfo("Ready to rumble"); - } else sanitize_stdfds(); -- cgit v1.2.1 From 561b133c2c29ccf5e2aeaa5d6b1da3835e660db8 Mon Sep 17 00:00:00 2001 From: Clemens Buchacher Date: Sat, 7 Jan 2012 12:42:47 +0100 Subject: git-daemon tests: wait until daemon is ready In start_daemon, git-daemon is started as a background process. In theory, the tests may try to connect before the daemon had a chance to open a listening socket. Avoid this race condition by waiting for it to output "Ready to rumble". Any other output is considered an error and the test is aborted. Should git-daemon produce no output at all, lib-git-daemon would block forever. This could be fixed by introducing a timeout. On the other hand, we have no timeout for other git commands which could suffer from the same problem. Since such a mechanism adds some complexity, I have decided against it. Signed-off-by: Clemens Buchacher Signed-off-by: Junio C Hamano --- t/lib-git-daemon.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh index 5e81a2594..ef2d01f36 100644 --- a/t/lib-git-daemon.sh +++ b/t/lib-git-daemon.sh @@ -23,12 +23,27 @@ start_git_daemon() { trap 'code=$?; stop_git_daemon; (exit $code); die' EXIT say >&3 "Starting git daemon ..." + mkfifo git_daemon_output git daemon --listen=127.0.0.1 --port="$LIB_GIT_DAEMON_PORT" \ --reuseaddr --verbose \ --base-path="$GIT_DAEMON_DOCUMENT_ROOT_PATH" \ "$@" "$GIT_DAEMON_DOCUMENT_ROOT_PATH" \ - >&3 2>&4 & + >&3 2>git_daemon_output & GIT_DAEMON_PID=$! + { + read line + echo >&4 "$line" + cat >&4 & + + # Check expected output + if test x"$(expr "$line" : "\[[0-9]*\] \(.*\)")" != x"Ready to rumble" + then + kill "$GIT_DAEMON_PID" + wait "$GIT_DAEMON_PID" + trap 'die' EXIT + error "git daemon failed to start" + fi + }