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