]>
Commit | Line | Data |
---|---|---|
29b0d019 NP |
1 | #!/bin/sh |
2 | # | |
3 | # Copyright (c) 2008 Nicolas Pitre | |
4 | # | |
5 | ||
6 | test_description='resilience to pack corruptions with redundant objects' | |
7 | . ./test-lib.sh | |
8 | ||
9 | # Note: the test objects are created with knowledge of their pack encoding | |
10 | # to ensure good code path coverage, and to facilitate direct alteration | |
11 | # later on. The assumed characteristics are: | |
12 | # | |
13 | # 1) blob_2 is a delta with blob_1 for base and blob_3 is a delta with blob2 | |
14 | # for base, such that blob_3 delta depth is 2; | |
15 | # | |
16 | # 2) the bulk of object data is uncompressible so the text part remains | |
17 | # visible; | |
18 | # | |
19 | # 3) object header is always 2 bytes. | |
20 | ||
21 | create_test_files() { | |
c680668d NTND |
22 | test-tool genrandom "foo" 2000 > file_1 && |
23 | test-tool genrandom "foo" 1800 > file_2 && | |
24 | test-tool genrandom "foo" 1800 > file_3 && | |
29b0d019 NP |
25 | echo " base " >> file_1 && |
26 | echo " delta1 " >> file_2 && | |
27 | echo " delta delta2 " >> file_3 && | |
c680668d NTND |
28 | test-tool genrandom "bar" 150 >> file_2 && |
29 | test-tool genrandom "baz" 100 >> file_3 | |
29b0d019 NP |
30 | } |
31 | ||
32 | create_new_pack() { | |
33 | rm -rf .git && | |
34 | git init && | |
a64d080f EP |
35 | blob_1=$(git hash-object -t blob -w file_1) && |
36 | blob_2=$(git hash-object -t blob -w file_2) && | |
37 | blob_3=$(git hash-object -t blob -w file_3) && | |
38 | pack=$(printf "$blob_1\n$blob_2\n$blob_3\n" | | |
39 | git pack-objects $@ .git/objects/pack/pack) && | |
29b0d019 NP |
40 | pack=".git/objects/pack/pack-${pack}" && |
41 | git verify-pack -v ${pack}.pack | |
42 | } | |
43 | ||
538cf6b6 | 44 | do_repack() { |
a64d080f EP |
45 | pack=$(printf "$blob_1\n$blob_2\n$blob_3\n" | |
46 | git pack-objects $@ .git/objects/pack/pack) && | |
538cf6b6 NP |
47 | pack=".git/objects/pack/pack-${pack}" |
48 | } | |
49 | ||
29b0d019 | 50 | do_corrupt_object() { |
a64d080f | 51 | ofs=$(git show-index < ${pack}.idx | grep $1 | cut -f1 -d" ") && |
29b0d019 NP |
52 | ofs=$(($ofs + $2)) && |
53 | chmod +w ${pack}.pack && | |
50b72ede | 54 | dd of=${pack}.pack bs=1 conv=notrunc seek=$ofs && |
29b0d019 NP |
55 | test_must_fail git verify-pack ${pack}.pack |
56 | } | |
57 | ||
b689ccf6 JS |
58 | printf '\0' > zero |
59 | ||
29b0d019 NP |
60 | test_expect_success \ |
61 | 'initial setup validation' \ | |
62 | 'create_test_files && | |
63 | create_new_pack && | |
64 | git prune-packed && | |
65 | git cat-file blob $blob_1 > /dev/null && | |
66 | git cat-file blob $blob_2 > /dev/null && | |
67 | git cat-file blob $blob_3 > /dev/null' | |
68 | ||
69 | test_expect_success \ | |
70 | 'create corruption in header of first object' \ | |
b689ccf6 | 71 | 'do_corrupt_object $blob_1 0 < zero && |
29b0d019 NP |
72 | test_must_fail git cat-file blob $blob_1 > /dev/null && |
73 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
74 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
75 | ||
76 | test_expect_success \ | |
77 | '... but having a loose copy allows for full recovery' \ | |
78 | 'mv ${pack}.idx tmp && | |
79 | git hash-object -t blob -w file_1 && | |
80 | mv tmp ${pack}.idx && | |
81 | git cat-file blob $blob_1 > /dev/null && | |
82 | git cat-file blob $blob_2 > /dev/null && | |
83 | git cat-file blob $blob_3 > /dev/null' | |
84 | ||
85 | test_expect_success \ | |
86 | '... and loose copy of first delta allows for partial recovery' \ | |
87 | 'git prune-packed && | |
88 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
89 | mv ${pack}.idx tmp && | |
90 | git hash-object -t blob -w file_2 && | |
91 | mv tmp ${pack}.idx && | |
92 | test_must_fail git cat-file blob $blob_1 > /dev/null && | |
93 | git cat-file blob $blob_2 > /dev/null && | |
94 | git cat-file blob $blob_3 > /dev/null' | |
95 | ||
96 | test_expect_success \ | |
97 | 'create corruption in data of first object' \ | |
98 | 'create_new_pack && | |
99 | git prune-packed && | |
100 | chmod +w ${pack}.pack && | |
94221d22 | 101 | perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack && |
29b0d019 NP |
102 | test_must_fail git cat-file blob $blob_1 > /dev/null && |
103 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
104 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
105 | ||
106 | test_expect_success \ | |
107 | '... but having a loose copy allows for full recovery' \ | |
108 | 'mv ${pack}.idx tmp && | |
109 | git hash-object -t blob -w file_1 && | |
110 | mv tmp ${pack}.idx && | |
111 | git cat-file blob $blob_1 > /dev/null && | |
112 | git cat-file blob $blob_2 > /dev/null && | |
113 | git cat-file blob $blob_3 > /dev/null' | |
114 | ||
115 | test_expect_success \ | |
116 | '... and loose copy of second object allows for partial recovery' \ | |
117 | 'git prune-packed && | |
118 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
119 | mv ${pack}.idx tmp && | |
120 | git hash-object -t blob -w file_2 && | |
121 | mv tmp ${pack}.idx && | |
122 | test_must_fail git cat-file blob $blob_1 > /dev/null && | |
123 | git cat-file blob $blob_2 > /dev/null && | |
124 | git cat-file blob $blob_3 > /dev/null' | |
125 | ||
126 | test_expect_success \ | |
127 | 'create corruption in header of first delta' \ | |
128 | 'create_new_pack && | |
129 | git prune-packed && | |
b689ccf6 | 130 | do_corrupt_object $blob_2 0 < zero && |
29b0d019 NP |
131 | git cat-file blob $blob_1 > /dev/null && |
132 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
133 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
134 | ||
135 | test_expect_success \ | |
136 | '... but having a loose copy allows for full recovery' \ | |
137 | 'mv ${pack}.idx tmp && | |
138 | git hash-object -t blob -w file_2 && | |
139 | mv tmp ${pack}.idx && | |
140 | git cat-file blob $blob_1 > /dev/null && | |
141 | git cat-file blob $blob_2 > /dev/null && | |
142 | git cat-file blob $blob_3 > /dev/null' | |
143 | ||
538cf6b6 NP |
144 | test_expect_success \ |
145 | '... and then a repack "clears" the corruption' \ | |
146 | 'do_repack && | |
147 | git prune-packed && | |
148 | git verify-pack ${pack}.pack && | |
149 | git cat-file blob $blob_1 > /dev/null && | |
150 | git cat-file blob $blob_2 > /dev/null && | |
151 | git cat-file blob $blob_3 > /dev/null' | |
152 | ||
29b0d019 NP |
153 | test_expect_success \ |
154 | 'create corruption in data of first delta' \ | |
155 | 'create_new_pack && | |
156 | git prune-packed && | |
157 | chmod +w ${pack}.pack && | |
94221d22 | 158 | perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack && |
29b0d019 NP |
159 | git cat-file blob $blob_1 > /dev/null && |
160 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
161 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
162 | ||
163 | test_expect_success \ | |
164 | '... but having a loose copy allows for full recovery' \ | |
165 | 'mv ${pack}.idx tmp && | |
166 | git hash-object -t blob -w file_2 && | |
167 | mv tmp ${pack}.idx && | |
168 | git cat-file blob $blob_1 > /dev/null && | |
169 | git cat-file blob $blob_2 > /dev/null && | |
170 | git cat-file blob $blob_3 > /dev/null' | |
171 | ||
538cf6b6 NP |
172 | test_expect_success \ |
173 | '... and then a repack "clears" the corruption' \ | |
174 | 'do_repack && | |
175 | git prune-packed && | |
176 | git verify-pack ${pack}.pack && | |
177 | git cat-file blob $blob_1 > /dev/null && | |
178 | git cat-file blob $blob_2 > /dev/null && | |
179 | git cat-file blob $blob_3 > /dev/null' | |
180 | ||
29b0d019 NP |
181 | test_expect_success \ |
182 | 'corruption in delta base reference of first delta (OBJ_REF_DELTA)' \ | |
183 | 'create_new_pack && | |
184 | git prune-packed && | |
b689ccf6 | 185 | do_corrupt_object $blob_2 2 < zero && |
29b0d019 NP |
186 | git cat-file blob $blob_1 > /dev/null && |
187 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
188 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
189 | ||
190 | test_expect_success \ | |
191 | '... but having a loose copy allows for full recovery' \ | |
192 | 'mv ${pack}.idx tmp && | |
193 | git hash-object -t blob -w file_2 && | |
194 | mv tmp ${pack}.idx && | |
195 | git cat-file blob $blob_1 > /dev/null && | |
196 | git cat-file blob $blob_2 > /dev/null && | |
197 | git cat-file blob $blob_3 > /dev/null' | |
198 | ||
199 | test_expect_success \ | |
538cf6b6 NP |
200 | '... and then a repack "clears" the corruption' \ |
201 | 'do_repack && | |
202 | git prune-packed && | |
203 | git verify-pack ${pack}.pack && | |
204 | git cat-file blob $blob_1 > /dev/null && | |
205 | git cat-file blob $blob_2 > /dev/null && | |
206 | git cat-file blob $blob_3 > /dev/null' | |
207 | ||
208 | test_expect_success \ | |
209 | 'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' \ | |
29b0d019 NP |
210 | 'create_new_pack --delta-base-offset && |
211 | git prune-packed && | |
b689ccf6 | 212 | do_corrupt_object $blob_2 2 < zero && |
29b0d019 NP |
213 | git cat-file blob $blob_1 > /dev/null && |
214 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
215 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
216 | ||
217 | test_expect_success \ | |
538cf6b6 | 218 | '... but having a loose copy allows for full recovery' \ |
29b0d019 | 219 | 'mv ${pack}.idx tmp && |
538cf6b6 NP |
220 | git hash-object -t blob -w file_2 && |
221 | mv tmp ${pack}.idx && | |
222 | git cat-file blob $blob_1 > /dev/null && | |
223 | git cat-file blob $blob_2 > /dev/null && | |
224 | git cat-file blob $blob_3 > /dev/null' | |
225 | ||
226 | test_expect_success \ | |
227 | '... and then a repack "clears" the corruption' \ | |
228 | 'do_repack --delta-base-offset && | |
229 | git prune-packed && | |
230 | git verify-pack ${pack}.pack && | |
231 | git cat-file blob $blob_1 > /dev/null && | |
232 | git cat-file blob $blob_2 > /dev/null && | |
233 | git cat-file blob $blob_3 > /dev/null' | |
234 | ||
235 | test_expect_success \ | |
236 | 'corruption #1 in delta base reference of first delta (OBJ_OFS_DELTA)' \ | |
237 | 'create_new_pack --delta-base-offset && | |
238 | git prune-packed && | |
a2d2c478 | 239 | printf "\001" | do_corrupt_object $blob_2 2 && |
538cf6b6 NP |
240 | git cat-file blob $blob_1 > /dev/null && |
241 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
242 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
243 | ||
244 | test_expect_success \ | |
245 | '... but having a loose copy allows for full recovery' \ | |
246 | 'mv ${pack}.idx tmp && | |
247 | git hash-object -t blob -w file_2 && | |
248 | mv tmp ${pack}.idx && | |
249 | git cat-file blob $blob_1 > /dev/null && | |
250 | git cat-file blob $blob_2 > /dev/null && | |
251 | git cat-file blob $blob_3 > /dev/null' | |
252 | ||
253 | test_expect_success \ | |
254 | '... and then a repack "clears" the corruption' \ | |
255 | 'do_repack --delta-base-offset && | |
256 | git prune-packed && | |
257 | git verify-pack ${pack}.pack && | |
258 | git cat-file blob $blob_1 > /dev/null && | |
259 | git cat-file blob $blob_2 > /dev/null && | |
260 | git cat-file blob $blob_3 > /dev/null' | |
261 | ||
262 | test_expect_success \ | |
263 | '... and a redundant pack allows for full recovery too' \ | |
b689ccf6 | 264 | 'do_corrupt_object $blob_2 2 < zero && |
538cf6b6 NP |
265 | git cat-file blob $blob_1 > /dev/null && |
266 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
267 | test_must_fail git cat-file blob $blob_3 > /dev/null && | |
268 | mv ${pack}.idx tmp && | |
29b0d019 NP |
269 | git hash-object -t blob -w file_1 && |
270 | git hash-object -t blob -w file_2 && | |
271 | printf "$blob_1\n$blob_2\n" | git pack-objects .git/objects/pack/pack && | |
272 | git prune-packed && | |
273 | mv tmp ${pack}.idx && | |
274 | git cat-file blob $blob_1 > /dev/null && | |
275 | git cat-file blob $blob_2 > /dev/null && | |
276 | git cat-file blob $blob_3 > /dev/null' | |
277 | ||
1ee886c1 JK |
278 | test_expect_success \ |
279 | 'corruption of delta base reference pointing to wrong object' \ | |
280 | 'create_new_pack --delta-base-offset && | |
281 | git prune-packed && | |
282 | printf "\220\033" | do_corrupt_object $blob_3 2 && | |
283 | git cat-file blob $blob_1 >/dev/null && | |
284 | git cat-file blob $blob_2 >/dev/null && | |
285 | test_must_fail git cat-file blob $blob_3 >/dev/null' | |
286 | ||
287 | test_expect_success \ | |
288 | '... but having a loose copy allows for full recovery' \ | |
289 | 'mv ${pack}.idx tmp && | |
290 | git hash-object -t blob -w file_3 && | |
291 | mv tmp ${pack}.idx && | |
292 | git cat-file blob $blob_1 > /dev/null && | |
293 | git cat-file blob $blob_2 > /dev/null && | |
294 | git cat-file blob $blob_3 > /dev/null' | |
295 | ||
296 | test_expect_success \ | |
297 | '... and then a repack "clears" the corruption' \ | |
298 | 'do_repack --delta-base-offset --no-reuse-delta && | |
299 | git prune-packed && | |
300 | git verify-pack ${pack}.pack && | |
301 | git cat-file blob $blob_1 > /dev/null && | |
302 | git cat-file blob $blob_2 > /dev/null && | |
303 | git cat-file blob $blob_3 > /dev/null' | |
304 | ||
b3118bdc SP |
305 | test_expect_success \ |
306 | 'corrupting header to have too small output buffer fails unpack' \ | |
307 | 'create_new_pack && | |
308 | git prune-packed && | |
309 | printf "\262\001" | do_corrupt_object $blob_1 0 && | |
310 | test_must_fail git cat-file blob $blob_1 > /dev/null && | |
311 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
312 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
313 | ||
9caf0107 JK |
314 | # \0 - empty base |
315 | # \1 - one byte in result | |
316 | # \1 - one literal byte (X) | |
317 | test_expect_success \ | |
318 | 'apply good minimal delta' \ | |
319 | 'printf "\0\1\1X" > minimal_delta && | |
320 | test-tool delta -p /dev/null minimal_delta /dev/null' | |
321 | ||
322 | # \0 - empty base | |
323 | # \1 - 1 byte in result | |
324 | # \2 - two literal bytes (one too many) | |
325 | test_expect_success \ | |
326 | 'apply delta with too many literal bytes' \ | |
327 | 'printf "\0\1\2XX" > too_big_literal && | |
328 | test_must_fail test-tool delta -p /dev/null too_big_literal /dev/null' | |
329 | ||
18f60f2d | 330 | # \4 - four bytes in base |
9caf0107 JK |
331 | # \1 - one byte in result |
332 | # \221 - copy, one byte offset, one byte size | |
333 | # \0 - copy from offset 0 | |
334 | # \2 - copy two bytes (one too many) | |
335 | test_expect_success \ | |
336 | 'apply delta with too many copied bytes' \ | |
18f60f2d JK |
337 | 'printf "\4\1\221\0\2" > too_big_copy && |
338 | printf base >base && | |
9caf0107 JK |
339 | test_must_fail test-tool delta -p base too_big_copy /dev/null' |
340 | ||
341 | # \0 - empty base | |
342 | # \2 - two bytes in result | |
343 | # \2 - two literal bytes (we are short one) | |
21870efc | 344 | test_expect_success \ |
9caf0107 JK |
345 | 'apply delta with too few literal bytes' \ |
346 | 'printf "\0\2\2X" > truncated_delta && | |
347 | test_must_fail test-tool delta -p /dev/null truncated_delta /dev/null' | |
348 | ||
349 | # \0 - empty base | |
350 | # \1 - one byte in result | |
351 | # \221 - copy, one byte offset, one byte size | |
352 | # \0 - copy from offset 0 | |
353 | # \1 - copy one byte (we are short one) | |
354 | test_expect_success \ | |
355 | 'apply delta with too few bytes in base' \ | |
356 | 'printf "\0\1\221\0\1" > truncated_base && | |
357 | test_must_fail test-tool delta -p /dev/null truncated_base /dev/null' | |
358 | ||
18f60f2d JK |
359 | # \4 - four bytes in base |
360 | # \2 - two bytes in result | |
9caf0107 JK |
361 | # \1 - one literal byte (X) |
362 | # \221 - copy, one byte offset, one byte size | |
363 | # (offset/size missing) | |
364 | # | |
365 | # Note that the literal byte is necessary to get past the uninteresting minimum | |
366 | # delta size check. | |
9514b0b2 | 367 | test_expect_success \ |
9caf0107 | 368 | 'apply delta with truncated copy parameters' \ |
18f60f2d JK |
369 | 'printf "\4\2\1X\221" > truncated_copy_delta && |
370 | printf base >base && | |
9caf0107 JK |
371 | test_must_fail test-tool delta -p base truncated_copy_delta /dev/null' |
372 | ||
fa72f90e JH |
373 | # \0 - empty base |
374 | # \1 - one byte in result | |
375 | # \1 - one literal byte (X) | |
376 | # \1 - trailing garbage command | |
377 | test_expect_success \ | |
378 | 'apply delta with trailing garbage literal' \ | |
379 | 'printf "\0\1\1X\1" > tail_garbage_literal && | |
380 | test_must_fail test-tool delta -p /dev/null tail_garbage_literal /dev/null' | |
381 | ||
18f60f2d | 382 | # \4 - four bytes in base |
fa72f90e JH |
383 | # \1 - one byte in result |
384 | # \1 - one literal byte (X) | |
385 | # \221 - copy, one byte offset, one byte size | |
386 | # \0 - copy from offset 0 | |
387 | # \1 - copy 1 byte | |
388 | test_expect_success \ | |
389 | 'apply delta with trailing garbage copy' \ | |
18f60f2d JK |
390 | 'printf "\4\1\1X\221\0\1" > tail_garbage_copy && |
391 | printf base >base && | |
fa72f90e JH |
392 | test_must_fail test-tool delta -p /dev/null tail_garbage_copy /dev/null' |
393 | ||
394 | # \0 - empty base | |
395 | # \1 - one byte in result | |
396 | # \1 - one literal byte (X) | |
397 | # \0 - bogus opcode | |
398 | test_expect_success \ | |
399 | 'apply delta with trailing garbage opcode' \ | |
400 | 'printf "\0\1\1X\0" > tail_garbage_opcode && | |
401 | test_must_fail test-tool delta -p /dev/null tail_garbage_opcode /dev/null' | |
402 | ||
29b0d019 | 403 | test_done |