]>
Commit | Line | Data |
---|---|---|
102d7154 JC |
1 | #!/bin/sh |
2 | ||
3 | test_description='Test reffiles backend' | |
4 | ||
5 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main | |
6 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME | |
7 | ||
8 | TEST_PASSES_SANITIZE_LEAK=true | |
9 | . ./test-lib.sh | |
10 | ||
11 | if ! test_have_prereq REFFILES | |
12 | then | |
13 | skip_all='skipping reffiles specific tests' | |
14 | test_done | |
15 | fi | |
16 | ||
17 | test_expect_success 'setup' ' | |
18 | git commit --allow-empty -m Initial && | |
19 | C=$(git rev-parse HEAD) && | |
20 | git commit --allow-empty -m Second && | |
21 | D=$(git rev-parse HEAD) && | |
22 | git commit --allow-empty -m Third && | |
23 | E=$(git rev-parse HEAD) | |
24 | ' | |
25 | ||
26 | test_expect_success 'empty directory should not fool rev-parse' ' | |
27 | prefix=refs/e-rev-parse && | |
28 | git update-ref $prefix/foo $C && | |
29 | git pack-refs --all && | |
30 | mkdir -p .git/$prefix/foo/bar/baz && | |
31 | echo "$C" >expected && | |
32 | git rev-parse $prefix/foo >actual && | |
33 | test_cmp expected actual | |
34 | ' | |
35 | ||
36 | test_expect_success 'empty directory should not fool for-each-ref' ' | |
37 | prefix=refs/e-for-each-ref && | |
38 | git update-ref $prefix/foo $C && | |
39 | git for-each-ref $prefix >expected && | |
40 | git pack-refs --all && | |
41 | mkdir -p .git/$prefix/foo/bar/baz && | |
42 | git for-each-ref $prefix >actual && | |
43 | test_cmp expected actual | |
44 | ' | |
45 | ||
46 | test_expect_success 'empty directory should not fool create' ' | |
47 | prefix=refs/e-create && | |
48 | mkdir -p .git/$prefix/foo/bar/baz && | |
49 | printf "create %s $C\n" $prefix/foo | | |
50 | git update-ref --stdin | |
51 | ' | |
52 | ||
53 | test_expect_success 'empty directory should not fool verify' ' | |
54 | prefix=refs/e-verify && | |
55 | git update-ref $prefix/foo $C && | |
56 | git pack-refs --all && | |
57 | mkdir -p .git/$prefix/foo/bar/baz && | |
58 | printf "verify %s $C\n" $prefix/foo | | |
59 | git update-ref --stdin | |
60 | ' | |
61 | ||
62 | test_expect_success 'empty directory should not fool 1-arg update' ' | |
63 | prefix=refs/e-update-1 && | |
64 | git update-ref $prefix/foo $C && | |
65 | git pack-refs --all && | |
66 | mkdir -p .git/$prefix/foo/bar/baz && | |
67 | printf "update %s $D\n" $prefix/foo | | |
68 | git update-ref --stdin | |
69 | ' | |
70 | ||
71 | test_expect_success 'empty directory should not fool 2-arg update' ' | |
72 | prefix=refs/e-update-2 && | |
73 | git update-ref $prefix/foo $C && | |
74 | git pack-refs --all && | |
75 | mkdir -p .git/$prefix/foo/bar/baz && | |
76 | printf "update %s $D $C\n" $prefix/foo | | |
77 | git update-ref --stdin | |
78 | ' | |
79 | ||
80 | test_expect_success 'empty directory should not fool 0-arg delete' ' | |
81 | prefix=refs/e-delete-0 && | |
82 | git update-ref $prefix/foo $C && | |
83 | git pack-refs --all && | |
84 | mkdir -p .git/$prefix/foo/bar/baz && | |
85 | printf "delete %s\n" $prefix/foo | | |
86 | git update-ref --stdin | |
87 | ' | |
88 | ||
89 | test_expect_success 'empty directory should not fool 1-arg delete' ' | |
90 | prefix=refs/e-delete-1 && | |
91 | git update-ref $prefix/foo $C && | |
92 | git pack-refs --all && | |
93 | mkdir -p .git/$prefix/foo/bar/baz && | |
94 | printf "delete %s $C\n" $prefix/foo | | |
95 | git update-ref --stdin | |
96 | ' | |
97 | ||
98 | test_expect_success 'non-empty directory blocks create' ' | |
99 | prefix=refs/ne-create && | |
100 | mkdir -p .git/$prefix/foo/bar && | |
101 | : >.git/$prefix/foo/bar/baz.lock && | |
102 | test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" && | |
103 | cat >expected <<-EOF && | |
104 | fatal: cannot lock ref $SQ$prefix/foo$SQ: there is a non-empty directory $SQ.git/$prefix/foo$SQ blocking reference $SQ$prefix/foo$SQ | |
105 | EOF | |
106 | printf "%s\n" "update $prefix/foo $C" | | |
107 | test_must_fail git update-ref --stdin 2>output.err && | |
108 | test_cmp expected output.err && | |
109 | cat >expected <<-EOF && | |
110 | fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ | |
111 | EOF | |
112 | printf "%s\n" "update $prefix/foo $D $C" | | |
113 | test_must_fail git update-ref --stdin 2>output.err && | |
114 | test_cmp expected output.err | |
115 | ' | |
116 | ||
117 | test_expect_success 'broken reference blocks create' ' | |
118 | prefix=refs/broken-create && | |
119 | mkdir -p .git/$prefix && | |
120 | echo "gobbledigook" >.git/$prefix/foo && | |
121 | test_when_finished "rm -f .git/$prefix/foo" && | |
122 | cat >expected <<-EOF && | |
123 | fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken | |
124 | EOF | |
125 | printf "%s\n" "update $prefix/foo $C" | | |
126 | test_must_fail git update-ref --stdin 2>output.err && | |
127 | test_cmp expected output.err && | |
128 | cat >expected <<-EOF && | |
129 | fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken | |
130 | EOF | |
131 | printf "%s\n" "update $prefix/foo $D $C" | | |
132 | test_must_fail git update-ref --stdin 2>output.err && | |
133 | test_cmp expected output.err | |
134 | ' | |
135 | ||
136 | test_expect_success 'non-empty directory blocks indirect create' ' | |
137 | prefix=refs/ne-indirect-create && | |
138 | git symbolic-ref $prefix/symref $prefix/foo && | |
139 | mkdir -p .git/$prefix/foo/bar && | |
140 | : >.git/$prefix/foo/bar/baz.lock && | |
141 | test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" && | |
142 | cat >expected <<-EOF && | |
143 | fatal: cannot lock ref $SQ$prefix/symref$SQ: there is a non-empty directory $SQ.git/$prefix/foo$SQ blocking reference $SQ$prefix/foo$SQ | |
144 | EOF | |
145 | printf "%s\n" "update $prefix/symref $C" | | |
146 | test_must_fail git update-ref --stdin 2>output.err && | |
147 | test_cmp expected output.err && | |
148 | cat >expected <<-EOF && | |
149 | fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ | |
150 | EOF | |
151 | printf "%s\n" "update $prefix/symref $D $C" | | |
152 | test_must_fail git update-ref --stdin 2>output.err && | |
153 | test_cmp expected output.err | |
154 | ' | |
155 | ||
156 | test_expect_success 'broken reference blocks indirect create' ' | |
157 | prefix=refs/broken-indirect-create && | |
158 | git symbolic-ref $prefix/symref $prefix/foo && | |
159 | echo "gobbledigook" >.git/$prefix/foo && | |
160 | test_when_finished "rm -f .git/$prefix/foo" && | |
161 | cat >expected <<-EOF && | |
162 | fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken | |
163 | EOF | |
164 | printf "%s\n" "update $prefix/symref $C" | | |
165 | test_must_fail git update-ref --stdin 2>output.err && | |
166 | test_cmp expected output.err && | |
167 | cat >expected <<-EOF && | |
168 | fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken | |
169 | EOF | |
170 | printf "%s\n" "update $prefix/symref $D $C" | | |
171 | test_must_fail git update-ref --stdin 2>output.err && | |
172 | test_cmp expected output.err | |
173 | ' | |
174 | ||
175 | test_expect_success 'no bogus intermediate values during delete' ' | |
176 | prefix=refs/slow-transaction && | |
177 | # Set up a reference with differing loose and packed versions: | |
178 | git update-ref $prefix/foo $C && | |
179 | git pack-refs --all && | |
180 | git update-ref $prefix/foo $D && | |
181 | # Now try to update the reference, but hold the `packed-refs` lock | |
182 | # for a while to see what happens while the process is blocked: | |
183 | : >.git/packed-refs.lock && | |
184 | test_when_finished "rm -f .git/packed-refs.lock" && | |
185 | { | |
186 | # Note: the following command is intentionally run in the | |
187 | # background. We increase the timeout so that `update-ref` | |
188 | # attempts to acquire the `packed-refs` lock for much longer | |
189 | # than it takes for us to do the check then delete it: | |
190 | git -c core.packedrefstimeout=30000 update-ref -d $prefix/foo & | |
191 | } && | |
192 | pid2=$! && | |
193 | # Give update-ref plenty of time to get to the point where it tries | |
194 | # to lock packed-refs: | |
195 | sleep 1 && | |
196 | # Make sure that update-ref did not complete despite the lock: | |
197 | kill -0 $pid2 && | |
198 | # Verify that the reference still has its old value: | |
199 | sha1=$(git rev-parse --verify --quiet $prefix/foo || echo undefined) && | |
200 | case "$sha1" in | |
201 | $D) | |
202 | # This is what we hope for; it means that nothing | |
203 | # user-visible has changed yet. | |
204 | : ;; | |
205 | undefined) | |
206 | # This is not correct; it means the deletion has happened | |
207 | # already even though update-ref should not have been | |
208 | # able to acquire the lock yet. | |
209 | echo "$prefix/foo deleted prematurely" && | |
210 | break | |
211 | ;; | |
212 | $C) | |
213 | # This value should never be seen. Probably the loose | |
214 | # reference has been deleted but the packed reference | |
215 | # is still there: | |
216 | echo "$prefix/foo incorrectly observed to be C" && | |
217 | break | |
218 | ;; | |
219 | *) | |
220 | # WTF? | |
221 | echo "unexpected value observed for $prefix/foo: $sha1" && | |
222 | break | |
223 | ;; | |
224 | esac >out && | |
225 | rm -f .git/packed-refs.lock && | |
226 | wait $pid2 && | |
227 | test_must_be_empty out && | |
228 | test_must_fail git rev-parse --verify --quiet $prefix/foo | |
229 | ' | |
230 | ||
231 | test_expect_success 'delete fails cleanly if packed-refs file is locked' ' | |
232 | prefix=refs/locked-packed-refs && | |
233 | # Set up a reference with differing loose and packed versions: | |
234 | git update-ref $prefix/foo $C && | |
235 | git pack-refs --all && | |
236 | git update-ref $prefix/foo $D && | |
237 | git for-each-ref $prefix >unchanged && | |
238 | # Now try to delete it while the `packed-refs` lock is held: | |
239 | : >.git/packed-refs.lock && | |
240 | test_when_finished "rm -f .git/packed-refs.lock" && | |
241 | test_must_fail git update-ref -d $prefix/foo >out 2>err && | |
242 | git for-each-ref $prefix >actual && | |
243 | test_grep "Unable to create $SQ.*packed-refs.lock$SQ: " err && | |
244 | test_cmp unchanged actual | |
245 | ' | |
246 | ||
247 | test_expect_success 'delete fails cleanly if packed-refs.new write fails' ' | |
248 | # Setup and expectations are similar to the test above. | |
249 | prefix=refs/failed-packed-refs && | |
250 | git update-ref $prefix/foo $C && | |
251 | git pack-refs --all && | |
252 | git update-ref $prefix/foo $D && | |
253 | git for-each-ref $prefix >unchanged && | |
254 | # This should not happen in practice, but it is an easy way to get a | |
255 | # reliable error (we open with create_tempfile(), which uses O_EXCL). | |
256 | : >.git/packed-refs.new && | |
257 | test_when_finished "rm -f .git/packed-refs.new" && | |
258 | test_must_fail git update-ref -d $prefix/foo && | |
259 | git for-each-ref $prefix >actual && | |
260 | test_cmp unchanged actual | |
261 | ' | |
262 | ||
e74d9f57 JC |
263 | RWT="test-tool ref-store worktree:wt" |
264 | RMAIN="test-tool ref-store worktree:main" | |
265 | ||
266 | test_expect_success 'setup worktree' ' | |
267 | test_commit first && | |
268 | git worktree add -b wt-main wt && | |
269 | ( | |
270 | cd wt && | |
271 | test_commit second | |
272 | ) | |
273 | ' | |
274 | ||
275 | # Some refs (refs/bisect/*, pseudorefs) are kept per worktree, so they should | |
276 | # only appear in the for-each-reflog output if it is called from the correct | |
277 | # worktree, which is exercised in this test. This test is poorly written for | |
278 | # mulitple reasons: 1) it creates invalidly formatted log entres. 2) it uses | |
279 | # direct FS access for creating the reflogs. 3) PSEUDO-WT and refs/bisect/random | |
280 | # do not create reflogs by default, so it is not testing a realistic scenario. | |
281 | test_expect_success 'for_each_reflog()' ' | |
282 | echo $ZERO_OID > .git/logs/PSEUDO-MAIN && | |
283 | mkdir -p .git/logs/refs/bisect && | |
284 | echo $ZERO_OID > .git/logs/refs/bisect/random && | |
285 | ||
286 | echo $ZERO_OID > .git/worktrees/wt/logs/PSEUDO-WT && | |
287 | mkdir -p .git/worktrees/wt/logs/refs/bisect && | |
288 | echo $ZERO_OID > .git/worktrees/wt/logs/refs/bisect/wt-random && | |
289 | ||
290 | $RWT for-each-reflog | cut -d" " -f 2- | sort >actual && | |
291 | cat >expected <<-\EOF && | |
292 | HEAD 0x1 | |
293 | PSEUDO-WT 0x0 | |
294 | refs/bisect/wt-random 0x0 | |
295 | refs/heads/main 0x0 | |
296 | refs/heads/wt-main 0x0 | |
297 | EOF | |
298 | test_cmp expected actual && | |
299 | ||
300 | $RMAIN for-each-reflog | cut -d" " -f 2- | sort >actual && | |
301 | cat >expected <<-\EOF && | |
302 | HEAD 0x1 | |
303 | PSEUDO-MAIN 0x0 | |
304 | refs/bisect/random 0x0 | |
305 | refs/heads/main 0x0 | |
306 | refs/heads/wt-main 0x0 | |
307 | EOF | |
308 | test_cmp expected actual | |
309 | ' | |
310 | ||
c02ce758 JC |
311 | # Triggering the bug detected by this test requires a newline to fall |
312 | # exactly BUFSIZ-1 bytes from the end of the file. We don't know | |
313 | # what that value is, since it's platform dependent. However, if | |
314 | # we choose some value N, we also catch any D which divides N evenly | |
315 | # (since we will read backwards in chunks of D). So we choose 8K, | |
316 | # which catches glibc (with an 8K BUFSIZ) and *BSD (1K). | |
317 | # | |
318 | # Each line is 114 characters, so we need 75 to still have a few before the | |
319 | # last 8K. The 89-character padding on the final entry lines up our | |
320 | # newline exactly. | |
321 | test_expect_success SHA1 'parsing reverse reflogs at BUFSIZ boundaries' ' | |
322 | git checkout -b reflogskip && | |
323 | zf=$(test_oid zero_2) && | |
324 | ident="abc <xyz> 0000000001 +0000" && | |
325 | for i in $(test_seq 1 75); do | |
326 | printf "$zf%02d $zf%02d %s\t" $i $(($i+1)) "$ident" && | |
327 | if test $i = 75; then | |
328 | for j in $(test_seq 1 89); do | |
329 | printf X || return 1 | |
330 | done | |
331 | else | |
332 | printf X | |
333 | fi && | |
334 | printf "\n" || return 1 | |
335 | done >.git/logs/refs/heads/reflogskip && | |
336 | git rev-parse reflogskip@{73} >actual && | |
337 | echo ${zf}03 >expect && | |
338 | test_cmp expect actual | |
339 | ' | |
340 | ||
341 | # This test takes a lock on an individual ref; this is not supported in | |
342 | # reftable. | |
343 | test_expect_success 'reflog expire operates on symref not referrent' ' | |
344 | git branch --create-reflog the_symref && | |
345 | git branch --create-reflog referrent && | |
346 | git update-ref referrent HEAD && | |
347 | git symbolic-ref refs/heads/the_symref refs/heads/referrent && | |
348 | test_when_finished "rm -f .git/refs/heads/referrent.lock" && | |
349 | touch .git/refs/heads/referrent.lock && | |
350 | git reflog expire --expire=all the_symref | |
351 | ' | |
352 | ||
353 | test_expect_success 'empty reflog' ' | |
354 | test_when_finished "rm -rf empty" && | |
355 | git init empty && | |
356 | test_commit -C empty A && | |
357 | >empty/.git/logs/refs/heads/foo && | |
358 | git -C empty reflog expire --all 2>err && | |
359 | test_must_be_empty err | |
360 | ' | |
361 | ||
dfc9486c JC |
362 | test_expect_success SYMLINKS 'ref resolution not confused by broken symlinks' ' |
363 | ln -s does-not-exist .git/refs/heads/broken && | |
364 | test_must_fail git rev-parse --verify broken | |
365 | ' | |
366 | ||
1030d140 JC |
367 | test_expect_success 'log diagnoses bogus HEAD hash' ' |
368 | git init empty && | |
369 | test_when_finished "rm -rf empty" && | |
370 | echo 1234abcd >empty/.git/refs/heads/main && | |
371 | test_must_fail git -C empty log 2>stderr && | |
372 | test_grep broken stderr | |
373 | ' | |
374 | ||
375 | test_expect_success 'log diagnoses bogus HEAD symref' ' | |
376 | git init empty && | |
377 | test-tool -C empty ref-store main create-symref HEAD refs/heads/invalid.lock && | |
378 | test_must_fail git -C empty log 2>stderr && | |
379 | test_grep broken stderr && | |
380 | test_must_fail git -C empty log --default totally-bogus 2>stderr && | |
381 | test_grep broken stderr | |
382 | ' | |
383 | ||
102d7154 | 384 | test_done |