Git fork
at reftables-rust 949 lines 32 kB view raw
1#!/bin/sh 2 3test_description='commit graph' 4 5. ./test-lib.sh 6. "$TEST_DIRECTORY"/lib-chunk.sh 7 8GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0 9 10test_expect_success 'usage' ' 11 test_expect_code 129 git commit-graph write blah 2>err && 12 test_expect_code 129 git commit-graph write verify 13' 14 15test_expect_success 'usage shown without sub-command' ' 16 test_expect_code 129 git commit-graph 2>err && 17 grep usage: err 18' 19 20test_expect_success 'usage shown with an error on unknown sub-command' ' 21 cat >expect <<-\EOF && 22 error: unknown subcommand: `unknown'\'' 23 EOF 24 test_expect_code 129 git commit-graph unknown 2>stderr && 25 grep error stderr >actual && 26 test_cmp expect actual 27' 28 29objdir=".git/objects" 30 31test_expect_success 'setup full repo' ' 32 git init full 33' 34 35test_expect_success POSIXPERM 'tweak umask for modebit tests' ' 36 umask 022 37' 38 39test_expect_success 'verify graph with no graph file' ' 40 git -C full commit-graph verify 41' 42 43test_expect_success 'write graph with no packs' ' 44 git -C full commit-graph write --object-dir $objdir && 45 test_path_is_missing full/$objdir/info/commit-graph 46' 47 48test_expect_success 'exit with correct error on bad input to --stdin-packs' ' 49 echo doesnotexist >in && 50 test_expect_code 1 git -C full commit-graph write --stdin-packs \ 51 <in 2>stderr && 52 test_grep "error adding pack" stderr 53' 54 55test_expect_success 'create commits and repack' ' 56 for i in $(test_seq 3) 57 do 58 test_commit -C full $i && 59 git -C full branch commits/$i || return 1 60 done && 61 git -C full repack 62' 63 64. "$TEST_DIRECTORY"/lib-commit-graph.sh 65 66graph_git_behavior 'no graph' full commits/3 commits/1 67 68test_expect_success 'exit with correct error on bad input to --stdin-commits' ' 69 # invalid, non-hex OID 70 echo HEAD | test_expect_code 1 git -C full commit-graph write \ 71 --stdin-commits 2>stderr && 72 test_grep "unexpected non-hex object ID: HEAD" stderr && 73 # non-existent OID 74 echo $ZERO_OID | test_expect_code 1 git -C full commit-graph write \ 75 --stdin-commits 2>stderr && 76 test_grep "invalid object" stderr && 77 # valid commit and tree OID 78 git -C full rev-parse HEAD HEAD^{tree} >in && 79 git -C full commit-graph write --stdin-commits <in && 80 graph_read_expect -C full 3 generation_data 81' 82 83test_expect_success 'write graph' ' 84 git -C full commit-graph write && 85 test_path_is_file full/$objdir/info/commit-graph && 86 graph_read_expect -C full 3 generation_data 87' 88 89test_expect_success POSIXPERM 'write graph has correct permissions' ' 90 test_path_is_file full/$objdir/info/commit-graph && 91 echo "-r--r--r--" >expect && 92 test_modebits full/$objdir/info/commit-graph >actual && 93 test_cmp expect actual 94' 95 96graph_git_behavior 'graph exists' full commits/3 commits/1 97 98test_expect_success 'Add more commits' ' 99 git -C full reset --hard commits/1 && 100 for i in $(test_seq 4 5) 101 do 102 test_commit -C full $i && 103 git -C full branch commits/$i || return 1 104 done && 105 git -C full reset --hard commits/2 && 106 for i in $(test_seq 6 7) 107 do 108 test_commit -C full $i && 109 git -C full branch commits/$i || return 1 110 done && 111 git -C full reset --hard commits/2 && 112 git -C full merge commits/4 && 113 git -C full branch merge/1 && 114 git -C full reset --hard commits/4 && 115 git -C full merge commits/6 && 116 git -C full branch merge/2 && 117 git -C full reset --hard commits/3 && 118 git -C full merge commits/5 commits/7 && 119 git -C full branch merge/3 && 120 git -C full repack 121' 122 123test_expect_success 'commit-graph write progress off for redirected stderr' ' 124 git -C full commit-graph write 2>err && 125 test_must_be_empty err 126' 127 128test_expect_success 'commit-graph write force progress on for stderr' ' 129 GIT_PROGRESS_DELAY=0 git -C full commit-graph write --progress 2>err && 130 test_file_not_empty err 131' 132 133test_expect_success 'commit-graph write with the --no-progress option' ' 134 git -C full commit-graph write --no-progress 2>err && 135 test_must_be_empty err 136' 137 138test_expect_success 'commit-graph write --stdin-commits progress off for redirected stderr' ' 139 git -C full rev-parse commits/5 >in && 140 git -C full commit-graph write --stdin-commits <in 2>err && 141 test_must_be_empty err 142' 143 144test_expect_success 'commit-graph write --stdin-commits force progress on for stderr' ' 145 git -C full rev-parse commits/5 >in && 146 GIT_PROGRESS_DELAY=0 git -C full commit-graph write --stdin-commits \ 147 --progress <in 2>err && 148 test_grep "Collecting commits from input" err 149' 150 151test_expect_success 'commit-graph write --stdin-commits with the --no-progress option' ' 152 git -C full rev-parse commits/5 >in && 153 git -C full commit-graph write --stdin-commits --no-progress <in 2>err && 154 test_must_be_empty err 155' 156 157test_expect_success 'commit-graph verify progress off for redirected stderr' ' 158 git -C full commit-graph verify 2>err && 159 test_must_be_empty err 160' 161 162test_expect_success 'commit-graph verify force progress on for stderr' ' 163 GIT_PROGRESS_DELAY=0 git -C full commit-graph verify --progress 2>err && 164 test_file_not_empty err 165' 166 167test_expect_success 'commit-graph verify with the --no-progress option' ' 168 git -C full commit-graph verify --no-progress 2>err && 169 test_must_be_empty err 170' 171 172# Current graph structure: 173# 174# __M3___ 175# / | \ 176# 3 M1 5 M2 7 177# |/ \|/ \| 178# 2 4 6 179# |___/____/ 180# 1 181 182test_expect_success 'write graph with merges' ' 183 git -C full commit-graph write && 184 test_path_is_file full/$objdir/info/commit-graph && 185 graph_read_expect -C full 10 "generation_data extra_edges" 186' 187 188graph_git_behavior 'merge 1 vs 2' full merge/1 merge/2 189graph_git_behavior 'merge 1 vs 3' full merge/1 merge/3 190graph_git_behavior 'merge 2 vs 3' full merge/2 merge/3 191 192test_expect_success 'Add one more commit' ' 193 test_commit -C full 8 && 194 git -C full branch commits/8 && 195 ls full/$objdir/pack | grep idx >existing-idx && 196 git -C full repack && 197 ls full/$objdir/pack| grep idx | grep -v -f existing-idx >new-idx 198' 199 200# Current graph structure: 201# 202# 8 203# | 204# __M3___ 205# / | \ 206# 3 M1 5 M2 7 207# |/ \|/ \| 208# 2 4 6 209# |___/____/ 210# 1 211 212graph_git_behavior 'mixed mode, commit 8 vs merge 1' full commits/8 merge/1 213graph_git_behavior 'mixed mode, commit 8 vs merge 2' full commits/8 merge/2 214 215test_expect_success 'write graph with new commit' ' 216 git -C full commit-graph write && 217 test_path_is_file full/$objdir/info/commit-graph && 218 graph_read_expect -C full 11 "generation_data extra_edges" 219' 220 221graph_git_behavior 'full graph, commit 8 vs merge 1' full commits/8 merge/1 222graph_git_behavior 'full graph, commit 8 vs merge 2' full commits/8 merge/2 223 224test_expect_success 'write graph with nothing new' ' 225 git -C full commit-graph write && 226 test_path_is_file full/$objdir/info/commit-graph && 227 graph_read_expect -C full 11 "generation_data extra_edges" 228' 229 230graph_git_behavior 'cleared graph, commit 8 vs merge 1' full commits/8 merge/1 231graph_git_behavior 'cleared graph, commit 8 vs merge 2' full commits/8 merge/2 232 233test_expect_success 'build graph from latest pack with closure' ' 234 git -C full commit-graph write --stdin-packs <new-idx && 235 test_path_is_file full/$objdir/info/commit-graph && 236 graph_read_expect -C full 9 "generation_data extra_edges" 237' 238 239graph_git_behavior 'graph from pack, commit 8 vs merge 1' full commits/8 merge/1 240graph_git_behavior 'graph from pack, commit 8 vs merge 2' full commits/8 merge/2 241 242test_expect_success 'build graph from commits with closure' ' 243 git -C full tag -a -m "merge" tag/merge merge/2 && 244 git -C full rev-parse tag/merge >commits-in && 245 git -C full rev-parse merge/1 >>commits-in && 246 git -C full commit-graph write --stdin-commits <commits-in && 247 test_path_is_file full/$objdir/info/commit-graph && 248 graph_read_expect -C full 6 "generation_data" 249' 250 251graph_git_behavior 'graph from commits, commit 8 vs merge 1' full commits/8 merge/1 252graph_git_behavior 'graph from commits, commit 8 vs merge 2' full commits/8 merge/2 253 254test_expect_success 'build graph from commits with append' ' 255 git -C full rev-parse merge/3 >in && 256 git -C full commit-graph write --stdin-commits --append <in && 257 test_path_is_file full/$objdir/info/commit-graph && 258 graph_read_expect -C full 10 "generation_data extra_edges" 259' 260 261graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1 262graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2 263 264test_expect_success 'build graph using --reachable' ' 265 git -C full commit-graph write --reachable && 266 test_path_is_file full/$objdir/info/commit-graph && 267 graph_read_expect -C full 11 "generation_data extra_edges" 268' 269 270graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1 271graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2 272 273test_expect_success 'setup bare repo' ' 274 git clone --bare --no-local full bare 275' 276 277graph_git_behavior 'bare repo, commit 8 vs merge 1' bare commits/8 merge/1 278graph_git_behavior 'bare repo, commit 8 vs merge 2' bare commits/8 merge/2 279 280test_expect_success 'write graph in bare repo' ' 281 git -C bare commit-graph write && 282 test_path_is_file bare/objects/info/commit-graph && 283 graph_read_expect -C bare 11 "generation_data extra_edges" 284' 285 286graph_git_behavior 'bare repo with graph, commit 8 vs merge 1' bare commits/8 merge/1 287graph_git_behavior 'bare repo with graph, commit 8 vs merge 2' bare commits/8 merge/2 288 289test_expect_success 'perform fast-forward merge in full repo' ' 290 git -C full checkout -b merge-5-to-8 commits/5 && 291 git -C full merge commits/8 && 292 git -C full show-ref -s merge-5-to-8 >output && 293 git -C full show-ref -s commits/8 >expect && 294 test_cmp expect output 295' 296 297test_expect_success 'check that gc computes commit-graph' ' 298 test_commit -C full --no-tag blank && 299 git -C full commit-graph write --reachable && 300 cp full/$objdir/info/commit-graph commit-graph-before-gc && 301 git -C full reset --hard HEAD~1 && 302 test_config -C full gc.writeCommitGraph true && 303 git -C full gc && 304 cp full/$objdir/info/commit-graph commit-graph-after-gc && 305 ! test_cmp_bin commit-graph-before-gc commit-graph-after-gc && 306 git -C full commit-graph write --reachable && 307 test_cmp_bin commit-graph-after-gc full/$objdir/info/commit-graph 308' 309 310test_expect_success 'replace-objects invalidates commit-graph' ' 311 test_when_finished rm -rf replace && 312 git clone full replace && 313 ( 314 cd replace && 315 git commit-graph write --reachable && 316 test_path_is_file .git/objects/info/commit-graph && 317 git replace HEAD~1 HEAD~2 && 318 graph_git_two_modes "commit-graph verify" && 319 git -c core.commitGraph=false log >expect && 320 git -c core.commitGraph=true log >actual && 321 test_cmp expect actual && 322 git commit-graph write --reachable && 323 git -c core.commitGraph=false --no-replace-objects log >expect && 324 git -c core.commitGraph=true --no-replace-objects log >actual && 325 test_cmp expect actual && 326 rm -rf .git/objects/info/commit-graph && 327 git commit-graph write --reachable && 328 test_path_is_file .git/objects/info/commit-graph 329 ) 330' 331 332test_expect_success 'commit grafts invalidate commit-graph' ' 333 test_when_finished rm -rf graft && 334 git clone --template= full graft && 335 ( 336 cd graft && 337 git commit-graph write --reachable && 338 test_path_is_file .git/objects/info/commit-graph && 339 H1=$(git rev-parse --verify HEAD~1) && 340 H3=$(git rev-parse --verify HEAD~3) && 341 mkdir .git/info && 342 echo "$H1 $H3" >.git/info/grafts && 343 git -c core.commitGraph=false log >expect && 344 git -c core.commitGraph=true log >actual && 345 test_cmp expect actual && 346 git commit-graph write --reachable && 347 git -c core.commitGraph=false --no-replace-objects log >expect && 348 git -c core.commitGraph=true --no-replace-objects log >actual && 349 test_cmp expect actual && 350 rm -rf .git/objects/info/commit-graph && 351 git commit-graph write --reachable && 352 test_path_is_missing .git/objects/info/commit-graph 353 ) 354' 355 356test_expect_success 'replace-objects invalidates commit-graph' ' 357 test_when_finished rm -rf shallow && 358 git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow && 359 ( 360 cd shallow && 361 git commit-graph write --reachable && 362 test_path_is_missing .git/objects/info/commit-graph && 363 git fetch origin --unshallow && 364 git commit-graph write --reachable && 365 test_path_is_file .git/objects/info/commit-graph 366 ) 367' 368 369test_expect_success 'warn on improper hash version' ' 370 git init --object-format=sha1 sha1 && 371 ( 372 cd sha1 && 373 test_commit 1 && 374 git commit-graph write --reachable && 375 mv .git/objects/info/commit-graph ../cg-sha1 376 ) && 377 git init --object-format=sha256 sha256 && 378 ( 379 cd sha256 && 380 test_commit 1 && 381 git commit-graph write --reachable && 382 mv .git/objects/info/commit-graph ../cg-sha256 383 ) && 384 ( 385 cd sha1 && 386 mv ../cg-sha256 .git/objects/info/commit-graph && 387 git log -1 2>err && 388 test_grep "commit-graph hash version 2 does not match version 1" err 389 ) && 390 ( 391 cd sha256 && 392 mv ../cg-sha1 .git/objects/info/commit-graph && 393 git log -1 2>err && 394 test_grep "commit-graph hash version 1 does not match version 2" err 395 ) 396' 397 398test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow chunk' ' 399 UNIX_EPOCH_ZERO="@0 +0000" && 400 FUTURE_DATE="@4147483646 +0000" && 401 rm -f full/.git/objects/info/commit-graph && 402 test_commit -C full --date "$FUTURE_DATE" future-1 && 403 test_commit -C full --date "$UNIX_EPOCH_ZERO" old-1 && 404 git -C full commit-graph write --reachable && 405 test_commit -C full --date "$FUTURE_DATE" future-2 && 406 test_commit -C full --date "$UNIX_EPOCH_ZERO" old-2 && 407 git -C full commit-graph write --reachable --split=no-merge && 408 test_commit -C full extra && 409 git -C full commit-graph write --reachable --split=no-merge && 410 git -C full commit-graph write --reachable && 411 graph_read_expect -C full 16 \ 412 "generation_data generation_data_overflow extra_edges" && 413 mv full/.git/objects/info/commit-graph commit-graph-upgraded && 414 git -C full commit-graph write --reachable && 415 graph_read_expect -C full 16 \ 416 "generation_data generation_data_overflow extra_edges" && 417 test_cmp full/.git/objects/info/commit-graph commit-graph-upgraded 418' 419 420# the verify tests below expect the commit-graph to contain 421# exactly the commits reachable from the commits/8 branch. 422# If the file changes the set of commits in the list, then the 423# offsets into the binary file will result in different edits 424# and the tests will likely break. 425 426test_expect_success 'git commit-graph verify' ' 427 git -C full rev-parse commits/8 >in && 428 git -C full -c commitGraph.generationVersion=1 commit-graph write \ 429 --stdin-commits <in && 430 git -C full commit-graph verify >output && 431 graph_read_expect -C full 9 extra_edges 1 432' 433 434NUM_COMMITS=9 435NUM_OCTOPUS_EDGES=2 436HASH_LEN="$(test_oid rawsz)" 437GRAPH_BYTE_VERSION=4 438GRAPH_BYTE_HASH=5 439GRAPH_BYTE_CHUNK_COUNT=6 440GRAPH_CHUNK_LOOKUP_OFFSET=8 441GRAPH_CHUNK_LOOKUP_WIDTH=12 442GRAPH_CHUNK_LOOKUP_ROWS=5 443GRAPH_BYTE_OID_FANOUT_ID=$GRAPH_CHUNK_LOOKUP_OFFSET 444GRAPH_BYTE_OID_LOOKUP_ID=$(($GRAPH_CHUNK_LOOKUP_OFFSET + \ 445 1 * $GRAPH_CHUNK_LOOKUP_WIDTH)) 446GRAPH_BYTE_COMMIT_DATA_ID=$(($GRAPH_CHUNK_LOOKUP_OFFSET + \ 447 2 * $GRAPH_CHUNK_LOOKUP_WIDTH)) 448GRAPH_FANOUT_OFFSET=$(($GRAPH_CHUNK_LOOKUP_OFFSET + \ 449 $GRAPH_CHUNK_LOOKUP_WIDTH * $GRAPH_CHUNK_LOOKUP_ROWS)) 450GRAPH_BYTE_FANOUT1=$(($GRAPH_FANOUT_OFFSET + 4 * 4)) 451GRAPH_BYTE_FANOUT2=$(($GRAPH_FANOUT_OFFSET + 4 * 255)) 452GRAPH_OID_LOOKUP_OFFSET=$(($GRAPH_FANOUT_OFFSET + 4 * 256)) 453GRAPH_BYTE_OID_LOOKUP_ORDER=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * 8)) 454GRAPH_BYTE_OID_LOOKUP_MISSING=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * 4 + 10)) 455GRAPH_COMMIT_DATA_WIDTH=$(($HASH_LEN + 16)) 456GRAPH_COMMIT_DATA_OFFSET=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * $NUM_COMMITS)) 457GRAPH_BYTE_COMMIT_TREE=$GRAPH_COMMIT_DATA_OFFSET 458GRAPH_BYTE_COMMIT_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN)) 459GRAPH_BYTE_COMMIT_EXTRA_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 4)) 460GRAPH_BYTE_COMMIT_WRONG_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 3)) 461GRAPH_BYTE_COMMIT_GENERATION=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 11)) 462GRAPH_BYTE_COMMIT_GENERATION_LAST=$(($GRAPH_BYTE_COMMIT_GENERATION + $(($NUM_COMMITS - 1)) * $GRAPH_COMMIT_DATA_WIDTH)) 463GRAPH_BYTE_COMMIT_DATE=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 12)) 464GRAPH_OCTOPUS_DATA_OFFSET=$(($GRAPH_COMMIT_DATA_OFFSET + \ 465 $GRAPH_COMMIT_DATA_WIDTH * $NUM_COMMITS)) 466GRAPH_BYTE_OCTOPUS=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4)) 467GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES)) 468 469corrupt_graph_setup() { 470 test_when_finished mv commit-graph-backup full/$objdir/info/commit-graph && 471 cp full/$objdir/info/commit-graph commit-graph-backup && 472 chmod u+w full/$objdir/info/commit-graph 473} 474 475corrupt_graph_verify() { 476 grepstr=$1 477 test_must_fail git -C full commit-graph verify 2>test_err && 478 grep -v "^+" test_err >err && 479 test_grep "$grepstr" err && 480 if test "$2" != "no-copy" 481 then 482 cp full/$objdir/info/commit-graph commit-graph-pre-write-test 483 fi && 484 git -C full status --short && 485 GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE=true git -C full commit-graph write && 486 chmod u+w full/$objdir/info/commit-graph && 487 git -C full commit-graph verify 488} 489 490# usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>] 491# Manipulates the commit-graph file at the position 492# by inserting the data, optionally zeroing the file 493# starting at <zero_pos>, then runs 'git commit-graph verify' 494# and places the output in the file 'err'. Test 'err' for 495# the given string. 496corrupt_graph_and_verify() { 497 pos=$1 498 data="${2:-\0}" 499 grepstr=$3 500 corrupt_graph_setup && 501 orig_size=$(wc -c <full/$objdir/info/commit-graph) && 502 zero_pos=${4:-${orig_size}} && 503 printf "$data" | dd of="full/$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc && 504 dd of="full/$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null && 505 test-tool genzeros $(($orig_size - $zero_pos)) >>"full/$objdir/info/commit-graph" && 506 corrupt_graph_verify "$grepstr" 507 508} 509 510test_expect_success POSIXPERM,SANITY 'detect permission problem' ' 511 corrupt_graph_setup && 512 chmod 000 full/$objdir/info/commit-graph && 513 corrupt_graph_verify "Could not open" "no-copy" 514' 515 516test_expect_success 'detect too small' ' 517 corrupt_graph_setup && 518 echo "a small graph" >full/$objdir/info/commit-graph && 519 corrupt_graph_verify "too small" 520' 521 522test_expect_success 'detect bad signature' ' 523 corrupt_graph_and_verify 0 "\0" \ 524 "graph signature" 525' 526 527test_expect_success 'detect bad version' ' 528 corrupt_graph_and_verify $GRAPH_BYTE_VERSION "\02" \ 529 "graph version" 530' 531 532test_expect_success 'detect bad hash version' ' 533 corrupt_graph_and_verify $GRAPH_BYTE_HASH "\03" \ 534 "hash version" 535' 536 537test_expect_success 'detect low chunk count' ' 538 corrupt_graph_and_verify $GRAPH_BYTE_CHUNK_COUNT "\01" \ 539 "final chunk has non-zero id" 540' 541 542test_expect_success 'detect missing OID fanout chunk' ' 543 corrupt_graph_and_verify $GRAPH_BYTE_OID_FANOUT_ID "\0" \ 544 "commit-graph required OID fanout chunk missing or corrupted" 545' 546 547test_expect_success 'detect missing OID lookup chunk' ' 548 corrupt_graph_and_verify $GRAPH_BYTE_OID_LOOKUP_ID "\0" \ 549 "commit-graph required OID lookup chunk missing or corrupted" 550' 551 552test_expect_success 'detect missing commit data chunk' ' 553 corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_DATA_ID "\0" \ 554 "commit-graph required commit data chunk missing or corrupted" 555' 556 557test_expect_success 'detect incorrect fanout' ' 558 corrupt_graph_and_verify $GRAPH_BYTE_FANOUT1 "\01" \ 559 "fanout value" 560' 561 562test_expect_success 'detect incorrect fanout final value' ' 563 corrupt_graph_and_verify $GRAPH_BYTE_FANOUT2 "\01" \ 564 "OID lookup chunk is the wrong size" 565' 566 567test_expect_success 'detect incorrect OID order' ' 568 corrupt_graph_and_verify $GRAPH_BYTE_OID_LOOKUP_ORDER "\01" \ 569 "incorrect OID order" 570' 571 572test_expect_success 'detect OID not in object database' ' 573 corrupt_graph_and_verify $GRAPH_BYTE_OID_LOOKUP_MISSING "\01" \ 574 "from object database" 575' 576 577test_expect_success 'detect incorrect tree OID' ' 578 corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_TREE "\01" \ 579 "root tree OID for commit" 580' 581 582test_expect_success 'detect incorrect parent int-id' ' 583 corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_PARENT "\01" \ 584 "invalid parent" 585' 586 587test_expect_success 'detect extra parent int-id' ' 588 corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_EXTRA_PARENT "\00" \ 589 "is too long" 590' 591 592test_expect_success 'detect wrong parent' ' 593 corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_WRONG_PARENT "\01" \ 594 "commit-graph parent for" 595' 596 597test_expect_success 'detect incorrect generation number' ' 598 corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\070" \ 599 "generation for commit" 600' 601 602test_expect_success 'detect incorrect commit date' ' 603 corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_DATE "\01" \ 604 "commit date" 605' 606 607test_expect_success 'detect incorrect parent for octopus merge' ' 608 corrupt_graph_and_verify $GRAPH_BYTE_OCTOPUS "\01" \ 609 "invalid parent" 610' 611 612test_expect_success 'detect invalid checksum hash' ' 613 corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ 614 "incorrect checksum" 615' 616 617test_expect_success 'detect incorrect chunk count' ' 618 corrupt_graph_and_verify $GRAPH_BYTE_CHUNK_COUNT "\377" \ 619 "commit-graph file is too small to hold [0-9]* chunks" \ 620 $GRAPH_CHUNK_LOOKUP_OFFSET 621' 622 623test_expect_success 'detect mixed generation numbers (non-zero to zero)' ' 624 corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION_LAST "\0\0\0\0" \ 625 "both zero and non-zero generations" 626' 627 628test_expect_success 'detect mixed generation numbers (zero to non-zero)' ' 629 corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\0\0\0\0" \ 630 "both zero and non-zero generations" 631' 632 633test_expect_success 'git fsck (checks commit-graph when config set to true)' ' 634 git -C full fsck && 635 corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ 636 "incorrect checksum" && 637 cp commit-graph-pre-write-test full/$objdir/info/commit-graph && 638 test_must_fail git -C full -c core.commitGraph=true fsck 639' 640 641test_expect_success 'git fsck (ignores commit-graph when config set to false)' ' 642 git -C full fsck && 643 corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ 644 "incorrect checksum" && 645 cp commit-graph-pre-write-test full/$objdir/info/commit-graph && 646 git -C full -c core.commitGraph=false fsck 647' 648 649test_expect_success 'git fsck (checks commit-graph when config unset)' ' 650 test_when_finished "git -C full config core.commitGraph true" && 651 652 git -C full fsck && 653 corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ 654 "incorrect checksum" && 655 test_unconfig -C full core.commitGraph && 656 cp commit-graph-pre-write-test full/$objdir/info/commit-graph && 657 test_must_fail git -C full fsck 658' 659 660test_expect_success 'git fsck shows commit-graph output with --progress' ' 661 git -C "$TRASH_DIRECTORY/full" fsck --progress 2>err && 662 grep "Verifying commits in commit graph" err 663' 664 665test_expect_success 'git fsck suppresses commit-graph output with --no-progress' ' 666 git -C "$TRASH_DIRECTORY/full" fsck --no-progress 2>err && 667 ! grep "Verifying commits in commit graph" err 668' 669 670test_expect_success 'setup non-the_repository tests' ' 671 rm -rf repo && 672 git init repo && 673 test_commit -C repo one && 674 test_commit -C repo two && 675 git -C repo config core.commitGraph true && 676 git -C repo rev-parse two | \ 677 git -C repo commit-graph write --stdin-commits 678' 679 680test_expect_success 'parse_commit_in_graph works for non-the_repository' ' 681 test-tool repository parse_commit_in_graph \ 682 repo/.git repo "$(git -C repo rev-parse two)" >actual && 683 { 684 git -C repo log --pretty=format:"%ct " -1 && 685 git -C repo rev-parse one 686 } >expect && 687 test_cmp expect actual && 688 689 test-tool repository parse_commit_in_graph \ 690 repo/.git repo "$(git -C repo rev-parse one)" >actual && 691 git -C repo log --pretty="%ct" -1 one >expect && 692 test_cmp expect actual 693' 694 695test_expect_success 'get_commit_tree_in_graph works for non-the_repository' ' 696 test-tool repository get_commit_tree_in_graph \ 697 repo/.git repo "$(git -C repo rev-parse two)" >actual && 698 git -C repo rev-parse two^{tree} >expect && 699 test_cmp expect actual && 700 701 test-tool repository get_commit_tree_in_graph \ 702 repo/.git repo "$(git -C repo rev-parse one)" >actual && 703 git -C repo rev-parse one^{tree} >expect && 704 test_cmp expect actual 705' 706 707test_expect_success 'corrupt commit-graph write (broken parent)' ' 708 rm -rf repo && 709 git init repo && 710 ( 711 cd repo && 712 empty="$(git mktree </dev/null)" && 713 cat >broken <<-EOF && 714 tree $empty 715 parent $ZERO_OID 716 author whatever <whatever@example.com> 1234 -0000 717 committer whatever <whatever@example.com> 1234 -0000 718 719 broken commit 720 EOF 721 broken="$(git hash-object -w -t commit --literally broken)" && 722 git commit-tree -p "$broken" -m "good commit" "$empty" >good && 723 test_must_fail git commit-graph write --stdin-commits \ 724 <good 2>test_err && 725 test_grep "unable to parse commit" test_err 726 ) 727' 728 729test_expect_success 'corrupt commit-graph write (missing tree)' ' 730 rm -rf repo && 731 git init repo && 732 ( 733 cd repo && 734 tree="$(git mktree </dev/null)" && 735 cat >broken <<-EOF && 736 parent $ZERO_OID 737 author whatever <whatever@example.com> 1234 -0000 738 committer whatever <whatever@example.com> 1234 -0000 739 740 broken commit 741 EOF 742 broken="$(git hash-object -w -t commit --literally broken)" && 743 git commit-tree -p "$broken" -m "good" "$tree" >good && 744 test_must_fail git commit-graph write --stdin-commits \ 745 <good 2>test_err && 746 test_grep "unable to parse commit" test_err 747 ) 748' 749 750# We test the overflow-related code with the following repo history: 751# 752# 4:F - 5:N - 6:U 753# / \ 754# 1:U - 2:N - 3:U M:N 755# \ / 756# 7:N - 8:F - 9:N 757# 758# Here the commits denoted by U have committer date of zero seconds 759# since Unix epoch, the commits denoted by N have committer date 760# starting from 1112354055 seconds since Unix epoch (default committer 761# date for the test suite), and the commits denoted by F have committer 762# date of (2 ^ 31 - 2) seconds since Unix epoch. 763# 764# The largest offset observed is 2 ^ 31, just large enough to overflow. 765# 766 767test_expect_success 'set up and verify repo with generation data overflow chunk' ' 768 UNIX_EPOCH_ZERO="@0 +0000" && 769 FUTURE_DATE="@2147483646 +0000" && 770 771 git init repo && 772 ( 773 cd repo && 774 775 test_commit --date "$UNIX_EPOCH_ZERO" 1 && 776 test_commit 2 && 777 test_commit --date "$UNIX_EPOCH_ZERO" 3 && 778 git commit-graph write --reachable && 779 graph_read_expect 3 generation_data && 780 test_commit --date "$FUTURE_DATE" 4 && 781 test_commit 5 && 782 test_commit --date "$UNIX_EPOCH_ZERO" 6 && 783 git branch left && 784 git reset --hard 3 && 785 test_commit 7 && 786 test_commit --date "$FUTURE_DATE" 8 && 787 test_commit 9 && 788 git branch right && 789 git reset --hard 3 && 790 test_merge M left right && 791 git commit-graph write --reachable && 792 graph_read_expect 10 "generation_data generation_data_overflow" && 793 git commit-graph verify 794 ) 795' 796 797graph_git_behavior 'generation data overflow chunk repo' repo left right 798 799test_expect_success 'overflow during generation version upgrade' ' 800 git init overflow-v2-upgrade && 801 ( 802 cd overflow-v2-upgrade && 803 804 # This commit will have a date at two seconds past the Epoch, 805 # and a (v1) generation number of 1, since it is a root commit. 806 # 807 # The offset will then be computed as 1-2, which will underflow 808 # to 2^31, which is greater than the v2 offset small limit of 809 # 2^31-1. 810 # 811 # This is sufficient to need a large offset table for the v2 812 # generation numbers. 813 test_commit --date "@2 +0000" base && 814 git repack -d && 815 816 # Test that upgrading from generation v1 to v2 correctly 817 # produces the overflow table. 818 git -c commitGraph.generationVersion=1 commit-graph write && 819 git -c commitGraph.generationVersion=2 commit-graph write \ 820 --changed-paths && 821 822 git rev-list --all 823 ) 824' 825 826corrupt_chunk () { 827 graph=full/.git/objects/info/commit-graph && 828 test_when_finished "rm -rf $graph" && 829 git -C full commit-graph write --reachable && 830 corrupt_chunk_file $graph "$@" 831} 832 833check_corrupt_chunk () { 834 corrupt_chunk "$@" && 835 git -C full -c core.commitGraph=false log >expect.out && 836 git -C full -c core.commitGraph=true log >out 2>err && 837 test_cmp expect.out out 838} 839 840test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' ' 841 # make it big enough that the graph file is plausible, 842 # otherwise we hit an earlier check 843 check_corrupt_chunk OIDF clear $(printf "000000%02x" $(test_seq 250)) && 844 cat >expect.err <<-\EOF && 845 error: commit-graph oid fanout chunk is wrong size 846 error: commit-graph required OID fanout chunk missing or corrupted 847 EOF 848 test_cmp expect.err err 849' 850 851test_expect_success PERL_TEST_HELPERS 'reader notices fanout/lookup table mismatch' ' 852 check_corrupt_chunk OIDF 1020 "FFFFFFFF" && 853 cat >expect.err <<-\EOF && 854 error: commit-graph OID lookup chunk is the wrong size 855 error: commit-graph required OID lookup chunk missing or corrupted 856 EOF 857 test_cmp expect.err err 858' 859 860test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' ' 861 # Rather than try to corrupt a specific hash, we will just 862 # wreck them all. But we cannot just set them all to 0xFFFFFFFF or 863 # similar, as they are used for hi/lo starts in a binary search (so if 864 # they are identical, that indicates that the search should abort 865 # immediately). Instead, we will give them high values that differ by 866 # 2^24, ensuring that any that are used would cause an out-of-bounds 867 # read. 868 check_corrupt_chunk OIDF 0 $(printf "%02x000000" $(test_seq 0 254)) && 869 cat >expect.err <<-\EOF && 870 error: commit-graph fanout values out of order 871 error: commit-graph required OID fanout chunk missing or corrupted 872 EOF 873 test_cmp expect.err err 874' 875 876test_expect_success PERL_TEST_HELPERS 'reader notices too-small commit data chunk' ' 877 check_corrupt_chunk CDAT clear 00000000 && 878 cat >expect.err <<-\EOF && 879 error: commit-graph commit data chunk is wrong size 880 error: commit-graph required commit data chunk missing or corrupted 881 EOF 882 test_cmp expect.err err 883' 884 885test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds extra edge' ' 886 check_corrupt_chunk EDGE clear && 887 cat >expect.err <<-\EOF && 888 error: commit-graph extra-edges pointer out of bounds 889 EOF 890 test_cmp expect.err err 891' 892 893test_expect_success PERL_TEST_HELPERS 'reader notices too-small generations chunk' ' 894 check_corrupt_chunk GDA2 clear 00000000 && 895 cat >expect.err <<-\EOF && 896 error: commit-graph generations chunk is wrong size 897 EOF 898 test_cmp expect.err err 899' 900 901test_expect_success 'stale commit cannot be parsed when given directly' ' 902 test_when_finished "rm -rf repo" && 903 git init repo && 904 ( 905 cd repo && 906 test_commit A && 907 test_commit B && 908 git commit-graph write --reachable && 909 910 oid=$(git rev-parse B) && 911 rm .git/objects/"$(test_oid_to_path "$oid")" && 912 913 # Verify that it is possible to read the commit from the 914 # commit graph when not being paranoid, ... 915 git rev-list B && 916 # ... but parsing the commit when double checking that 917 # it actually exists in the object database should fail. 918 test_must_fail env GIT_COMMIT_GRAPH_PARANOIA=true git rev-list -1 B 919 ) 920' 921 922test_expect_success 'stale commit cannot be parsed when traversing graph' ' 923 test_when_finished "rm -rf repo" && 924 git init repo && 925 ( 926 cd repo && 927 928 test_commit A && 929 test_commit B && 930 test_commit C && 931 git commit-graph write --reachable && 932 933 # Corrupt the repository by deleting the intermediate commit 934 # object. Commands should notice that this object is absent and 935 # thus that the repository is corrupt even if the commit graph 936 # exists. 937 oid=$(git rev-parse B) && 938 rm .git/objects/"$(test_oid_to_path "$oid")" && 939 940 # Again, we should be able to parse the commit when not 941 # being paranoid about commit graph staleness... 942 git rev-parse HEAD~2 && 943 # ... but fail when we are paranoid. 944 test_must_fail env GIT_COMMIT_GRAPH_PARANOIA=true git rev-parse HEAD~2 2>error && 945 grep "error: commit $oid exists in commit-graph but not in the object database" error 946 ) 947' 948 949test_done