t / t5703-upload-pack-ref-in-want.shon commit upload-pack: test negotiation with changing repository (3374292)
   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 $(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 behind - no ref in want' '
 215        git -C "$REPO" config uploadpack.allowRefInWant false &&
 216        rm -rf local &&
 217        cp -r "$LOCAL_PRISTINE" local &&
 218        inconsistency master "master^" &&
 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
 226stop_httpd
 227
 228test_done