about summary refs log tree commit diff
path: root/t/t9164-git-svn-dcommit-concurrent.sh
blob: 90346ff4e92ac06d6ca9fd8ea7b5b7d4f1f7f374 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#!/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