chiark / gitweb /
http[s] tests: Add http test case
[dgit.git] / tests / lib
1 #
2
3 exec 2>&1
4 set -x
5 set -o pipefail
6
7 . tests/lib-core
8 . tests/lib-restricts
9
10 t-report-failure () {
11         set +x
12         rc=$1
13         cat <<END >&2
14 TEST FAILED
15 cwd: $PWD
16 funcs: ${FUNCNAME[*]}
17 lines: ${BASH_LINENO[*]}
18 files: ${BASH_SOURCE[*]}
19 END
20         t-save-artifacts
21
22         exit 16
23 }
24
25 trap '
26         rc=$?
27         set +e
28         [ "x$DGIT_TEST_TMP" = x ] || rm -rf $DGIT_TEST_TMP/must-clean
29         set -e
30         test $rc = 0 || t-report-failure
31 ' EXIT
32
33 t-filter-out-git-hyphen-dir
34
35 t-set-intree
36
37 : ${DGIT_TEST_DEBUG=-D}
38 export DGIT_TEST_DEBUG
39
40 : ${DGIT_TEST_DEBPUSH_DEBUG=x}
41 export DGIT_TEST_DEBPUSH_DEBUG
42
43 : ${DGIT_TEST_DISTRO+ ${distro=${DGIT_TEST_DISTRO}}}
44
45 export GIT_COMMITTER_DATE='1530000000 +0100'
46 export GIT_AUTHOR_DATE='1530000000 +0100'
47
48 export LC_CTYPE=C.UTF-8
49 unset CDPATH
50
51 root=`pwd`
52 troot=$root/tests
53 testname="${DGIT_TEST_TESTNAME-${0##*/}}"
54 export DGIT_TEST_TROOT=$troot
55 bpd=..
56
57 tmp=$ADTTMP
58 if [ x"$tmp" = x ]; then
59         export DGIT_TEST_BYHAND=1
60         mkdir -p tests/tmp
61         tmpbase=$troot/tmp
62         tmp=tests/tmp/$testname
63         rm -rf $tmp
64         mkdir $tmp
65 elif [ "x$DGIT_TEST_TMPBASE" != x ]; then
66         tmpbase="$DGIT_TEST_TMPBASE"
67 fi
68 cd $tmp
69
70 tmp=`pwd`
71
72 t-set-using-tmp
73
74 test -f $tmp/.save-env || \
75 env -0 >$tmp/.save-env
76
77 ln -sf $troot/ssh ssh
78
79 export DEBCHANGE_VENDOR=dpkg
80 unset VISUAL
81 unset GIT_EDITOR
82
83 mkdir -p $tmp/must-clean
84 # must-clean is usually removed after each test, on success or failure.
85 # But this must not be relied on for correctness, only for garbage
86 # collection etc.
87
88 mkdir -p $tmp/incoming
89 cat <<END >$tmp/dput.cf
90 [test-dummy]
91 method                  = local
92 incoming                = $tmp/incoming
93 run_dinstall            = 0
94 END
95
96 schroot=${DGIT_SCHROOT_CHROOT:-build}
97 # Pretty much any Debian sid snapshot schroot will do.
98
99 : ${t_archive_method:=aq}
100 : ${tagpfx:=archive/test-dummy}
101 : ${suitespecs:=sid:unstable}
102
103 t-git-next-date () {
104         GIT_COMMITTER_DATE="$(( ${GIT_COMMITTER_DATE%% *} + 1 )) ${GIT_COMMITTER_DATE#* }"
105         GIT_AUTHOR_DATE="$GIT_COMMITTER_DATE"
106 }
107
108 t-expect-fail () {
109         local mpat="$1"; shift
110
111         set +o pipefail
112         LC_MESSAGES=${expect_fail_lcmessages-C} \
113         LANGUAGE=${expect_fail_lcmessages-C} \
114         "$@" 2>&1 | tee $tmp/t.output
115         local ps="${PIPESTATUS[*]}"
116         set -o pipefail
117
118         case $ps in
119         "0 0")  fail "command unexpectedly succeeded (instead of: $mpat)" ;;
120         *" 0")  ;;
121         *)      fail "tee failed"  ;;
122         esac
123
124         t-grep-mpat "$mpat" $tmp/t.output
125 }
126
127 t-grep-mpat () {
128         local mpat="$1"
129         local file="$2"
130
131         local grepper=fgrep
132         case "$mpat" in
133         [A-Z]:*)
134                 case "$mpat" in
135                 E:*)    grepper=egrep   ;;
136                 F:*)    grepper=fgrep   ;;
137                 *)      fail "bad mpat prefix in $mpat";;
138                 esac
139                 mpat=${mpat#[A-Z]:}
140                 ;;
141         esac
142
143         $grepper -e "$mpat" "$file" ||
144                 fail "message not found"
145 }
146
147 t-expect-push-fail () {
148         local mpat="$1"; shift
149
150         local triedpush; triedpush=`git rev-parse HEAD`
151
152         t-reporefs pre-push
153         t-expect-fail "$mpat"  "$@"
154         t-reporefs post-push
155         diff $tmp/show-refs.{pre,post}-push
156
157         t-git-objects-not-present '' $triedpush
158
159         eval "$t_expect_push_fail_hook"
160 }
161
162 t-git-objects-not-present () {
163         # t-git-objects-not-present GITDIR|'' OBJID [...]
164         # specifying '' means the repo for package $p
165         local gitdir="${1-$dgitrepo}"
166         local obj
167         if ! [ -e "$gitdir" ]; then return; fi
168         for obj in "$@"; do
169                 GIT_DIR=$gitdir \
170                 t-expect-fail 'unable to find' \
171                 git cat-file -t $obj
172         done
173 }
174
175 t-reporefs () {
176         local whichoutput=$1; shift
177         local whichrepo=${1-$dgitrepo}
178         local outputfile="$tmp/show-refs.$whichoutput"
179         (set -e
180          exec >"$outputfile"
181          if test -d $whichrepo; then
182                 cd $whichrepo
183                 git show-ref |t-sort
184         fi)
185 }
186
187 t-untar () {
188         local tarfile=$1.tar
189         local edittree=$1.edit
190         if test -d "$edittree"; then
191                 cp -a "$edittree"/* .
192         else
193                 tar xf "$tarfile"
194         fi
195 }
196
197 t-worktree () {
198         rm -rf $p
199         t-untar $troot/worktrees/${p}_$1
200 }
201
202 t-select-package () {
203         p=$1
204         dgitrepo=$tmp/git/$p.git
205 }
206
207 t-git () {
208         t-select-package $1
209         v=$2
210         mkdir -p $tmp/git
211         local gs=$troot/git-srcs/${p}_$v.git
212         (set -e; cd $tmp/git; t-untar $gs)
213 }
214
215 t-git-none () {
216         mkdir -p $tmp/git
217         (set -e; cd $tmp/git; tar xf $troot/git-template.tar)
218 }
219
220 t-salsa-add-remote () {
221         local d=$tmp/salsa/$p
222         mkdir -p $d
223         (set -e; cd $d; git init --bare)
224         git remote add ${1-origin} $d
225 }
226
227 t-git-merge-base () {
228         git merge-base $1 $2 || test $? = 1
229 }
230
231 t-has-ancestor () {
232         # t-has-ancestor ANCESTOR
233         # (CHILD is implicit, HEAD)
234         local now;      now=`git rev-parse HEAD`
235         local ancestor; ancestor=`git rev-parse $1^{}`
236         local mbase;    mbase=`t-git-merge-base $ancestor $now`
237         if [ x$mbase != x$ancestor ]; then
238                 fail "not ff $ancestor..$now, $mbase != $ancestor"
239         fi
240 }
241
242 t-has-parent-or-is () {
243         # t-has-parent-or-is CHILD PARENT
244         local child=$1
245         local parent=$2
246         local parents
247         parents=$(git show --pretty=format:' %P %H ' "$child")
248         parent=$(git rev-parse "$parent~0")
249         case "$parents" in
250         *" $parent "*)  ;;
251         *)      fail "child $child lacks parent $parent" ;;
252         esac
253 }
254
255 t-prep-newpackage () {
256         t-select-package $1
257         v=$2
258         t-archive-none $p
259         t-git-none
260         t-worktree $v
261         cd $p
262         if ! git show-ref --verify --quiet refs/heads/master; then
263                 git branch -m dgit/sid master
264                 git remote rm dgit
265         fi
266         cd ..
267 }
268
269 t-archive-none () {
270         t-select-package $1
271         t-archive-none-$t_archive_method
272 }
273 t-archive-none-aq () {
274         mkdir -p $tmp/aq/dsc_in_suite $tmp/mirror/pool/main
275
276         : >$tmp/aq/suites
277         local jsondelim="["
278
279         local suitespec
280         for suitespec in $suitespecs; do
281                 local suite=${suitespec%%:*}
282                 local sname=${suitespec#*:}
283
284                 >$tmp/aq/package.$suite.$p
285                 t-aq-archive-updated $suite $p
286
287                 >$tmp/aq/package.new.$p
288                 t-aq-archive-updated new $p
289
290                 ln -sf $suite $tmp/aq/dsc_in_suite/$sname
291
292                 cat <<END >>$tmp/aq/suites
293 $jsondelim
294    {
295       "archive" : "ftp-master",
296       "codename" : "$suite",
297       "components" : [
298          "main",
299          "contrib",
300          "non-free"
301       ],
302       "name" : "$sname",
303       "dakname" : "$sname"
304 END
305
306                 jsondelim="   },"
307
308         done
309         cat <<END >>$tmp/aq/suites
310     }
311 ]
312 END
313 }
314
315 t-aq-archive-updated () {
316         local suite=$1
317         local p=$2
318         local suitedir=$tmp/aq/dsc_in_suite/$suite
319         mkdir -p $suitedir
320         perl <$tmp/aq/package.$suite.$p >$suitedir/$p -wne '
321                 use JSON;
322                 use strict;
323                 our @v;
324                 m{^(\S+) (\w+) ([^ \t/]+)/(\S+)} or die;
325                 push @v, {
326                         "version" => "$1",
327                         "sha256sum" => "$2",
328                         "component" => "$3",
329                         "filename" => "$4",
330                 };
331                 END {
332                         my $json = JSON->new->canonical();
333                         print $json->encode(\@v) or die $!;
334                 }
335         '
336 }
337
338 t-archive-process-incoming () {
339         local suite=$1
340         mv $tmp/incoming/${p}_* $tmp/mirror/pool/main/
341         t-archive-query "$suite"
342 }
343
344 t-archive-query () {
345         local suite=${1-sid}
346         local dscf=main/${p}_${v}.dsc
347         t-archive-query-$t_archive_method "$suite" "$p" "$v" "$dscf"
348 }
349 t-archive-query-aq () {
350         local suite=$1
351         local p=$2
352         local v=$3
353         local dscf=$4
354         local sha; sha=`sha256sum <$tmp/mirror/pool/$dscf`
355         echo "${v} ${sha%  -} $dscf" >>$tmp/aq/package.$suite.${p}
356         t-aq-archive-updated $suite $p
357 }
358
359 t-archive () {
360         t-archive-none $1
361         v=$2
362         local dscf=${p}_$2.dsc
363         rm -f $tmp/mirror/pool/main/${p}_*
364         ln -s $troot/pkg-srcs/${p}_${2%-*}* $tmp/mirror/pool/main/
365         t-archive-query $suite
366         rm -rf $tmp/extract
367         mkdir $tmp/extract
368         (set -e; cd $tmp/extract; dpkg-source -x ../mirror/pool/main/$dscf)
369 }
370
371 t-git-dir-time-passes () {
372         touch -d 'last year' $dgitrepo
373 }
374
375 t-git-dir-check () {
376         local gitdir=$dgitrepo
377         case "$1" in
378         enoent)
379                 if test -e "$gitdir"; then fail "$gitdir exists"; fi
380                 return
381                 ;;
382         public) wantstat='7[75]5' ;;
383         secret) wantstat='7[70]0' ;;
384         *)      fail "$1 t-git-dir-check ?" ;;
385         esac
386         gotstat=`stat -c%a $gitdir`
387         case "$gotstat" in
388         *$wantstat) return ;;
389         *)      fail "$gitdir has mode $gotstat, expected $wantstat" ;;
390         esac
391 }
392
393 t-expect-fsck-fail () {
394         echo >>$tmp/fsck.expected-errors "$1"
395 }
396
397 t-git-fsck () {
398         local fsckerrs=$(git rev-parse --git-dir)/dgit-test-fsck.errs
399
400         set +e
401         LC_MESSAGES=C git fsck --no-dangling --strict 2>&1 \
402                 | tee $fsckerrs
403         ps="${PIPESTATUS[*]}"
404         set -e
405
406         local pats
407         if [ -f $tmp/fsck.expected-errors ]; then
408                 pats=(-w -f $tmp/fsck.expected-errors)
409         else
410                 test "$ps" = "0 0"
411         fi
412         pats+=(-e 'notice: HEAD points to an unborn branch')
413         pats+=(-e 'notice: No default references')
414
415         set +e
416         grep -v "${pats[@]}" $fsckerrs
417         rc=$?
418         set -e
419         case $rc in
420         1) ;; # no unexpected errors
421         0) fail "unexpected messages from git-fsck" ;;
422         *) fail "grep of git-fsck failed" ;;
423         esac
424 }
425
426 t-check-only-bpd () {
427         if [ "$bpd" = .. ]; then return; fi
428         t-files-notexist \
429                 $tmp/*.{deb,changes,dsc,buildinfo} \
430                 $tmp/*.{tar,diff}.*
431 }
432
433 t-fscks () {
434         (
435         shopt -s nullglob
436         for d in $tmp/*/.git $tmp/git/*.git; do
437                 cd "${d%/.git}"
438                 t-git-fsck
439         done
440         )
441 }
442
443 t-ok () {
444         : '========================================'
445         t-check-only-bpd
446         t-fscks
447         t-save-artifacts
448         echo ok.
449 }
450
451 t-save-artifacts () {
452         artifacts="$AUTOPKGTEST_ARTIFACTS"
453         if [ x"$artifacts" = x ]; then return; fi
454         if [ x"tmp" = x ]; then return; fi
455         GZIP=-1v tar -C "$tmp" -zc -f "$artifacts/${0##*/}.tar.gz" \
456                 --exclude=\*.tar .
457 }
458
459 t-rm-dput-dropping () {
460         rm -f $tmp/${p}_${v}_*.upload
461 }
462
463 t-dgit () {
464         local dgit=${DGIT_TEST-dgit}
465         pwd >&2
466         : '
467 {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{'
468         $dgit --dgit=$dgit --dget:-u --dput:--config=$tmp/dput.cf \
469  ${dgit_config_debian_alias-"--config-lookup-explode=dgit-distro.debian.alias-canon"} \
470  ${DGIT_GITDEBREBASE_TEST+--git-debrebase=}${DGIT_GITDEBREBASE_TEST} \
471                 ${distro+${distro:+-d}}${distro--dtest-dummy} \
472                 $DGIT_TEST_OPTS $DGIT_TEST_DEBUG \
473                 -kBCD22CD83243B79D3DFAC33EA3DBCBC039B13D8A $t_dgit_xopts "$@"
474         : '}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
475 '
476 }
477
478 t-dgit-manpage () {
479         local section=$1
480         local page=$2
481         (export LC_ALL=C.UTF-8
482          if [ "$DGIT_TEST_INTREE" ]; then
483                 make -C $DGIT_TEST_INTREE $page.$section.view
484          else
485                 man $section $page
486          fi)
487 }
488
489 t-diff-nogit () {
490         diff --exclude=.git --exclude=.pc -ruN $*
491 }
492
493 t-files-notexist () {
494         local f
495         for f in "$@"; do
496                 if [ -e $f ]; then
497                         fail "$f exists!"
498                 fi
499         done
500 }
501
502 t-cloned-fetched-good () {
503         t-diff-nogit ../extract/$p-${v%-*} .
504         t-clean-on-branch dgit/sid
505         t-refs-same-start
506         t-refs-same \
507                 refs/heads/dgit/sid \
508                 refs/remotes/dgit/dgit/sid
509         t-refs-notexist refs/dgit/unstable refs/remotes/dgit/dgit/unstable
510 }
511
512 t-output () {
513         printf "%s${1:+\n}" "$1" >$tmp/t.want
514         shift
515         "$@" >$tmp/t.got
516         diff $tmp/t.want $tmp/t.got
517 }
518
519 t-clean-on-branch () {
520         t-output "## $1" git status -b --porcelain
521 }
522
523 t-setup-done () {
524         local savevars=$1
525         local savedirs=$2
526         local importeval=$3
527
528         local import=IMPORT.${DGIT_TEST_TESTNAME-${0##*/}}
529         exec 4>$tmp/$import.new
530
531         local vn
532         for vn in $savevars; do
533                 perl >&4 -"I$root" -MDebian::Dgit -e '
534                         printf "%s=%s\n", $ARGV[0], shellquote $ARGV[1]
535                 ' $vn "$(eval "printf '%s\n' \"\$$vn\"")"
536         done
537
538         perl >&4 -"I$root" -MDebian::Dgit -we '
539                 foreach my $vn (grep m/^DGIT_TEST_REAL_/, keys %ENV) {
540                         print STDERR "saving-exporting $vn\n";
541                         printf "export %s=%s\n", $vn, shellquote $ENV{$vn}
542                                 or die $!;
543                 }
544         '
545
546         (set -e; cd $tmp; tar cf $import.tar $savedirs)
547
548         printf >&4 "\n%s\n" "$importeval"
549
550         mv -f $tmp/$import.new $tmp/$import
551 }
552
553 t-setup-import () {
554         local setupname=$1
555
556         local setupsrc
557         local lock
558         if [ "x$tmpbase" = x ]; then
559                 # ADTTMP was set on entry to tests/lib, so we
560                 # are not sharing tmp area between tests
561                 setupsrc="$tmp"
562                 lock="$tmp/.dummy.lock"
563         else
564                 setupsrc="$tmpbase/$setupname"
565                 lock="$setupsrc.lock"
566         fi
567
568         local simport="$setupsrc/IMPORT.$setupname"
569
570         if ! [ -e "$simport" ]; then
571                 with-lock-ex -w "$lock" \
572                 xargs -0 -a $tmp/.save-env \
573                 bash -xec '
574                         cd "$1"; shift
575                         setupname="$1"; shift
576                         simport="$1"; shift
577                         if [ -e "$simport" ]; then exit 0; fi
578                         env - "$@" \
579                         "tests/setup/$setupname"
580                 ' x "$root" "$setupname" "$simport"
581         fi
582
583         if [ "x$setupsrc" != "x$tmp" ]; then
584                 (set -e; cd $tmp; tar xf "$simport.tar")
585         fi
586
587         mkdir -p $tmp/must-clean
588
589         . "$simport"
590 }
591
592 t-git-get-ref-exact () {
593         local ref=$1
594         # does not dereference, unlike t-git-get-ref
595         case "$ref" in
596         refs/*) ;;
597         *) fail "t-git-get-ref-exact bad $ref" ;;
598         esac
599         git for-each-ref --format='%(objectname)' "[r]efs/${ref#refs/}"
600 }
601
602 t-git-get-ref () {
603         local ref=$1
604         case "$ref" in
605         refs/*) ;;
606         *) fail "t-git-get-ref bad $ref" ;;
607         esac
608         (git show-ref -d $1 || test $? = 1) | perl -ne '
609                 $x = $1 if m#^(\w+) \Q'$1'\E(?:\^\{\})?$#;
610                 END { print "$x\n" if length $x; }
611         '
612 }
613
614 t-ref-same-exact () {
615         local name="$1"
616         local val; val=`t-git-get-ref-exact $name`
617         t-ref-same-val "$name" $val
618 }
619
620 t-ref-same () {
621         local name="$1"
622         local val; val=`t-git-get-ref $name`
623         t-ref-same-val "$name" $val
624 }
625
626 t-ref-head () {
627         local val; val=`git rev-parse HEAD`
628         t-ref-same-val HEAD $val
629 }
630
631 t-ref-same-val () {
632         local name="$1"
633         local val=$2
634         case "${t_ref_val-unset}" in
635         unset)          ;;
636         "$val")         ;;
637         *)              fail "ref varies: ($name)\
638  ${val:-nothing} != ${t_ref_val:-nothing} (${t_ref_names[*]})" ;;
639         esac
640         t_ref_val="$val"
641         t_ref_names+=("$name")
642 }
643
644 t-refs-same-start () {
645         unset t_ref_val
646         t_ref_names=()
647 }
648
649 t-refs-same () {
650         local g
651         for g in $*; do
652                 t-ref-same $g
653         done
654 }
655
656 t-refs-notexist () {
657         local val
658         for g in $*; do
659                 val=`t-git-get-ref $g`
660                 if [ "x$val" != x ]; then
661                         fail "ref $g unexpectedly exists ($val)"
662                 fi
663         done
664 }
665
666 t-v-tag () {
667         echo refs/tags/$tagpfx/${v//\~/_}
668 }
669
670 t-format-ref () {
671         git log -n1 --pretty=format:"$1" "$2"
672 }
673
674 t-sametree-parent () {
675         local ref=$1
676         local parent
677         local ctree; ctree=$(t-format-ref '%T' "$ref")
678         while :; do
679                 local psame=''
680                 for parent in $(t-format-ref '%P' "$ref"); do
681                         local ptree; ptree=$(t-format-ref '%T' "$parent")
682                         if [ "x$ptree" = "x$ctree" ]; then
683                                 psame+=" $parent"
684                         fi
685                 done
686                 case "$psame" in ""|" * *") break ;; esac
687                 ref="${psame# }"
688         done
689         echo "$ref"
690 }
691
692 t-check-pushed-master () {
693         local master; master=`t-git-get-ref refs/heads/master`
694         if [ x$master = x$t_ref_val ]; then return; fi
695         if [ x$master = x ]; then fail "failed to push master"; fi
696         # didn't update master, it must be not FF
697         local mbase; mbase=`t-git-merge-base $master $t_ref_val`
698         if [ x$mbase = x$master ]; then fail "failed to ff master"; fi
699 }
700
701 t-push-was-source-only () {
702         local f
703         t-files-notexist $tmp/incoming/${p}_${v}_*.deb \
704                          $tmp/incoming/${p}_${v}_*.udeb
705         # we permit _source.buildinfo files; see test_changes_source_only()
706         for f in $tmp/incoming/${p}_${v}_*.buildinfo; do
707             if [ -e $f ]; then
708                 case "$f" in
709                     *_source.buildinfo) ;;
710                     *) fail "non-source-only file $f exists!" ;;
711                 esac
712             fi
713         done
714 }
715
716 t-push-included () {
717     for f in $@; do
718         stat $tmp/incoming/$f
719     done
720 }
721
722 t-pushed-good () {
723         local branch=$1
724         local suite=${2:-sid}
725         t-refs-same \
726                 refs/heads/$branch
727         t-pushed-good-core
728 }
729         
730 t-pushed-good-core () {
731         t-ref-dsc-dgit
732         t-refs-same \
733                 `t-v-tag` \
734                 refs/remotes/dgit/dgit/$suite
735         t-refs-notexist \
736                 refs/heads/dgit/unstable \
737                 refs/remotes/dgit/dgit/unstable
738         (set -e; cd $dgitrepo
739          t-refs-same \
740                 refs/dgit/$suite \
741                 `t-v-tag`
742          ${t_check_pushed_master:- : NOT-DRS-NO-CHECK-PUSHED-MASTER}
743          t-refs-notexist \
744                 refs/dgit/unstable
745         )
746         git verify-tag `t-v-tag`
747 }
748
749 t-pushed-good-check-changes () {
750         changes_filename="$tmp/incoming/${p}_${v}_*.changes"
751         grep -E "^Distribution: $suite" $changes_filename
752         grep -E "^Version: $v" $changes_filename
753 }
754
755 t-splitbrain-pushed-good--unpack () {
756         cd $tmp
757         rm -rf t-unpack
758         mkdir t-unpack
759         cd t-unpack
760         ln -s $tmp/mirror/pool/main/*.orig*.tar* .
761         ln -s $tmp/incoming/*.orig*.tar* . ||:
762         ln -s $incoming_dsc .
763         ln -s ${incoming_dsc/.dsc/.debian.tar}* .
764         ln -s ${incoming_dsc/.dsc/.tar}* . ||:
765         dpkg-source "$@" -x *.dsc
766         cd */.
767         git init
768         git fetch ../../$p "refs/tags/*:refs/tags/*"
769 }
770
771 t-splitbrain-pushed-good--checkprep () {
772         git add -Af .
773         git rm --cached -r --ignore-unmatch .pc
774 }
775
776 t-splitbrain-pushed-good--checkdiff () {
777         local tag=$1
778         t-splitbrain-pushed-good--checkprep
779         t-output "" git diff --stat --cached $tag
780 }
781
782 t-splitbrain-pushed-good-start () {
783         dep14tag=refs/tags/test-dummy/${v//\~/_}
784         dgittag=$(t-v-tag)
785         t-output "" git status --porcelain
786         t-ref-head
787         t-refs-same $dep14tag
788         (set -e; cd $dgitrepo; t-refs-same $dep14tag)
789         git merge-base --is-ancestor $dep14tag $dgittag
790
791         t-refs-same-start
792         t-ref-same refs/heads/split.p
793         local split_b=$(t-git-get-ref refs/heads/split.b)
794         case "$split_b" in
795         "$t_ref_val") ;;
796         "$(git rev-parse refs/heads/split.p^0)") ;;
797         "$(git rev-parse refs/heads/split.p^1)") ;;
798         *) fail "bad b/p (b=$split_b)" ;;
799         esac
800         t-pushed-good-core
801
802         t-incoming-dsc
803
804         t-splitbrain-pushed-good--unpack
805         t-splitbrain-pushed-good--checkdiff $dgittag
806 }
807 t-splitbrain-pushed-good-end-made-dep14 () {
808         t-splitbrain-pushed-good--checkdiff $dep14tag
809         cd $tmp/$p
810 }
811
812 t-splitbrain-rm-1-patch () {
813         local patchname=$1
814         perl -i -pe '
815                 next unless $_ eq "'"$patchname"'\n";
816                 die if $counter++;
817                 chomp;
818                 rename "debian/patches/$_", "../t-'"$patchname"'" or die $!;
819                 $_ = "";
820         ' debian/patches/series
821 }
822
823 t-splitbrain-rm-gitignore-patch () {
824         t-splitbrain-rm-1-patch auto-gitignore
825 }
826
827 t-gbp-pushed-good () {
828         local suite=${1:-sid}
829         t-splitbrain-pushed-good-start
830
831         # Right, now we want to check that the maintainer tree and
832         # the dgit tree differ in exactly the ways we expect.  We
833         # achieve this by trying to reconstruct the maintainer tree
834         # from the dgit tree.
835
836         # So, unpack it withut the patches applied
837         t-splitbrain-pushed-good--unpack --skip-patches
838
839         # dgit might have added a .gitignore patch, which we need to
840         # drop and remove
841         t-splitbrain-rm-gitignore-patch
842
843         # Now the result should differ only in non-debian/ .gitignores
844         t-splitbrain-pushed-good--checkprep
845         git diff --cached --name-only $dep14tag >../changed
846         perl -ne '
847                 next if !m#^debian/# && m#(^|/)\.gitignore#;
848                 die "$_ mismatch";
849         ' <../changed
850
851         # If we actually apply the gitignore patch by hand, it
852         # should be perfect:
853         if [ -f ../t-auto-gitignore ]; then
854                 patch --backup-if-mismatch -p1 -u <../t-auto-gitignore
855         fi
856
857         t-splitbrain-pushed-good-end-made-dep14
858 }
859
860 t-unapplied-pushed-good () {
861         local suite=${1:-sid}
862         t-splitbrain-pushed-good-start
863         t-splitbrain-pushed-good--unpack --skip-patches
864         t-splitbrain-pushed-good-end-made-dep14
865 }
866
867 t-dpm-pushed-good () {
868         local suite=${1:-sid}
869         t-splitbrain-pushed-good-start
870         t-splitbrain-pushed-good--unpack
871         t-splitbrain-rm-gitignore-patch
872         t-splitbrain-pushed-good-end-made-dep14
873 }
874
875 t-split-unchanged-pushed-good () {
876         local suite=${1:-sid}
877         t-splitbrain-pushed-good-start
878         t-splitbrain-pushed-good--unpack
879         t-splitbrain-pushed-good-end-made-dep14
880 }
881
882 t-commit-build-push-expect-log () {
883         local msg=$1
884         local mpat=$2
885         t-commit "$msg"
886         t-dgit build
887         LC_MESSAGES=C \
888         t-dgit push --new 2>&1 |tee $tmp/push.log
889         t-grep-mpat "$mpat" $tmp/push.log
890 }
891
892 t-822-field () {
893         local file=$1
894         local field=$2
895         perl -e '
896                 use Dpkg::Control::Hash;
897                 my $h = new Dpkg::Control::Hash allow_pgp=>1;
898                 $h->parse(\*STDIN,"'"$file"'");
899                 my $val = $h->{"'$field'"},"\n";
900                 die "'"$file $field"'" unless defined $val;
901                 print $val,"\n";
902         ' <$file
903 }
904
905 t-defdistro () {
906         export DGIT_TEST_DISTRO=''
907         distro=''
908         t-git-config dgit-suite.unstable.distro test-dummy
909 }
910
911 t-stunt-envvar () {
912         local var=$1
913         local tstunt=$2
914         eval '
915                 case "$'$var'" in
916                 "$tstunt:"*)    ;;
917                 *":$tstunt:"*)  ;;
918                 "")             '$var'="$tstunt" ;;
919                 *)              '$var'="$tstunt:$'$var'" ;;
920                 esac
921                 export '$var'
922         '
923 }
924
925 t-tstunt--save-real () {
926         local f="$1"
927         case "$f" in
928         */*) return ;;
929         esac
930
931         local rc
932         local real
933         set +e
934         real=$(
935                 p=":$PATH:"
936                 p="${p/:"$tmp/tstunt":/:}"
937                 p="${p%:}"
938                 p="${p#:}"
939                 PATH="$p"
940                 type -p "$f"
941         )
942         rc=$?
943         set -e
944
945         case $rc in
946         1)      return ;;
947         0)      ;;
948         *)      fail "did not find $f on PATH $PATH" ;;
949         esac
950
951         local varname=${f//[^_0-9a-zA-Z]/_}
952         varname=DGIT_TEST_REAL_${varname^^}
953
954         eval "
955                 : \${$varname:=\$real}
956                 export $varname
957         "
958 }
959
960 t-tstunt () {
961         local tstunt=$tmp/tstunt
962         t-stunt-envvar PATH $tstunt
963         t-stunt-envvar PERLLIB $tstunt
964         local f
965         for f in "$@"; do
966                 t-tstunt--save-real $f
967                 f="./$f"
968                 local d="$tstunt/${f%/*}"
969                 mkdir -p $d
970                 ln -sf "$troot/tstunt/$f" "$d"/.
971         done
972 }
973
974 t-tstunt-parsechangelog () {
975         t-tstunt dpkg-parsechangelog Dpkg/Changelog/Parse.pm
976 }
977
978 t-tstunt-lintian () {
979         t-tstunt lintian
980 }
981
982 t-tstunt-debuild () {
983         t-tstunt debuild
984 }
985
986 t-incoming-dsc () {
987         local dsc=${p}_${v}.dsc
988         incoming_dsc=$tmp/incoming/$dsc
989 }
990
991 t-ref-dsc-dgit () {
992         t-incoming-dsc
993         local val; val=`t-822-field $incoming_dsc Dgit`
994         val=$( perl -e '
995                 $_=shift @ARGV;
996                 die "Dgit $_ ?" unless m/^\w+\b/;
997                 print $&,"\n" or die $!;
998         ' "$val")
999         t-ref-same-val $incoming_dsc "$val"
1000 }
1001
1002 t-apply-diff () {
1003         local v1=$1
1004         local v2=$2
1005         (cd $troot/pkg-srcs;
1006          debdiff ${p}_${v1}.dsc ${p}_${v2}.dsc || test $? = 1) \
1007          | patch -p1 -u
1008 }
1009
1010 t-gbp-unapplied-pq2qc () {
1011         # does `gbp pq export'
1012         # commits the resulting debian/patches on  qc/BRANCH
1013         # leaves us on qc/BRANCH (eg "qc/quilt-tip"))
1014         # qc/BRANCH is not fast-forwarding
1015
1016         gbp pq export
1017
1018         branch=`git symbolic-ref HEAD`
1019         branch=${branch#refs/heads/}
1020
1021         case "$branch" in
1022         */*) fail "unexpected branch $branch" ;;
1023         esac
1024
1025         git branch -f qc/$branch
1026         git checkout qc/$branch
1027         git add debian/patches
1028         git commit -m 'Commit patch queue'
1029 }
1030
1031 t-git-pseudo-merge () {
1032         # like   git merge -s ours
1033         if [ ! "$git_pseuomerge_opts" ]; then
1034                 if git merge --help \
1035                  | grep -q allow-unrelated-histories; then
1036                         git_pseuomerge_opts='--allow-unrelated-histories'
1037                 fi
1038                 git_pseuomerge_opts+=' -s ours'
1039         fi
1040         git merge $git_pseuomerge_opts "$@"
1041 }
1042
1043 t-gbp-example-prep-no-ff () {
1044         t-archive example 1.0-1
1045         t-git-none
1046         t-worktree 1.0
1047
1048         cd example
1049
1050         t-dgit fetch
1051
1052         git checkout -b patch-queue/quilt-tip-2 patch-queue/quilt-tip
1053         gbp pq rebase
1054
1055         echo '/* some comment */' >>src.c
1056         git add src.c
1057         git commit -m 'Add a comment to an upstream file'
1058
1059         t-gbp-unapplied-pq2qc
1060
1061         t-commit 'some updates' 1.0-2
1062 }
1063
1064 t-gbp-example-prep () {
1065         t-gbp-example-prep-no-ff
1066
1067         t-git-pseudo-merge \
1068                 -m 'Pseudo-merge to make descendant of archive' \
1069                 remotes/dgit/dgit/sid
1070 }
1071
1072 t-make-badcommit () {
1073         badcommit=$(
1074                 git cat-file commit HEAD | \
1075                 perl -pe 's/^committer /commiter /' | \
1076                 git hash-object -w -t commit --stdin
1077         )
1078         t-expect-fsck-fail $badcommit
1079 }
1080
1081 t-make-orig () {
1082         # leaves ust set to filename of orig tarball
1083         local p=$1
1084         local v=$2
1085         local tag=${3-v$2}
1086         ust=${p}_${v}.orig.tar.gz
1087         GZIP=-1 git archive -o $bpd/$ust --prefix=${p}-${v}/ $tag
1088 }
1089
1090 t-merge-conflicted-stripping-conflict-markers () {
1091         local otherbranch=$1
1092         local file=$2
1093
1094         t-expect-fail F:"Merge conflict in $file" \
1095         git merge $otherbranch
1096
1097         perl -i~ -ne 'print unless m{^(?:\<\<\<|\>\>\>|===)}' "$file"
1098         git add "$file"
1099         git commit --no-edit
1100 }
1101
1102 t-commit () {
1103         local msg=$1
1104         v=${2:-${majorv:-1}.$revision}
1105         $troot/tstunt/debchange \
1106                 --force-distribution -v$v --distribution ${3:-unstable} "$1"
1107         git add debian/changelog
1108         debcommit
1109         revision=$(( ${revision-0} + 1 ))
1110 }
1111
1112 t-dch-r-rune () {
1113         local cmd="$1"; shift
1114         local suite=${1-unstable}
1115         $cmd -r -D "$suite" ''
1116 }
1117
1118 t-dch-commit-r () {
1119         t-dch-r-rune t-dch-commit "$@"
1120 }
1121
1122 t-dch-commit () {
1123         $troot/tstunt/debchange "$@"
1124         git commit -m "dch $*" debian/changelog
1125 }
1126
1127 t-git-config () {
1128         git config --global "$@"
1129 }
1130
1131 t-drs () {
1132  t-git-config dgit-distro.test-dummy.git-url "ext::$troot/drs-git-ext %S "
1133  t-git-config dgit-distro.test-dummy.git-check true
1134  t-git-config dgit-distro.test-dummy.git-create true
1135         cp $troot/gnupg/{dd.gpg,dm.gpg,dm.txt} $tmp/.
1136         cp $troot/suites $tmp/.
1137         cp $troot/suites $tmp/suites-master
1138
1139         export t_check_pushed_master=t-check-pushed-master
1140
1141         drs_dispatch=$tmp/distro=test-dummy
1142         mkdir $drs_dispatch
1143
1144         if [ "x$DGIT_TEST_INTREE" != x ]; then
1145                 ln -sf "$DGIT_TEST_INTREE" $drs_dispatch/dgit-live
1146         fi
1147
1148         ln -sf $tmp/git $drs_dispatch/repos
1149         ln -sf $tmp/suites $tmp/suites-master $tmp/dm.txt $drs_dispatch/
1150         mkdir -p $drs_dispatch/keyrings
1151         ln -sf $tmp/dd.gpg $drs_dispatch/keyrings/debian-keyring.gpg
1152         ln -sf $tmp/dm.gpg $drs_dispatch/keyrings/debian-maintainers.gpg
1153         ln -sf /bin/true $drs_dispatch/policy-hook
1154 }
1155
1156 t-dsd () {
1157         t-drs
1158  t-git-config dgit-distro.test-dummy.ssh "$troot/dsd-ssh"
1159  t-git-config dgit-distro.test-dummy.git-check ssh-cmd
1160  t-git-config dgit-distro.test-dummy.git-create true
1161  t-git-config dgit-distro.test-dummy.git-url \
1162                 "ext::$troot/dsd-ssh X %S /dgit/test-dummy/repos"
1163
1164  t-git-config dgit-distro.test-dummy.diverts.drs /drs
1165  t-git-config dgit-distro.test-dummy/drs.ssh "$troot/ssh"
1166  t-git-config dgit-distro.test-dummy/drs.git-url $tmp/git
1167  t-git-config dgit-distro.test-dummy/drs.git-check ssh-cmd
1168  t-git-config dgit-distro.test-dummy/drs.git-create ssh-cmd
1169
1170         echo 'no-such-package* drs' >$drs_dispatch/diverts
1171 }
1172
1173 t-policy-admin () {
1174         : '(((((((((((((((((((((((((((((((((((((((('
1175         ${DGIT_INFRA_PFX}dgit-repos-admin-debian --repos $tmp/git "$@"
1176         : '))))))))))))))))))))))))))))))))))))))))'
1177 }
1178
1179 t-policy-nonexist () {
1180         ln -sf no-such-file-or-directory $drs_dispatch/policy-hook
1181 }
1182
1183 t-make-hook-link () {
1184         local hook=$1 # in infra/
1185         local linkpath=$2
1186         hook=${DGIT_INFRA_PFX}$hook
1187         case $hook in
1188         */*)    ;;
1189         *)      hook=`type -P $hook` ;;
1190         esac
1191         ln -sf "$hook" $linkpath
1192 }
1193
1194 t-policy () {
1195         local policyhook=$1
1196         t-make-hook-link $policyhook $drs_dispatch/policy-hook
1197 }
1198
1199 t-debpolicy () {
1200         t-dsd
1201         t-policy dgit-repos-policy-debian
1202
1203         mkdir -p $tmp/git
1204         t-policy-admin create-db
1205 }
1206
1207 t-policy-periodic () {
1208         : '(((((((((((((((((((((((((((((((((((((((('
1209         ${DGIT_REPOS_SERVER_TEST-dgit-repos-server} \
1210                 test-dummy $drs_dispatch '' --cron
1211         : '))))))))))))))))))))))))))))))))))))))))'
1212 }
1213
1214 t-tagupl-settings () {
1215         export DGIT_DRS_EMAIL_NOREPLY=noreply@example.org
1216         export DGIT_DRS_SENDMAIL=$troot/tstunt/sendmail
1217         export DGIT_DRS_DGIT=$troot/tstunt/dgit
1218         t-chain-test-somehow
1219
1220         mkdir ../pretend-salsa
1221         (set -e; cd ../pretend-salsa; git init --bare)
1222         git remote add salsa $tmp/pretend-salsa
1223         # git branch --set-upstream-to complains, so
1224         git config branch.master.remote salsa
1225         git config branch.master.merge refs/heads/master
1226 }
1227
1228 t-tagupl-run-drs () {
1229         local source=$1
1230         cd ..
1231         cd tagupl
1232
1233         DGIT_DRS_ANY_URL=1 \
1234         DGIT_DRS_MODE="tag2upload $source $tagname" \
1235          $troot/drs-git-ext 
1236
1237         cd $tmp/$p
1238 }
1239
1240 t-tagupl-test () {
1241         ${DGIT_DEBPUSH_TEST-git debpush} \
1242                 --distro=test-dummy -u Senatus "$@"
1243
1244         mkdir ../tagupl
1245         t-tagupl-run-drs $tmp/pretend-salsa
1246
1247         cd ../pretend-salsa
1248         t-refs-same refs/heads/master
1249         cd ../$p
1250
1251         t-dgit fetch
1252 }
1253
1254 t-buildproductsdir-config () {
1255         bpd=$tmp/bpd
1256         t-git-config dgit.default.build-products-dir $bpd
1257         mkdir -p $bpd
1258         cat <<END >>$tmp/.gbp.conf
1259 [buildpackage]
1260 export-dir = $bpd
1261 END
1262 }
1263
1264 t-restrict () {
1265         local restriction=$1
1266         (cd $root; t-restriction-$restriction >&2)
1267 }
1268
1269 t-dependencies () {
1270         : "Hopefully installed: $*"
1271 }
1272
1273 t-chain-test-somehow () {
1274         export DGIT_TEST_TESTNAME="$testname"
1275         export DGIT_TEST_TMPBASE="$tmpbase"
1276         export ADTTMP=$tmp
1277 }
1278
1279 t-chain-test () {
1280         t-chain-test-somehow
1281         local ct=$1
1282         local d=${0%/*}
1283         cd $root
1284         exec "$d/$ct"
1285 }       
1286
1287 t-alt-test () {
1288         local t=${0##*/}
1289         t-${t%%-*}
1290         t-chain-test "${t#*-}"
1291 }
1292
1293 t-git-config dgit.default.old-dsc-distro test-dummy
1294
1295 for import in ${autoimport-gnupg}; do
1296         case "$0" in
1297         */$import) ;;
1298         *)
1299                 t-setup-import $import
1300                 ;;
1301         esac
1302 done