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