|  | #!/bin/sh | 
|  | # | 
|  | # Copyright (c) 2012 Robert Luberda | 
|  | # | 
|  |  | 
|  | test_description='concurrent git svn dcommit' | 
|  | . ./lib-git-svn.sh | 
|  |  | 
|  |  | 
|  |  | 
|  | test_expect_success 'setup svn repository' ' | 
|  | svn_cmd checkout "$svnrepo" work.svn && | 
|  | ( | 
|  | cd work.svn && | 
|  | echo >file && echo > auto_updated_file | 
|  | svn_cmd add file auto_updated_file && | 
|  | svn_cmd commit -m "initial commit" | 
|  | ) && | 
|  | svn_cmd checkout "$svnrepo" work-auto-commits.svn | 
|  | ' | 
|  | N=0 | 
|  | next_N() | 
|  | { | 
|  | N=$(( $N + 1 )) | 
|  | } | 
|  |  | 
|  | # Setup SVN repository hooks to emulate SVN failures or concurrent commits | 
|  | # The function adds | 
|  | # either pre-commit  hook, which causes SVN commit given in second argument | 
|  | #                    to fail | 
|  | # or     post-commit hook, which creates a new commit (a new line added to | 
|  | #                    auto_updated_file) after given SVN commit | 
|  | # The first argument contains a type of the hook | 
|  | # The second argument contains a number (not SVN revision) of commit | 
|  | # the hook should be applied for (each time the hook is run, the given | 
|  | # number is decreased by one until it gets 0, in which case the hook | 
|  | # will execute its real action) | 
|  | setup_hook() | 
|  | { | 
|  | hook_type="$1"  # "pre-commit" or "post-commit" | 
|  | skip_revs="$2" | 
|  | [ "$hook_type" = "pre-commit" ] || | 
|  | [ "$hook_type" = "post-commit" ] || | 
|  | { echo "ERROR: invalid argument ($hook_type)" \ | 
|  | "passed to setup_hook" >&2 ; return 1; } | 
|  | echo "cnt=$skip_revs" > "$hook_type-counter" | 
|  | rm -f "$rawsvnrepo/hooks/"*-commit # drop previous hooks | 
|  | hook="$rawsvnrepo/hooks/$hook_type" | 
|  | cat > "$hook" <<- 'EOF1' | 
|  | #!/bin/sh | 
|  | set -e | 
|  | cd "$1/.."  # "$1" is repository location | 
|  | exec >> svn-hook.log 2>&1 | 
|  | hook="$(basename "$0")" | 
|  | echo "*** Executing $hook $@" | 
|  | set -x | 
|  | . ./$hook-counter | 
|  | cnt="$(($cnt - 1))" | 
|  | echo "cnt=$cnt" > ./$hook-counter | 
|  | [ "$cnt" = "0" ] || exit 0 | 
|  | EOF1 | 
|  | if [ "$hook_type" = "pre-commit" ]; then | 
|  | echo "echo 'commit disallowed' >&2; exit 1" >>"$hook" | 
|  | else | 
|  | echo "PATH=\"$PATH\"; export PATH" >>"$hook" | 
|  | echo "svnconf=\"$svnconf\"" >>"$hook" | 
|  | cat >>"$hook" <<- 'EOF2' | 
|  | cd work-auto-commits.svn | 
|  | svn up --config-dir "$svnconf" | 
|  | echo "$$" >> auto_updated_file | 
|  | svn commit --config-dir "$svnconf" \ | 
|  | -m "auto-committing concurrent change" | 
|  | exit 0 | 
|  | EOF2 | 
|  | fi | 
|  | chmod 755 "$hook" | 
|  | } | 
|  |  | 
|  | check_contents() | 
|  | { | 
|  | gitdir="$1" | 
|  | (cd ../work.svn && svn_cmd up) && | 
|  | test_cmp file ../work.svn/file && | 
|  | test_cmp auto_updated_file ../work.svn/auto_updated_file | 
|  | } | 
|  |  | 
|  | test_expect_success 'check if post-commit hook creates a concurrent commit' ' | 
|  | setup_hook post-commit 1 && | 
|  | ( | 
|  | cd work.svn && | 
|  | cp auto_updated_file au_file_saved && | 
|  | echo 1 >> file && | 
|  | svn_cmd commit -m "changing file" && | 
|  | svn_cmd up && | 
|  | test_must_fail test_cmp auto_updated_file au_file_saved | 
|  | ) | 
|  | ' | 
|  |  | 
|  | test_expect_success 'check if pre-commit hook fails' ' | 
|  | setup_hook pre-commit 2 && | 
|  | ( | 
|  | cd work.svn && | 
|  | echo 2 >> file && | 
|  | svn_cmd commit -m "changing file once again" && | 
|  | echo 3 >> file && | 
|  | test_must_fail svn_cmd commit -m "this commit should fail" && | 
|  | svn_cmd revert file | 
|  | ) | 
|  | ' | 
|  |  | 
|  | test_expect_success 'dcommit error handling' ' | 
|  | setup_hook pre-commit 2 && | 
|  | next_N && git svn clone "$svnrepo" work$N.git && | 
|  | ( | 
|  | cd work$N.git && | 
|  | echo 1 >> file && git commit -am "commit change $N.1" && | 
|  | echo 2 >> file && git commit -am "commit change $N.2" && | 
|  | echo 3 >> file && git commit -am "commit change $N.3" && | 
|  | # should fail to dcommit 2nd and 3rd change | 
|  | # but still should leave the repository in reasonable state | 
|  | test_must_fail git svn dcommit && | 
|  | git update-index --refresh && | 
|  | git show HEAD~2   | grep -q git-svn-id && | 
|  | ! git show HEAD~1 | grep -q git-svn-id && | 
|  | ! git show HEAD   | grep -q git-svn-id | 
|  | ) | 
|  | ' | 
|  |  | 
|  | test_expect_success 'dcommit concurrent change in non-changed file' ' | 
|  | setup_hook post-commit 2 && | 
|  | next_N && git svn clone "$svnrepo" work$N.git && | 
|  | ( | 
|  | cd work$N.git && | 
|  | echo 1 >> file && git commit -am "commit change $N.1" && | 
|  | echo 2 >> file && git commit -am "commit change $N.2" && | 
|  | echo 3 >> file && git commit -am "commit change $N.3" && | 
|  | # should rebase and leave the repository in reasonable state | 
|  | git svn dcommit && | 
|  | git update-index --refresh && | 
|  | check_contents && | 
|  | git show HEAD~3 | grep -q git-svn-id && | 
|  | git show HEAD~2 | grep -q git-svn-id && | 
|  | git show HEAD~1 | grep -q auto-committing && | 
|  | git show HEAD   | grep -q git-svn-id | 
|  | ) | 
|  | ' | 
|  |  | 
|  | # An utility function used in the following test | 
|  | delete_first_line() | 
|  | { | 
|  | file="$1" && | 
|  | sed 1d < "$file" > "${file}.tmp" && | 
|  | rm "$file" && | 
|  | mv "${file}.tmp" "$file" | 
|  | } | 
|  |  | 
|  | test_expect_success 'dcommit concurrent non-conflicting change' ' | 
|  | setup_hook post-commit 2 && | 
|  | next_N && git svn clone "$svnrepo" work$N.git && | 
|  | ( | 
|  | cd work$N.git && | 
|  | cat file >> auto_updated_file && | 
|  | git commit -am "commit change $N.1" && | 
|  | delete_first_line auto_updated_file && | 
|  | git commit -am "commit change $N.2" && | 
|  | delete_first_line auto_updated_file && | 
|  | git commit -am "commit change $N.3" && | 
|  | # should rebase and leave the repository in reasonable state | 
|  | git svn dcommit && | 
|  | git update-index --refresh && | 
|  | check_contents && | 
|  | git show HEAD~3 | grep -q git-svn-id && | 
|  | git show HEAD~2 | grep -q git-svn-id && | 
|  | git show HEAD~1 | grep -q auto-committing && | 
|  | git show HEAD   | grep -q git-svn-id | 
|  | ) | 
|  | ' | 
|  |  | 
|  | test_expect_success 'dcommit --no-rebase concurrent non-conflicting change' ' | 
|  | setup_hook post-commit 2 && | 
|  | next_N && git svn clone "$svnrepo" work$N.git && | 
|  | ( | 
|  | cd work$N.git && | 
|  | cat file >> auto_updated_file && | 
|  | git commit -am "commit change $N.1" && | 
|  | delete_first_line auto_updated_file && | 
|  | git commit -am "commit change $N.2" && | 
|  | delete_first_line auto_updated_file && | 
|  | git commit -am "commit change $N.3" && | 
|  | # should fail as rebase is needed | 
|  | test_must_fail git svn dcommit --no-rebase && | 
|  | # but should leave HEAD unchanged | 
|  | git update-index --refresh && | 
|  | ! git show HEAD~2 | grep -q git-svn-id && | 
|  | ! git show HEAD~1 | grep -q git-svn-id && | 
|  | ! git show HEAD   | grep -q git-svn-id | 
|  | ) | 
|  | ' | 
|  |  | 
|  | test_expect_success 'dcommit fails on concurrent conflicting change' ' | 
|  | setup_hook post-commit 1 && | 
|  | next_N && git svn clone "$svnrepo" work$N.git && | 
|  | ( | 
|  | cd work$N.git && | 
|  | echo a >> file && | 
|  | git commit -am "commit change $N.1" && | 
|  | echo b >> auto_updated_file && | 
|  | git commit -am "commit change $N.2" && | 
|  | echo c >> auto_updated_file && | 
|  | git commit -am "commit change $N.3" && | 
|  | test_must_fail git svn dcommit && # rebase should fail | 
|  | test_must_fail git update-index --refresh | 
|  | ) | 
|  | ' | 
|  |  | 
|  | test_done |