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