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