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