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