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