t / t5703-upload-pack-ref-in-want.shon commit upload-pack: support hidden refs with protocol v2 (e20b419)
   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-pkt-line unpack >actual_refs
  13}
  14
  15get_actual_commits () {
  16        sed -n -e '/packfile/,/0000/{
  17                /packfile/d
  18                p
  19                }' <out | test-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        git serve --advertise-capabilities >out &&
  52        ! grep -a ref-in-want out &&
  53
  54        git config uploadpack.allowRefInWant false &&
  55        git serve --advertise-capabilities >out &&
  56        ! grep -a ref-in-want out &&
  57
  58        git config uploadpack.allowRefInWant true &&
  59        git serve --advertise-capabilities >out &&
  60        grep -a ref-in-want out
  61'
  62
  63test_expect_success 'invalid want-ref line' '
  64        test-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 git serve --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-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        git serve --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-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        git serve --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-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        git serve --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-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        git serve --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        grep "ERR 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        grep "ERR unknown ref refs/heads/raster" err
 258'
 259
 260stop_httpd
 261
 262REPO="$(pwd)/repo"
 263LOCAL_PRISTINE="$(pwd)/local_pristine"
 264
 265# $REPO
 266# c(o/foo) d(o/bar)
 267#        \ /
 268#         b   e(baz)  f(master)
 269#          \__  |  __/
 270#             \ | /
 271#               a
 272#
 273# $LOCAL_PRISTINE
 274#               s32(side)
 275#               |
 276#               .
 277#               .
 278#               |
 279#               a(master)
 280test_expect_success 'setup repos for fetching with ref-in-want tests' '
 281        (
 282                git init "$REPO" &&
 283                cd "$REPO" &&
 284                test_commit a &&
 285
 286                # Local repo with many commits (so that negotiation will take
 287                # more than 1 request/response pair)
 288                rm -rf "$LOCAL_PRISTINE" &&
 289                git clone "file://$REPO" "$LOCAL_PRISTINE" &&
 290                cd "$LOCAL_PRISTINE" &&
 291                git checkout -b side &&
 292                for i in $(test_seq 1 33); do test_commit s$i; done &&
 293
 294                # Add novel commits to upstream
 295                git checkout master &&
 296                cd "$REPO" &&
 297                git checkout -b o/foo &&
 298                test_commit b &&
 299                test_commit c &&
 300                git checkout -b o/bar b &&
 301                test_commit d &&
 302                git checkout -b baz a &&
 303                test_commit e &&
 304                git checkout master &&
 305                test_commit f
 306        ) &&
 307        git -C "$REPO" config uploadpack.allowRefInWant true &&
 308        git -C "$LOCAL_PRISTINE" config protocol.version 2
 309'
 310
 311test_expect_success 'fetching with exact OID' '
 312        test_when_finished "rm -f log" &&
 313
 314        rm -rf local &&
 315        cp -r "$LOCAL_PRISTINE" local &&
 316        GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin \
 317                $(git -C "$REPO" rev-parse d):refs/heads/actual &&
 318
 319        git -C "$REPO" rev-parse "d" >expected &&
 320        git -C local rev-parse refs/heads/actual >actual &&
 321        test_cmp expected actual &&
 322        grep "want $(git -C "$REPO" rev-parse d)" log
 323'
 324
 325test_expect_success 'fetching multiple refs' '
 326        test_when_finished "rm -f log" &&
 327
 328        rm -rf local &&
 329        cp -r "$LOCAL_PRISTINE" local &&
 330        GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin master baz &&
 331
 332        git -C "$REPO" rev-parse "master" "baz" >expected &&
 333        git -C local rev-parse refs/remotes/origin/master refs/remotes/origin/baz >actual &&
 334        test_cmp expected actual &&
 335        grep "want-ref refs/heads/master" log &&
 336        grep "want-ref refs/heads/baz" log
 337'
 338
 339test_expect_success 'fetching ref and exact OID' '
 340        test_when_finished "rm -f log" &&
 341
 342        rm -rf local &&
 343        cp -r "$LOCAL_PRISTINE" local &&
 344        GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin \
 345                master $(git -C "$REPO" rev-parse b):refs/heads/actual &&
 346
 347        git -C "$REPO" rev-parse "master" "b" >expected &&
 348        git -C local rev-parse refs/remotes/origin/master refs/heads/actual >actual &&
 349        test_cmp expected actual &&
 350        grep "want $(git -C "$REPO" rev-parse b)" log &&
 351        grep "want-ref refs/heads/master" log
 352'
 353
 354test_expect_success 'fetching with wildcard that does not match any refs' '
 355        test_when_finished "rm -f log" &&
 356
 357        rm -rf local &&
 358        cp -r "$LOCAL_PRISTINE" local &&
 359        git -C local fetch origin refs/heads/none*:refs/heads/* >out &&
 360        test_must_be_empty out
 361'
 362
 363test_expect_success 'fetching with wildcard that matches multiple refs' '
 364        test_when_finished "rm -f log" &&
 365
 366        rm -rf local &&
 367        cp -r "$LOCAL_PRISTINE" local &&
 368        GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin refs/heads/o*:refs/heads/o* &&
 369
 370        git -C "$REPO" rev-parse "o/foo" "o/bar" >expected &&
 371        git -C local rev-parse "o/foo" "o/bar" >actual &&
 372        test_cmp expected actual &&
 373        grep "want-ref refs/heads/o/foo" log &&
 374        grep "want-ref refs/heads/o/bar" log
 375'
 376
 377test_done