t / t5703-upload-pack-ref-in-want.shon commit Merge branch 'es/local-atomic-push-failure-with-http' into maint (1a27b78)
   1#!/bin/sh
   2
   3test_description='upload-pack ref-in-want'
   4
   5. ./test-lib.sh
   6
   7get_actual_refs () {
   8        sed -n -e '/wanted-refs/,/0001/{
   9                /wanted-refs/d
  10                /0001/d
  11                p
  12                }' <out | test-tool pkt-line unpack >actual_refs
  13}
  14
  15get_actual_commits () {
  16        sed -n -e '/packfile/,/0000/{
  17                /packfile/d
  18                p
  19                }' <out | test-tool pkt-line unpack-sideband >o.pack &&
  20        git index-pack o.pack &&
  21        git verify-pack -v o.idx | grep commit | cut -c-40 | sort >actual_commits
  22}
  23
  24check_output () {
  25        get_actual_refs &&
  26        test_cmp expected_refs actual_refs &&
  27        get_actual_commits &&
  28        test_cmp expected_commits actual_commits
  29}
  30
  31# c(o/foo) d(o/bar)
  32#        \ /
  33#         b   e(baz)  f(master)
  34#          \__  |  __/
  35#             \ | /
  36#               a
  37test_expect_success 'setup repository' '
  38        test_commit a &&
  39        git checkout -b o/foo &&
  40        test_commit b &&
  41        test_commit c &&
  42        git checkout -b o/bar b &&
  43        test_commit d &&
  44        git checkout -b baz a &&
  45        test_commit e &&
  46        git checkout master &&
  47        test_commit f
  48'
  49
  50test_expect_success 'config controls ref-in-want advertisement' '
  51        test-tool serve-v2 --advertise-capabilities >out &&
  52        ! grep -a ref-in-want out &&
  53
  54        git config uploadpack.allowRefInWant false &&
  55        test-tool serve-v2 --advertise-capabilities >out &&
  56        ! grep -a ref-in-want out &&
  57
  58        git config uploadpack.allowRefInWant true &&
  59        test-tool serve-v2 --advertise-capabilities >out &&
  60        grep -a ref-in-want out
  61'
  62
  63test_expect_success 'invalid want-ref line' '
  64        test-tool pkt-line pack >in <<-EOF &&
  65        command=fetch
  66        0001
  67        no-progress
  68        want-ref refs/heads/non-existent
  69        done
  70        0000
  71        EOF
  72
  73        test_must_fail test-tool serve-v2 --stateless-rpc 2>out <in &&
  74        grep "unknown ref" out
  75'
  76
  77test_expect_success 'basic want-ref' '
  78        cat >expected_refs <<-EOF &&
  79        $(git rev-parse f) refs/heads/master
  80        EOF
  81        git rev-parse f | sort >expected_commits &&
  82
  83        test-tool pkt-line pack >in <<-EOF &&
  84        command=fetch
  85        0001
  86        no-progress
  87        want-ref refs/heads/master
  88        have $(git rev-parse a)
  89        done
  90        0000
  91        EOF
  92
  93        test-tool serve-v2 --stateless-rpc >out <in &&
  94        check_output
  95'
  96
  97test_expect_success 'multiple want-ref lines' '
  98        cat >expected_refs <<-EOF &&
  99        $(git rev-parse c) refs/heads/o/foo
 100        $(git rev-parse d) refs/heads/o/bar
 101        EOF
 102        git rev-parse c d | sort >expected_commits &&
 103
 104        test-tool pkt-line pack >in <<-EOF &&
 105        command=fetch
 106        0001
 107        no-progress
 108        want-ref refs/heads/o/foo
 109        want-ref refs/heads/o/bar
 110        have $(git rev-parse b)
 111        done
 112        0000
 113        EOF
 114
 115        test-tool serve-v2 --stateless-rpc >out <in &&
 116        check_output
 117'
 118
 119test_expect_success 'mix want and want-ref' '
 120        cat >expected_refs <<-EOF &&
 121        $(git rev-parse f) refs/heads/master
 122        EOF
 123        git rev-parse e f | sort >expected_commits &&
 124
 125        test-tool pkt-line pack >in <<-EOF &&
 126        command=fetch
 127        0001
 128        no-progress
 129        want-ref refs/heads/master
 130        want $(git rev-parse e)
 131        have $(git rev-parse a)
 132        done
 133        0000
 134        EOF
 135
 136        test-tool serve-v2 --stateless-rpc >out <in &&
 137        check_output
 138'
 139
 140test_expect_success 'want-ref with ref we already have commit for' '
 141        cat >expected_refs <<-EOF &&
 142        $(git rev-parse c) refs/heads/o/foo
 143        EOF
 144        >expected_commits &&
 145
 146        test-tool pkt-line pack >in <<-EOF &&
 147        command=fetch
 148        0001
 149        no-progress
 150        want-ref refs/heads/o/foo
 151        have $(git rev-parse c)
 152        done
 153        0000
 154        EOF
 155
 156        test-tool serve-v2 --stateless-rpc >out <in &&
 157        check_output
 158'
 159
 160. "$TEST_DIRECTORY"/lib-httpd.sh
 161start_httpd
 162
 163REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
 164LOCAL_PRISTINE="$(pwd)/local_pristine"
 165
 166test_expect_success 'setup repos for change-while-negotiating test' '
 167        (
 168                git init "$REPO" &&
 169                cd "$REPO" &&
 170                >.git/git-daemon-export-ok &&
 171                test_commit m1 &&
 172                git tag -d m1 &&
 173
 174                # Local repo with many commits (so that negotiation will take
 175                # more than 1 request/response pair)
 176                git clone "http://127.0.0.1:$LIB_HTTPD_PORT/smart/repo" "$LOCAL_PRISTINE" &&
 177                cd "$LOCAL_PRISTINE" &&
 178                git checkout -b side &&
 179                for i in $(test_seq 1 33); do test_commit s$i; done &&
 180
 181                # Add novel commits to upstream
 182                git checkout master &&
 183                cd "$REPO" &&
 184                test_commit m2 &&
 185                test_commit m3 &&
 186                git tag -d m2 m3
 187        ) &&
 188        git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_sed/repo" &&
 189        git -C "$LOCAL_PRISTINE" config protocol.version 2
 190'
 191
 192inconsistency () {
 193        # Simulate that the server initially reports $2 as the ref
 194        # corresponding to $1, and after that, $1 as the ref corresponding to
 195        # $1. This corresponds to the real-life situation where the server's
 196        # repository appears to change during negotiation, for example, when
 197        # different servers in a load-balancing arrangement serve (stateless)
 198        # RPCs during a single negotiation.
 199        printf "s/%s/%s/" \
 200               $(git -C "$REPO" rev-parse $1 | tr -d "\n") \
 201               $(git -C "$REPO" rev-parse $2 | tr -d "\n") \
 202               >"$HTTPD_ROOT_PATH/one-time-sed"
 203}
 204
 205test_expect_success 'server is initially ahead - no ref in want' '
 206        git -C "$REPO" config uploadpack.allowRefInWant false &&
 207        rm -rf local &&
 208        cp -r "$LOCAL_PRISTINE" local &&
 209        inconsistency master 1234567890123456789012345678901234567890 &&
 210        test_must_fail git -C local fetch 2>err &&
 211        test_i18ngrep "fatal: remote error: upload-pack: not our ref" err
 212'
 213
 214test_expect_success 'server is initially ahead - ref in want' '
 215        git -C "$REPO" config uploadpack.allowRefInWant true &&
 216        rm -rf local &&
 217        cp -r "$LOCAL_PRISTINE" local &&
 218        inconsistency master 1234567890123456789012345678901234567890 &&
 219        git -C local fetch &&
 220
 221        git -C "$REPO" rev-parse --verify master >expected &&
 222        git -C local rev-parse --verify refs/remotes/origin/master >actual &&
 223        test_cmp expected actual
 224'
 225
 226test_expect_success 'server is initially behind - no ref in want' '
 227        git -C "$REPO" config uploadpack.allowRefInWant false &&
 228        rm -rf local &&
 229        cp -r "$LOCAL_PRISTINE" local &&
 230        inconsistency master "master^" &&
 231        git -C local fetch &&
 232
 233        git -C "$REPO" rev-parse --verify "master^" >expected &&
 234        git -C local rev-parse --verify refs/remotes/origin/master >actual &&
 235        test_cmp expected actual
 236'
 237
 238test_expect_success 'server is initially behind - ref in want' '
 239        git -C "$REPO" config uploadpack.allowRefInWant true &&
 240        rm -rf local &&
 241        cp -r "$LOCAL_PRISTINE" local &&
 242        inconsistency master "master^" &&
 243        git -C local fetch &&
 244
 245        git -C "$REPO" rev-parse --verify "master" >expected &&
 246        git -C local rev-parse --verify refs/remotes/origin/master >actual &&
 247        test_cmp expected actual
 248'
 249
 250test_expect_success 'server loses a ref - ref in want' '
 251        git -C "$REPO" config uploadpack.allowRefInWant true &&
 252        rm -rf local &&
 253        cp -r "$LOCAL_PRISTINE" local &&
 254        echo "s/master/raster/" >"$HTTPD_ROOT_PATH/one-time-sed" &&
 255        test_must_fail git -C local fetch 2>err &&
 256
 257        test_i18ngrep "fatal: remote error: unknown ref refs/heads/raster" err
 258'
 259
 260REPO="$(pwd)/repo"
 261LOCAL_PRISTINE="$(pwd)/local_pristine"
 262
 263# $REPO
 264# c(o/foo) d(o/bar)
 265#        \ /
 266#         b   e(baz)  f(master)
 267#          \__  |  __/
 268#             \ | /
 269#               a
 270#
 271# $LOCAL_PRISTINE
 272#               s32(side)
 273#               |
 274#               .
 275#               .
 276#               |
 277#               a(master)
 278test_expect_success 'setup repos for fetching with ref-in-want tests' '
 279        (
 280                git init "$REPO" &&
 281                cd "$REPO" &&
 282                test_commit a &&
 283
 284                # Local repo with many commits (so that negotiation will take
 285                # more than 1 request/response pair)
 286                rm -rf "$LOCAL_PRISTINE" &&
 287                git clone "file://$REPO" "$LOCAL_PRISTINE" &&
 288                cd "$LOCAL_PRISTINE" &&
 289                git checkout -b side &&
 290                for i in $(test_seq 1 33); do test_commit s$i; done &&
 291
 292                # Add novel commits to upstream
 293                git checkout master &&
 294                cd "$REPO" &&
 295                git checkout -b o/foo &&
 296                test_commit b &&
 297                test_commit c &&
 298                git checkout -b o/bar b &&
 299                test_commit d &&
 300                git checkout -b baz a &&
 301                test_commit e &&
 302                git checkout master &&
 303                test_commit f
 304        ) &&
 305        git -C "$REPO" config uploadpack.allowRefInWant true &&
 306        git -C "$LOCAL_PRISTINE" config protocol.version 2
 307'
 308
 309test_expect_success 'fetching with exact OID' '
 310        test_when_finished "rm -f log" &&
 311
 312        rm -rf local &&
 313        cp -r "$LOCAL_PRISTINE" local &&
 314        GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin \
 315                $(git -C "$REPO" rev-parse d):refs/heads/actual &&
 316
 317        git -C "$REPO" rev-parse "d" >expected &&
 318        git -C local rev-parse refs/heads/actual >actual &&
 319        test_cmp expected actual &&
 320        grep "want $(git -C "$REPO" rev-parse d)" log
 321'
 322
 323test_expect_success 'fetching multiple refs' '
 324        test_when_finished "rm -f log" &&
 325
 326        rm -rf local &&
 327        cp -r "$LOCAL_PRISTINE" local &&
 328        GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin master baz &&
 329
 330        git -C "$REPO" rev-parse "master" "baz" >expected &&
 331        git -C local rev-parse refs/remotes/origin/master refs/remotes/origin/baz >actual &&
 332        test_cmp expected actual &&
 333        grep "want-ref refs/heads/master" log &&
 334        grep "want-ref refs/heads/baz" log
 335'
 336
 337test_expect_success 'fetching ref and exact OID' '
 338        test_when_finished "rm -f log" &&
 339
 340        rm -rf local &&
 341        cp -r "$LOCAL_PRISTINE" local &&
 342        GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin \
 343                master $(git -C "$REPO" rev-parse b):refs/heads/actual &&
 344
 345        git -C "$REPO" rev-parse "master" "b" >expected &&
 346        git -C local rev-parse refs/remotes/origin/master refs/heads/actual >actual &&
 347        test_cmp expected actual &&
 348        grep "want $(git -C "$REPO" rev-parse b)" log &&
 349        grep "want-ref refs/heads/master" log
 350'
 351
 352test_expect_success 'fetching with wildcard that does not match any refs' '
 353        test_when_finished "rm -f log" &&
 354
 355        rm -rf local &&
 356        cp -r "$LOCAL_PRISTINE" local &&
 357        git -C local fetch origin refs/heads/none*:refs/heads/* >out &&
 358        test_must_be_empty out
 359'
 360
 361test_expect_success 'fetching with wildcard that matches multiple refs' '
 362        test_when_finished "rm -f log" &&
 363
 364        rm -rf local &&
 365        cp -r "$LOCAL_PRISTINE" local &&
 366        GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin refs/heads/o*:refs/heads/o* &&
 367
 368        git -C "$REPO" rev-parse "o/foo" "o/bar" >expected &&
 369        git -C local rev-parse "o/foo" "o/bar" >actual &&
 370        test_cmp expected actual &&
 371        grep "want-ref refs/heads/o/foo" log &&
 372        grep "want-ref refs/heads/o/bar" log
 373'
 374
 375test_done