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