1#!/bin/sh
2
3test_description='Test git update-ref error handling'
4. ./test-lib.sh
5
6# Create some references, perhaps run pack-refs --all, then try to
7# create some more references. Ensure that the second creation fails
8# with the correct error message.
9# Usage: test_update_rejected <before> <pack> <create> <error>
10# <before> is a ws-separated list of refs to create before the test
11# <pack> (true or false) tells whether to pack the refs before the test
12# <create> is a list of variables to attempt creating
13# <error> is a string to look for in the stderr of update-ref.
14# All references are created in the namespace specified by the current
15# value of $prefix.
16test_update_rejected () {
17 before="$1" &&
18 pack="$2" &&
19 create="$3" &&
20 error="$4" &&
21 printf "create $prefix/%s $C\n" $before |
22 git update-ref --stdin &&
23 git for-each-ref $prefix >unchanged &&
24 if $pack
25 then
26 git pack-refs --all
27 fi &&
28 printf "create $prefix/%s $C\n" $create >input &&
29 test_must_fail git update-ref --stdin <input 2>output.err &&
30 grep -F "$error" output.err &&
31 git for-each-ref $prefix >actual &&
32 test_cmp unchanged actual
33}
34
35Q="'"
36
37test_expect_success 'setup' '
38
39 git commit --allow-empty -m Initial &&
40 C=$(git rev-parse HEAD) &&
41 git commit --allow-empty -m Second &&
42 D=$(git rev-parse HEAD) &&
43 git commit --allow-empty -m Third &&
44 E=$(git rev-parse HEAD)
45'
46
47test_expect_success 'existing loose ref is a simple prefix of new' '
48
49 prefix=refs/1l &&
50 test_update_rejected "a c e" false "b c/x d" \
51 "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x$Q"
52
53'
54
55test_expect_success 'existing packed ref is a simple prefix of new' '
56
57 prefix=refs/1p &&
58 test_update_rejected "a c e" true "b c/x d" \
59 "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x$Q"
60
61'
62
63test_expect_success 'existing loose ref is a deeper prefix of new' '
64
65 prefix=refs/2l &&
66 test_update_rejected "a c e" false "b c/x/y d" \
67 "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x/y$Q"
68
69'
70
71test_expect_success 'existing packed ref is a deeper prefix of new' '
72
73 prefix=refs/2p &&
74 test_update_rejected "a c e" true "b c/x/y d" \
75 "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x/y$Q"
76
77'
78
79test_expect_success 'new ref is a simple prefix of existing loose' '
80
81 prefix=refs/3l &&
82 test_update_rejected "a c/x e" false "b c d" \
83 "$Q$prefix/c/x$Q exists; cannot create $Q$prefix/c$Q"
84
85'
86
87test_expect_success 'new ref is a simple prefix of existing packed' '
88
89 prefix=refs/3p &&
90 test_update_rejected "a c/x e" true "b c d" \
91 "$Q$prefix/c/x$Q exists; cannot create $Q$prefix/c$Q"
92
93'
94
95test_expect_success 'new ref is a deeper prefix of existing loose' '
96
97 prefix=refs/4l &&
98 test_update_rejected "a c/x/y e" false "b c d" \
99 "$Q$prefix/c/x/y$Q exists; cannot create $Q$prefix/c$Q"
100
101'
102
103test_expect_success 'new ref is a deeper prefix of existing packed' '
104
105 prefix=refs/4p &&
106 test_update_rejected "a c/x/y e" true "b c d" \
107 "$Q$prefix/c/x/y$Q exists; cannot create $Q$prefix/c$Q"
108
109'
110
111test_expect_success 'one new ref is a simple prefix of another' '
112
113 prefix=refs/5 &&
114 test_update_rejected "a e" false "b c c/x d" \
115 "cannot process $Q$prefix/c$Q and $Q$prefix/c/x$Q at the same time"
116
117'
118
119test_expect_success 'empty directory should not fool rev-parse' '
120 prefix=refs/e-rev-parse &&
121 git update-ref $prefix/foo $C &&
122 git pack-refs --all &&
123 mkdir -p .git/$prefix/foo/bar/baz &&
124 echo "$C" >expected &&
125 git rev-parse $prefix/foo >actual &&
126 test_cmp expected actual
127'
128
129test_expect_success 'empty directory should not fool for-each-ref' '
130 prefix=refs/e-for-each-ref &&
131 git update-ref $prefix/foo $C &&
132 git for-each-ref $prefix >expected &&
133 git pack-refs --all &&
134 mkdir -p .git/$prefix/foo/bar/baz &&
135 git for-each-ref $prefix >actual &&
136 test_cmp expected actual
137'
138
139test_expect_success 'empty directory should not fool create' '
140 prefix=refs/e-create &&
141 mkdir -p .git/$prefix/foo/bar/baz &&
142 printf "create %s $C\n" $prefix/foo |
143 git update-ref --stdin
144'
145
146test_expect_success 'empty directory should not fool verify' '
147 prefix=refs/e-verify &&
148 git update-ref $prefix/foo $C &&
149 git pack-refs --all &&
150 mkdir -p .git/$prefix/foo/bar/baz &&
151 printf "verify %s $C\n" $prefix/foo |
152 git update-ref --stdin
153'
154
155test_expect_success 'empty directory should not fool 1-arg update' '
156 prefix=refs/e-update-1 &&
157 git update-ref $prefix/foo $C &&
158 git pack-refs --all &&
159 mkdir -p .git/$prefix/foo/bar/baz &&
160 printf "update %s $D\n" $prefix/foo |
161 git update-ref --stdin
162'
163
164test_expect_success 'empty directory should not fool 2-arg update' '
165 prefix=refs/e-update-2 &&
166 git update-ref $prefix/foo $C &&
167 git pack-refs --all &&
168 mkdir -p .git/$prefix/foo/bar/baz &&
169 printf "update %s $D $C\n" $prefix/foo |
170 git update-ref --stdin
171'
172
173test_expect_success 'empty directory should not fool 0-arg delete' '
174 prefix=refs/e-delete-0 &&
175 git update-ref $prefix/foo $C &&
176 git pack-refs --all &&
177 mkdir -p .git/$prefix/foo/bar/baz &&
178 printf "delete %s\n" $prefix/foo |
179 git update-ref --stdin
180'
181
182test_expect_success 'empty directory should not fool 1-arg delete' '
183 prefix=refs/e-delete-1 &&
184 git update-ref $prefix/foo $C &&
185 git pack-refs --all &&
186 mkdir -p .git/$prefix/foo/bar/baz &&
187 printf "delete %s $C\n" $prefix/foo |
188 git update-ref --stdin
189'
190
191# Test various errors when reading the old values of references...
192
193test_expect_success 'missing old value blocks update' '
194 prefix=refs/missing-update &&
195 cat >expected <<-EOF &&
196 fatal: cannot lock ref $Q$prefix/foo$Q: unable to resolve reference $Q$prefix/foo$Q
197 EOF
198 printf "%s\n" "update $prefix/foo $E $D" |
199 test_must_fail git update-ref --stdin 2>output.err &&
200 test_cmp expected output.err
201'
202
203test_expect_success 'incorrect old value blocks update' '
204 prefix=refs/incorrect-update &&
205 git update-ref $prefix/foo $C &&
206 cat >expected <<-EOF &&
207 fatal: cannot lock ref $Q$prefix/foo$Q: is at $C but expected $D
208 EOF
209 printf "%s\n" "update $prefix/foo $E $D" |
210 test_must_fail git update-ref --stdin 2>output.err &&
211 test_cmp expected output.err
212'
213
214test_expect_success 'existing old value blocks create' '
215 prefix=refs/existing-create &&
216 git update-ref $prefix/foo $C &&
217 cat >expected <<-EOF &&
218 fatal: cannot lock ref $Q$prefix/foo$Q: reference already exists
219 EOF
220 printf "%s\n" "create $prefix/foo $E" |
221 test_must_fail git update-ref --stdin 2>output.err &&
222 test_cmp expected output.err
223'
224
225test_expect_success 'incorrect old value blocks delete' '
226 prefix=refs/incorrect-delete &&
227 git update-ref $prefix/foo $C &&
228 cat >expected <<-EOF &&
229 fatal: cannot lock ref $Q$prefix/foo$Q: is at $C but expected $D
230 EOF
231 printf "%s\n" "delete $prefix/foo $D" |
232 test_must_fail git update-ref --stdin 2>output.err &&
233 test_cmp expected output.err
234'
235
236test_expect_success 'missing old value blocks indirect update' '
237 prefix=refs/missing-indirect-update &&
238 git symbolic-ref $prefix/symref $prefix/foo &&
239 cat >expected <<-EOF &&
240 fatal: cannot lock ref $Q$prefix/symref$Q: unable to resolve reference $Q$prefix/foo$Q
241 EOF
242 printf "%s\n" "update $prefix/symref $E $D" |
243 test_must_fail git update-ref --stdin 2>output.err &&
244 test_cmp expected output.err
245'
246
247test_expect_success 'incorrect old value blocks indirect update' '
248 prefix=refs/incorrect-indirect-update &&
249 git symbolic-ref $prefix/symref $prefix/foo &&
250 git update-ref $prefix/foo $C &&
251 cat >expected <<-EOF &&
252 fatal: cannot lock ref $Q$prefix/symref$Q: is at $C but expected $D
253 EOF
254 printf "%s\n" "update $prefix/symref $E $D" |
255 test_must_fail git update-ref --stdin 2>output.err &&
256 test_cmp expected output.err
257'
258
259test_expect_success 'existing old value blocks indirect create' '
260 prefix=refs/existing-indirect-create &&
261 git symbolic-ref $prefix/symref $prefix/foo &&
262 git update-ref $prefix/foo $C &&
263 cat >expected <<-EOF &&
264 fatal: cannot lock ref $Q$prefix/symref$Q: reference already exists
265 EOF
266 printf "%s\n" "create $prefix/symref $E" |
267 test_must_fail git update-ref --stdin 2>output.err &&
268 test_cmp expected output.err
269'
270
271test_expect_success 'incorrect old value blocks indirect delete' '
272 prefix=refs/incorrect-indirect-delete &&
273 git symbolic-ref $prefix/symref $prefix/foo &&
274 git update-ref $prefix/foo $C &&
275 cat >expected <<-EOF &&
276 fatal: cannot lock ref $Q$prefix/symref$Q: is at $C but expected $D
277 EOF
278 printf "%s\n" "delete $prefix/symref $D" |
279 test_must_fail git update-ref --stdin 2>output.err &&
280 test_cmp expected output.err
281'
282
283test_expect_success 'missing old value blocks indirect no-deref update' '
284 prefix=refs/missing-noderef-update &&
285 git symbolic-ref $prefix/symref $prefix/foo &&
286 cat >expected <<-EOF &&
287 fatal: cannot lock ref $Q$prefix/symref$Q: reference is missing but expected $D
288 EOF
289 printf "%s\n" "option no-deref" "update $prefix/symref $E $D" |
290 test_must_fail git update-ref --stdin 2>output.err &&
291 test_cmp expected output.err
292'
293
294test_expect_success 'incorrect old value blocks indirect no-deref update' '
295 prefix=refs/incorrect-noderef-update &&
296 git symbolic-ref $prefix/symref $prefix/foo &&
297 git update-ref $prefix/foo $C &&
298 cat >expected <<-EOF &&
299 fatal: cannot lock ref $Q$prefix/symref$Q: is at $C but expected $D
300 EOF
301 printf "%s\n" "option no-deref" "update $prefix/symref $E $D" |
302 test_must_fail git update-ref --stdin 2>output.err &&
303 test_cmp expected output.err
304'
305
306test_expect_success 'existing old value blocks indirect no-deref create' '
307 prefix=refs/existing-noderef-create &&
308 git symbolic-ref $prefix/symref $prefix/foo &&
309 git update-ref $prefix/foo $C &&
310 cat >expected <<-EOF &&
311 fatal: cannot lock ref $Q$prefix/symref$Q: reference already exists
312 EOF
313 printf "%s\n" "option no-deref" "create $prefix/symref $E" |
314 test_must_fail git update-ref --stdin 2>output.err &&
315 test_cmp expected output.err
316'
317
318test_expect_success 'incorrect old value blocks indirect no-deref delete' '
319 prefix=refs/incorrect-noderef-delete &&
320 git symbolic-ref $prefix/symref $prefix/foo &&
321 git update-ref $prefix/foo $C &&
322 cat >expected <<-EOF &&
323 fatal: cannot lock ref $Q$prefix/symref$Q: is at $C but expected $D
324 EOF
325 printf "%s\n" "option no-deref" "delete $prefix/symref $D" |
326 test_must_fail git update-ref --stdin 2>output.err &&
327 test_cmp expected output.err
328'
329
330test_expect_success 'non-empty directory blocks create' '
331 prefix=refs/ne-create &&
332 mkdir -p .git/$prefix/foo/bar &&
333 : >.git/$prefix/foo/bar/baz.lock &&
334 test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" &&
335 cat >expected <<-EOF &&
336 fatal: cannot lock ref $Q$prefix/foo$Q: there is a non-empty directory $Q.git/$prefix/foo$Q blocking reference $Q$prefix/foo$Q
337 EOF
338 printf "%s\n" "update $prefix/foo $C" |
339 test_must_fail git update-ref --stdin 2>output.err &&
340 test_cmp expected output.err &&
341 cat >expected <<-EOF &&
342 fatal: cannot lock ref $Q$prefix/foo$Q: unable to resolve reference $Q$prefix/foo$Q
343 EOF
344 printf "%s\n" "update $prefix/foo $D $C" |
345 test_must_fail git update-ref --stdin 2>output.err &&
346 test_cmp expected output.err
347'
348
349test_expect_success 'broken reference blocks create' '
350 prefix=refs/broken-create &&
351 mkdir -p .git/$prefix &&
352 echo "gobbledigook" >.git/$prefix/foo &&
353 test_when_finished "rm -f .git/$prefix/foo" &&
354 cat >expected <<-EOF &&
355 fatal: cannot lock ref $Q$prefix/foo$Q: unable to resolve reference $Q$prefix/foo$Q: reference broken
356 EOF
357 printf "%s\n" "update $prefix/foo $C" |
358 test_must_fail git update-ref --stdin 2>output.err &&
359 test_cmp expected output.err &&
360 cat >expected <<-EOF &&
361 fatal: cannot lock ref $Q$prefix/foo$Q: unable to resolve reference $Q$prefix/foo$Q: reference broken
362 EOF
363 printf "%s\n" "update $prefix/foo $D $C" |
364 test_must_fail git update-ref --stdin 2>output.err &&
365 test_cmp expected output.err
366'
367
368test_expect_success 'non-empty directory blocks indirect create' '
369 prefix=refs/ne-indirect-create &&
370 git symbolic-ref $prefix/symref $prefix/foo &&
371 mkdir -p .git/$prefix/foo/bar &&
372 : >.git/$prefix/foo/bar/baz.lock &&
373 test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" &&
374 cat >expected <<-EOF &&
375 fatal: cannot lock ref $Q$prefix/symref$Q: there is a non-empty directory $Q.git/$prefix/foo$Q blocking reference $Q$prefix/foo$Q
376 EOF
377 printf "%s\n" "update $prefix/symref $C" |
378 test_must_fail git update-ref --stdin 2>output.err &&
379 test_cmp expected output.err &&
380 cat >expected <<-EOF &&
381 fatal: cannot lock ref $Q$prefix/symref$Q: unable to resolve reference $Q$prefix/foo$Q
382 EOF
383 printf "%s\n" "update $prefix/symref $D $C" |
384 test_must_fail git update-ref --stdin 2>output.err &&
385 test_cmp expected output.err
386'
387
388test_expect_success 'broken reference blocks indirect create' '
389 prefix=refs/broken-indirect-create &&
390 git symbolic-ref $prefix/symref $prefix/foo &&
391 echo "gobbledigook" >.git/$prefix/foo &&
392 test_when_finished "rm -f .git/$prefix/foo" &&
393 cat >expected <<-EOF &&
394 fatal: cannot lock ref $Q$prefix/symref$Q: unable to resolve reference $Q$prefix/foo$Q: reference broken
395 EOF
396 printf "%s\n" "update $prefix/symref $C" |
397 test_must_fail git update-ref --stdin 2>output.err &&
398 test_cmp expected output.err &&
399 cat >expected <<-EOF &&
400 fatal: cannot lock ref $Q$prefix/symref$Q: unable to resolve reference $Q$prefix/foo$Q: reference broken
401 EOF
402 printf "%s\n" "update $prefix/symref $D $C" |
403 test_must_fail git update-ref --stdin 2>output.err &&
404 test_cmp expected output.err
405'
406
407test_expect_success 'no bogus intermediate values during delete' '
408 prefix=refs/slow-transaction &&
409 # Set up a reference with differing loose and packed versions:
410 git update-ref $prefix/foo $C &&
411 git pack-refs --all &&
412 git update-ref $prefix/foo $D &&
413 git for-each-ref $prefix >unchanged &&
414 # Now try to update the reference, but hold the `packed-refs` lock
415 # for a while to see what happens while the process is blocked:
416 : >.git/packed-refs.lock &&
417 test_when_finished "rm -f .git/packed-refs.lock" &&
418 {
419 # Note: the following command is intentionally run in the
420 # background. We increase the timeout so that `update-ref`
421 # attempts to acquire the `packed-refs` lock for longer than
422 # it takes for us to do the check then delete it:
423 git -c core.packedrefstimeout=3000 update-ref -d $prefix/foo &
424 } &&
425 pid2=$! &&
426 # Give update-ref plenty of time to get to the point where it tries
427 # to lock packed-refs:
428 sleep 1 &&
429 # Make sure that update-ref did not complete despite the lock:
430 kill -0 $pid2 &&
431 # Verify that the reference still has its old value:
432 sha1=$(git rev-parse --verify --quiet $prefix/foo || echo undefined) &&
433 case "$sha1" in
434 $D)
435 # This is what we hope for; it means that nothing
436 # user-visible has changed yet.
437 : ;;
438 undefined)
439 # This is not correct; it means the deletion has happened
440 # already even though update-ref should not have been
441 # able to acquire the lock yet.
442 echo "$prefix/foo deleted prematurely" &&
443 break
444 ;;
445 $C)
446 # This value should never be seen. Probably the loose
447 # reference has been deleted but the packed reference
448 # is still there:
449 echo "$prefix/foo incorrectly observed to be C" &&
450 break
451 ;;
452 *)
453 # WTF?
454 echo "unexpected value observed for $prefix/foo: $sha1" &&
455 break
456 ;;
457 esac >out &&
458 rm -f .git/packed-refs.lock &&
459 wait $pid2 &&
460 test_must_be_empty out &&
461 test_must_fail git rev-parse --verify --quiet $prefix/foo
462'
463
464test_expect_success 'delete fails cleanly if packed-refs file is locked' '
465 prefix=refs/locked-packed-refs &&
466 # Set up a reference with differing loose and packed versions:
467 git update-ref $prefix/foo $C &&
468 git pack-refs --all &&
469 git update-ref $prefix/foo $D &&
470 git for-each-ref $prefix >unchanged &&
471 # Now try to delete it while the `packed-refs` lock is held:
472 : >.git/packed-refs.lock &&
473 test_when_finished "rm -f .git/packed-refs.lock" &&
474 test_must_fail git update-ref -d $prefix/foo >out 2>err &&
475 git for-each-ref $prefix >actual &&
476 test_i18ngrep "Unable to create $Q.*packed-refs.lock$Q: File exists" err &&
477 test_cmp unchanged actual
478'
479
480test_done