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