t / t1404-update-ref-errors.shon commit submodule: port submodule subcommand 'status' from shell to C (a9f8a37)
   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