add a test for git-send-email for threaded mails without chain-reply-to
[git/spearce.git] / t / t9001-send-email.sh
blob4f67de3ac7f882836444ea46ba938341c7be22cf
1 #!/bin/sh
3 test_description='git send-email'
4 . ./test-lib.sh
6 if ! test_have_prereq PERL; then
7 say 'skipping git send-email tests, perl not available'
8 test_done
9 fi
11 PROG='git send-email'
12 test_expect_success \
13 'prepare reference tree' \
14 'echo "1A quick brown fox jumps over the" >file &&
15 echo "lazy dog" >>file &&
16 git add file &&
17 GIT_AUTHOR_NAME="A" git commit -a -m "Initial."'
19 test_expect_success \
20 'Setup helper tool' \
21 '(echo "#!$SHELL_PATH"
22 echo shift
23 echo output=1
24 echo "while test -f commandline\$output; do output=\$((\$output+1)); done"
25 echo for a
26 echo do
27 echo " echo \"!\$a!\""
28 echo "done >commandline\$output"
29 echo "cat > msgtxt\$output"
30 ) >fake.sendmail &&
31 chmod +x ./fake.sendmail &&
32 git add fake.sendmail &&
33 GIT_AUTHOR_NAME="A" git commit -a -m "Second."'
35 clean_fake_sendmail() {
36 rm -f commandline* msgtxt*
39 test_expect_success 'Extract patches' '
40 patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
43 # Test no confirm early to ensure remaining tests will not hang
44 test_no_confirm () {
45 rm -f no_confirm_okay
46 echo n | \
47 GIT_SEND_EMAIL_NOTTY=1 \
48 git send-email \
49 --from="Example <from@example.com>" \
50 --to=nobody@example.com \
51 --smtp-server="$(pwd)/fake.sendmail" \
52 $@ \
53 $patches > stdout &&
54 test_must_fail grep "Send this email" stdout &&
55 > no_confirm_okay
58 # Exit immediately to prevent hang if a no-confirm test fails
59 check_no_confirm () {
60 test -f no_confirm_okay || {
61 say 'No confirm test failed; skipping remaining tests to prevent hanging'
62 test_done
66 test_expect_success 'No confirm with --suppress-cc' '
67 test_no_confirm --suppress-cc=sob
69 check_no_confirm
71 test_expect_success 'No confirm with --confirm=never' '
72 test_no_confirm --confirm=never
74 check_no_confirm
76 # leave sendemail.confirm set to never after this so that none of the
77 # remaining tests prompt unintentionally.
78 test_expect_success 'No confirm with sendemail.confirm=never' '
79 git config sendemail.confirm never &&
80 test_no_confirm --compose --subject=foo
82 check_no_confirm
84 test_expect_success 'Send patches' '
85 git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
88 cat >expected <<\EOF
89 !nobody@example.com!
90 !author@example.com!
91 !one@example.com!
92 !two@example.com!
93 EOF
94 test_expect_success \
95 'Verify commandline' \
96 'test_cmp expected commandline1'
98 cat >expected-show-all-headers <<\EOF
99 0001-Second.patch
100 (mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
101 (mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
102 (mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
103 Dry-OK. Log says:
104 Server: relay.example.com
105 MAIL FROM:<from@example.com>
106 RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<bcc@example.com>
107 From: Example <from@example.com>
108 To: to@example.com
109 Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com
110 Subject: [PATCH 1/1] Second.
111 Date: DATE-STRING
112 Message-Id: MESSAGE-ID-STRING
113 X-Mailer: X-MAILER-STRING
114 In-Reply-To: <unique-message-id@example.com>
115 References: <unique-message-id@example.com>
117 Result: OK
120 test_expect_success 'Show all headers' '
121 git send-email \
122 --dry-run \
123 --suppress-cc=sob \
124 --from="Example <from@example.com>" \
125 --to=to@example.com \
126 --cc=cc@example.com \
127 --bcc=bcc@example.com \
128 --in-reply-to="<unique-message-id@example.com>" \
129 --smtp-server relay.example.com \
130 $patches |
131 sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \
132 -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
133 -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
134 >actual-show-all-headers &&
135 test_cmp expected-show-all-headers actual-show-all-headers
138 test_expect_success 'Prompting works' '
139 clean_fake_sendmail &&
140 (echo "Example <from@example.com>"
141 echo "to@example.com"
142 echo ""
143 ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \
144 --smtp-server="$(pwd)/fake.sendmail" \
145 $patches \
146 2>errors &&
147 grep "^From: Example <from@example.com>$" msgtxt1 &&
148 grep "^To: to@example.com$" msgtxt1
151 z8=zzzzzzzz
152 z64=$z8$z8$z8$z8$z8$z8$z8$z8
153 z512=$z64$z64$z64$z64$z64$z64$z64$z64
154 test_expect_success 'reject long lines' '
155 clean_fake_sendmail &&
156 cp $patches longline.patch &&
157 echo $z512$z512 >>longline.patch &&
158 test_must_fail git send-email \
159 --from="Example <nobody@example.com>" \
160 --to=nobody@example.com \
161 --smtp-server="$(pwd)/fake.sendmail" \
162 $patches longline.patch \
163 2>errors &&
164 grep longline.patch errors
167 test_expect_success 'no patch was sent' '
168 ! test -e commandline1
171 test_expect_success 'Author From: in message body' '
172 clean_fake_sendmail &&
173 git send-email \
174 --from="Example <nobody@example.com>" \
175 --to=nobody@example.com \
176 --smtp-server="$(pwd)/fake.sendmail" \
177 $patches &&
178 sed "1,/^$/d" < msgtxt1 > msgbody1
179 grep "From: A <author@example.com>" msgbody1
182 test_expect_success 'Author From: not in message body' '
183 clean_fake_sendmail &&
184 git send-email \
185 --from="A <author@example.com>" \
186 --to=nobody@example.com \
187 --smtp-server="$(pwd)/fake.sendmail" \
188 $patches &&
189 sed "1,/^$/d" < msgtxt1 > msgbody1
190 ! grep "From: A <author@example.com>" msgbody1
193 test_expect_success 'allow long lines with --no-validate' '
194 git send-email \
195 --from="Example <nobody@example.com>" \
196 --to=nobody@example.com \
197 --smtp-server="$(pwd)/fake.sendmail" \
198 --novalidate \
199 $patches longline.patch \
200 2>errors
203 test_expect_success 'Invalid In-Reply-To' '
204 clean_fake_sendmail &&
205 git send-email \
206 --from="Example <nobody@example.com>" \
207 --to=nobody@example.com \
208 --in-reply-to=" " \
209 --smtp-server="$(pwd)/fake.sendmail" \
210 $patches
211 2>errors
212 ! grep "^In-Reply-To: < *>" msgtxt1
215 test_expect_success 'Valid In-Reply-To when prompting' '
216 clean_fake_sendmail &&
217 (echo "From Example <from@example.com>"
218 echo "To Example <to@example.com>"
219 echo ""
220 ) | env GIT_SEND_EMAIL_NOTTY=1 git send-email \
221 --smtp-server="$(pwd)/fake.sendmail" \
222 $patches 2>errors &&
223 ! grep "^In-Reply-To: < *>" msgtxt1
226 test_expect_success 'setup fake editor' '
227 (echo "#!$SHELL_PATH" &&
228 echo "echo fake edit >>\"\$1\""
229 ) >fake-editor &&
230 chmod +x fake-editor
233 test_set_editor "$(pwd)/fake-editor"
235 test_expect_success '--compose works' '
236 clean_fake_sendmail &&
237 git send-email \
238 --compose --subject foo \
239 --from="Example <nobody@example.com>" \
240 --to=nobody@example.com \
241 --smtp-server="$(pwd)/fake.sendmail" \
242 $patches \
243 2>errors
246 test_expect_success 'first message is compose text' '
247 grep "^fake edit" msgtxt1
250 test_expect_success 'second message is patch' '
251 grep "Subject:.*Second" msgtxt2
254 cat >expected-suppress-sob <<\EOF
255 0001-Second.patch
256 (mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
257 (mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
258 (mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
259 Dry-OK. Log says:
260 Server: relay.example.com
261 MAIL FROM:<from@example.com>
262 RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
263 From: Example <from@example.com>
264 To: to@example.com
265 Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com
266 Subject: [PATCH 1/1] Second.
267 Date: DATE-STRING
268 Message-Id: MESSAGE-ID-STRING
269 X-Mailer: X-MAILER-STRING
271 Result: OK
274 test_suppression () {
275 git send-email \
276 --dry-run \
277 --suppress-cc=$1 \
278 --from="Example <from@example.com>" \
279 --to=to@example.com \
280 --smtp-server relay.example.com \
281 $patches |
282 sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \
283 -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
284 -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
285 >actual-suppress-$1 &&
286 test_cmp expected-suppress-$1 actual-suppress-$1
289 test_expect_success 'sendemail.cc set' '
290 git config sendemail.cc cc@example.com &&
291 test_suppression sob
294 cat >expected-suppress-sob <<\EOF
295 0001-Second.patch
296 (mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
297 (mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
298 (mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
299 Dry-OK. Log says:
300 Server: relay.example.com
301 MAIL FROM:<from@example.com>
302 RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
303 From: Example <from@example.com>
304 To: to@example.com
305 Cc: A <author@example.com>, One <one@example.com>, two@example.com
306 Subject: [PATCH 1/1] Second.
307 Date: DATE-STRING
308 Message-Id: MESSAGE-ID-STRING
309 X-Mailer: X-MAILER-STRING
311 Result: OK
314 test_expect_success 'sendemail.cc unset' '
315 git config --unset sendemail.cc &&
316 test_suppression sob
319 cat >expected-suppress-all <<\EOF
320 0001-Second.patch
321 Dry-OK. Log says:
322 Server: relay.example.com
323 MAIL FROM:<from@example.com>
324 RCPT TO:<to@example.com>
325 From: Example <from@example.com>
326 To: to@example.com
327 Subject: [PATCH 1/1] Second.
328 Date: DATE-STRING
329 Message-Id: MESSAGE-ID-STRING
330 X-Mailer: X-MAILER-STRING
332 Result: OK
335 test_expect_success '--suppress-cc=all' '
336 test_suppression all
339 cat >expected-suppress-body <<\EOF
340 0001-Second.patch
341 (mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
342 (mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
343 (mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
344 Dry-OK. Log says:
345 Server: relay.example.com
346 MAIL FROM:<from@example.com>
347 RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
348 From: Example <from@example.com>
349 To: to@example.com
350 Cc: A <author@example.com>, One <one@example.com>, two@example.com
351 Subject: [PATCH 1/1] Second.
352 Date: DATE-STRING
353 Message-Id: MESSAGE-ID-STRING
354 X-Mailer: X-MAILER-STRING
356 Result: OK
359 test_expect_success '--suppress-cc=body' '
360 test_suppression body
363 cat >expected-suppress-sob <<\EOF
364 0001-Second.patch
365 (mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
366 (mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
367 (mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
368 Dry-OK. Log says:
369 Server: relay.example.com
370 MAIL FROM:<from@example.com>
371 RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
372 From: Example <from@example.com>
373 To: to@example.com
374 Cc: A <author@example.com>, One <one@example.com>, two@example.com
375 Subject: [PATCH 1/1] Second.
376 Date: DATE-STRING
377 Message-Id: MESSAGE-ID-STRING
378 X-Mailer: X-MAILER-STRING
380 Result: OK
383 test_expect_success '--suppress-cc=sob' '
384 test_suppression sob
387 cat >expected-suppress-bodycc <<\EOF
388 0001-Second.patch
389 (mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
390 (mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
391 (mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
392 (body) Adding cc: C O Mitter <committer@example.com> from line 'Signed-off-by: C O Mitter <committer@example.com>'
393 Dry-OK. Log says:
394 Server: relay.example.com
395 MAIL FROM:<from@example.com>
396 RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<committer@example.com>
397 From: Example <from@example.com>
398 To: to@example.com
399 Cc: A <author@example.com>, One <one@example.com>, two@example.com, C O Mitter <committer@example.com>
400 Subject: [PATCH 1/1] Second.
401 Date: DATE-STRING
402 Message-Id: MESSAGE-ID-STRING
403 X-Mailer: X-MAILER-STRING
405 Result: OK
408 test_expect_success '--suppress-cc=bodycc' '
409 test_suppression bodycc
412 cat >expected-suppress-cc <<\EOF
413 0001-Second.patch
414 (mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
415 (body) Adding cc: C O Mitter <committer@example.com> from line 'Signed-off-by: C O Mitter <committer@example.com>'
416 Dry-OK. Log says:
417 Server: relay.example.com
418 MAIL FROM:<from@example.com>
419 RCPT TO:<to@example.com>,<author@example.com>,<committer@example.com>
420 From: Example <from@example.com>
421 To: to@example.com
422 Cc: A <author@example.com>, C O Mitter <committer@example.com>
423 Subject: [PATCH 1/1] Second.
424 Date: DATE-STRING
425 Message-Id: MESSAGE-ID-STRING
426 X-Mailer: X-MAILER-STRING
428 Result: OK
431 test_expect_success '--suppress-cc=cc' '
432 test_suppression cc
435 test_confirm () {
436 echo y | \
437 GIT_SEND_EMAIL_NOTTY=1 \
438 git send-email \
439 --from="Example <nobody@example.com>" \
440 --to=nobody@example.com \
441 --smtp-server="$(pwd)/fake.sendmail" \
442 $@ $patches > stdout &&
443 grep "Send this email" stdout
446 test_expect_success '--confirm=always' '
447 test_confirm --confirm=always --suppress-cc=all
450 test_expect_success '--confirm=auto' '
451 test_confirm --confirm=auto
454 test_expect_success '--confirm=cc' '
455 test_confirm --confirm=cc
458 test_expect_success '--confirm=compose' '
459 test_confirm --confirm=compose --compose
462 test_expect_success 'confirm by default (due to cc)' '
463 CONFIRM=$(git config --get sendemail.confirm) &&
464 git config --unset sendemail.confirm &&
465 test_confirm
466 ret="$?"
467 git config sendemail.confirm ${CONFIRM:-never}
468 test $ret = "0"
471 test_expect_success 'confirm by default (due to --compose)' '
472 CONFIRM=$(git config --get sendemail.confirm) &&
473 git config --unset sendemail.confirm &&
474 test_confirm --suppress-cc=all --compose
475 ret="$?"
476 git config sendemail.confirm ${CONFIRM:-never}
477 test $ret = "0"
480 test_expect_success 'confirm detects EOF (inform assumes y)' '
481 CONFIRM=$(git config --get sendemail.confirm) &&
482 git config --unset sendemail.confirm &&
483 rm -fr outdir &&
484 git format-patch -2 -o outdir &&
485 GIT_SEND_EMAIL_NOTTY=1 \
486 git send-email \
487 --from="Example <nobody@example.com>" \
488 --to=nobody@example.com \
489 --smtp-server="$(pwd)/fake.sendmail" \
490 outdir/*.patch < /dev/null
491 ret="$?"
492 git config sendemail.confirm ${CONFIRM:-never}
493 test $ret = "0"
496 test_expect_success 'confirm detects EOF (auto causes failure)' '
497 CONFIRM=$(git config --get sendemail.confirm) &&
498 git config sendemail.confirm auto &&
499 GIT_SEND_EMAIL_NOTTY=1 &&
500 export GIT_SEND_EMAIL_NOTTY &&
501 test_must_fail git send-email \
502 --from="Example <nobody@example.com>" \
503 --to=nobody@example.com \
504 --smtp-server="$(pwd)/fake.sendmail" \
505 $patches < /dev/null
506 ret="$?"
507 git config sendemail.confirm ${CONFIRM:-never}
508 test $ret = "0"
511 test_expect_success 'confirm doesnt loop forever' '
512 CONFIRM=$(git config --get sendemail.confirm) &&
513 git config sendemail.confirm auto &&
514 GIT_SEND_EMAIL_NOTTY=1 &&
515 export GIT_SEND_EMAIL_NOTTY &&
516 yes "bogus" | test_must_fail git send-email \
517 --from="Example <nobody@example.com>" \
518 --to=nobody@example.com \
519 --smtp-server="$(pwd)/fake.sendmail" \
520 $patches
521 ret="$?"
522 git config sendemail.confirm ${CONFIRM:-never}
523 test $ret = "0"
526 test_expect_success 'utf8 Cc is rfc2047 encoded' '
527 clean_fake_sendmail &&
528 rm -fr outdir &&
529 git format-patch -1 -o outdir --cc="àéìöú <utf8@example.com>" &&
530 git send-email \
531 --from="Example <nobody@example.com>" \
532 --to=nobody@example.com \
533 --smtp-server="$(pwd)/fake.sendmail" \
534 outdir/*.patch &&
535 grep "^Cc:" msgtxt1 |
536 grep "=?UTF-8?q?=C3=A0=C3=A9=C3=AC=C3=B6=C3=BA?= <utf8@example.com>"
539 test_expect_success '--compose adds MIME for utf8 body' '
540 clean_fake_sendmail &&
541 (echo "#!$SHELL_PATH" &&
542 echo "echo utf8 body: àéìöú >>\"\$1\""
543 ) >fake-editor-utf8 &&
544 chmod +x fake-editor-utf8 &&
545 GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
546 git send-email \
547 --compose --subject foo \
548 --from="Example <nobody@example.com>" \
549 --to=nobody@example.com \
550 --smtp-server="$(pwd)/fake.sendmail" \
551 $patches &&
552 grep "^utf8 body" msgtxt1 &&
553 grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1
556 test_expect_success '--compose respects user mime type' '
557 clean_fake_sendmail &&
558 (echo "#!$SHELL_PATH" &&
559 echo "(echo MIME-Version: 1.0"
560 echo " echo Content-Type: text/plain\\; charset=iso-8859-1"
561 echo " echo Content-Transfer-Encoding: 8bit"
562 echo " echo Subject: foo"
563 echo " echo "
564 echo " echo utf8 body: àéìöú) >\"\$1\""
565 ) >fake-editor-utf8-mime &&
566 chmod +x fake-editor-utf8-mime &&
567 GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
568 git send-email \
569 --compose --subject foo \
570 --from="Example <nobody@example.com>" \
571 --to=nobody@example.com \
572 --smtp-server="$(pwd)/fake.sendmail" \
573 $patches &&
574 grep "^utf8 body" msgtxt1 &&
575 grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 &&
576 ! grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1
579 test_expect_success '--compose adds MIME for utf8 subject' '
580 clean_fake_sendmail &&
581 GIT_EDITOR="\"$(pwd)/fake-editor\"" \
582 git send-email \
583 --compose --subject utf8-sübjëct \
584 --from="Example <nobody@example.com>" \
585 --to=nobody@example.com \
586 --smtp-server="$(pwd)/fake.sendmail" \
587 $patches &&
588 grep "^fake edit" msgtxt1 &&
589 grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
592 test_expect_success 'detects ambiguous reference/file conflict' '
593 echo master > master &&
594 git add master &&
595 git commit -m"add master" &&
596 test_must_fail git send-email --dry-run master 2>errors &&
597 grep disambiguate errors
600 test_expect_success 'feed two files' '
601 rm -fr outdir &&
602 git format-patch -2 -o outdir &&
603 git send-email \
604 --dry-run \
605 --from="Example <nobody@example.com>" \
606 --to=nobody@example.com \
607 outdir/000?-*.patch 2>errors >out &&
608 grep "^Subject: " out >subjects &&
609 test "z$(sed -n -e 1p subjects)" = "zSubject: [PATCH 1/2] Second." &&
610 test "z$(sed -n -e 2p subjects)" = "zSubject: [PATCH 2/2] add master"
613 test_expect_success 'in-reply-to but no threading' '
614 git send-email \
615 --dry-run \
616 --from="Example <nobody@example.com>" \
617 --to=nobody@example.com \
618 --in-reply-to="<in-reply-id@example.com>" \
619 --nothread \
620 $patches |
621 grep "In-Reply-To: <in-reply-id@example.com>"
624 test_expect_failure 'threading but no chain-reply-to' '
625 git send-email \
626 --dry-run \
627 --from="Example <nobody@example.com>" \
628 --to=nobody@example.com \
629 --thread \
630 --nochain-reply-to \
631 $patches $patches >stdout &&
632 grep "In-Reply-To: " stdout
635 test_done