chiark / gitweb /
Test suite: orig-include-exclude: Test orig tarball hash mismatch
[dgit.git] / tests / lib
index 1158f0a1448b0248a564e04e19d16e8f2a1db38f..ee4bfd07bfdc145e31b60a9dc1af312c2f3e01fa 100644 (file)
--- a/tests/lib
+++ b/tests/lib
@@ -2,14 +2,35 @@
 
 exec 2>&1
 set -x
+set -o pipefail
 
 . tests/lib-core
+. tests/lib-restricts
+
+t-report-failure () {
+       set +x
+       rc=$1
+       cat <<END >&2
+TEST FAILED
+funcs: ${FUNCNAME[*]}
+lines: ${BASH_LINENO[*]}
+files: ${BASH_SOURCE[*]}
+END
+       exit 16
+}
+
+trap 'test $? = 0 || t-report-failure' EXIT
+
+t-filter-out-git-hyphen-dir
 
 t-set-intree
 
-: ${DGIT_TEST_DEBUG:=-D}
+: ${DGIT_TEST_DEBUG=-D}
 export DGIT_TEST_DEBUG
 
+export GIT_COMMITTER_DATE='1440253867 +0100'
+export GIT_AUTHOR_DATE='1440253867 +0100'
+
 root=`pwd`
 troot=$root/tests
 testname="${DGIT_TEST_TESTNAME-${0##*/}}"
@@ -17,21 +38,24 @@ testname="${DGIT_TEST_TESTNAME-${0##*/}}"
 tmp=$ADTTMP
 if [ x"$tmp" = x ]; then
        mkdir -p tests/tmp
+       tmpbase=$troot/tmp
        tmp=tests/tmp/$testname
        rm -rf $tmp
        mkdir $tmp
+elif [ "x$DGIT_TEST_TMPBASE" != x ]; then
+       tmpbase="$DGIT_TEST_TMPBASE"
 fi
 cd $tmp
 
 tmp=`pwd`
-export HOME=$tmp
-export DGIT_TEST_DUMMY_DIR=$tmp
+
+t-set-using-tmp
+
+env -0 >$tmp/.save-env
+
 ln -f $troot/ssh ssh
 
-mkdir -p $tmp/gnupg
-cp $troot/gnupg/* $tmp/gnupg
-chmod go-rw $tmp/gnupg/*
-export GNUPGHOME=$tmp/gnupg
+export DEBCHANGE_VENDOR=dpkg
 
 mkdir -p $tmp/incoming
 cat <<END >$tmp/dput.cf
@@ -41,18 +65,96 @@ incoming            = $tmp/incoming
 run_dinstall           = 0
 END
 
+: ${tagpfx:=archive/test-dummy}
+: ${suitespecs:=sid:unstable}
+
+t-git-next-date () {
+       GIT_COMMITTER_DATE="$(( ${GIT_COMMITTER_DATE%% *} + 1 )) ${GIT_COMMITTER_DATE#* }"
+       GIT_AUTHOR_DATE="$GIT_COMMITTER_DATE"
+}
+
 t-expect-fail () {
        local mpat="$1"; shift
+
+       set +o pipefail
        LC_MESSAGES=C "$@" 2>&1 | tee $tmp/t.output
-       test ${PIPESTATUS[0]} != 0
-       egrep "$mpat" $tmp/t.output ||false
+       local ps="${PIPESTATUS[*]}"
+       set -o pipefail
+
+       case $ps in
+       "0 0")  fail "command unexpectedly succeeded (instead of: $mpat)" ;;
+       *" 0")  ;;
+       *)      fail "tee failed"  ;;
+       esac
+
+       t-grep-mpat "$mpat" $tmp/t.output
+}
+
+t-grep-mpat () {
+       local mpat="$1"
+       local file="$2"
+
+       local grepper=fgrep
+       case "$mpat" in
+       [A-Z]:*)
+               case "$mpat" in
+               E:*)    grepper=egrep   ;;
+               F:*)    grepper=fgrep   ;;
+               *)      fail "bad mpat prefix in $mpat";;
+               esac
+               mpat=${mpat#[A-Z]:}
+               ;;
+       esac
+
+       $grepper -e "$mpat" "$file" ||
+               fail "message not found"
+}
+
+t-expect-push-fail () {
+       local mpat="$1"; shift
+
+       local triedpush=`git rev-parse HEAD`
+
+       t-reporefs pre-push
+       t-expect-fail "$mpat"  "$@"
+       t-reporefs post-push
+       diff $tmp/show-refs.{pre,post}-push
+
+       t-git-objects-not-present '' $triedpush
+
+       eval "$t_expect_push_fail_hook"
+}
+
+t-git-objects-not-present () {
+       # t-git-objects-not-present GITDIR|'' OBJID [...]
+       # specifying '' means the repo for package $p
+       local gitdir="${1-$dgitrepo}"
+       local obj
+       if ! [ -e "$gitdir" ]; then return; fi
+       for obj in "$@"; do
+               GIT_DIR=$gitdir \
+               t-expect-fail 'unable to find' \
+               git cat-file -t $obj
+       done
+}
+
+t-reporefs () {
+       local whichoutput=$1; shift
+       local whichrepo=${1-$dgitrepo}
+       local outputfile="$tmp/show-refs.$whichoutput"
+       (set -e
+        exec >"$outputfile"
+        if test -d $whichrepo; then
+               cd $whichrepo
+               git show-ref |sort
+       fi)
 }
 
 t-untar () {
        local tarfile=$1.tar
        local edittree=$1.edit
        if test -d "$edittree"; then
-               cp -al "$edittree"/* .
+               cp -a "$edittree"/* .
        else
                tar xf "$tarfile"
        fi
@@ -63,8 +165,13 @@ t-worktree () {
        t-untar $troot/worktrees/${p}_$1
 }
 
-t-git () {
+t-select-package () {
        p=$1
+       dgitrepo=$tmp/git/$p.git
+}
+
+t-git () {
+       t-select-package $1
        v=$2
        mkdir -p $tmp/git
        local gs=$troot/git-srcs/${p}_$v.git
@@ -76,53 +183,72 @@ t-git-none () {
        (set -e; cd $tmp/git; tar xf $troot/git-template.tar)
 }
 
+t-git-merge-base () {
+       git merge-base $1 $2 || test $? = 1
+}
+
 t-has-ancestor () {
        local now=`git rev-parse HEAD`
        local ancestor=`git rev-parse $1^{}`
-       local mbase=`git merge-base $ancestor $now`
+       local mbase=`t-git-merge-base $ancestor $now`
        if [ x$mbase != x$ancestor ]; then
                fail "not ff $ancestor..$now, $mbase != $ancestor"
        fi
 }
 
 t-prep-newpackage () {
-       p=$1
+       t-select-package $1
        v=$2
        t-archive-none $p
        t-git-none
        t-worktree $v
        cd $p
-       git branch -m dgit/sid master
-       git remote rm dgit
+       if ! git show-ref --verify --quiet refs/heads/master; then
+               git branch -m dgit/sid master
+               git remote rm dgit
+       fi
        cd ..
 }
 
 t-archive-none () {
-       p=$1
-       mkdir -p $tmp/aq $tmp/mirror/pool/main
+       t-select-package $1
+       mkdir -p $tmp/aq/dsc_in_suite $tmp/mirror/pool/main
 
-       local suite=sid
+       : >$tmp/aq/suites
+       local jsondelim="["
 
-       >$tmp/aq/package.$suite.$p
-       t-archive-updated $suite $p
+       local suitespec
+       for suitespec in $suitespecs; do
+               local suite=${suitespec%%:*}
+               local sname=${suitespec#*:}
 
-       >$tmp/aq/package.new.$p
-       t-archive-updated new $p
+               >$tmp/aq/package.$suite.$p
+               t-archive-updated $suite $p
 
-       ln -s sid $tmp/aq/dsc_in_suite/unstable
-       cat <<'END' >$tmp/aq/suites
-[
+               >$tmp/aq/package.new.$p
+               t-archive-updated new $p
+
+               ln -sf $suite $tmp/aq/dsc_in_suite/$sname
+
+               cat <<END >>$tmp/aq/suites
+$jsondelim
    {
       "archive" : "ftp-master",
-      "codename" : "sid",
+      "codename" : "$suite",
       "components" : [
          "main",
          "contrib",
          "non-free"
       ],
-      "name" : "unstable",
-      "dakname" : "unstable"
-   }
+      "name" : "$sname",
+      "dakname" : "$sname"
+END
+
+               jsondelim="   },"
+
+       done
+       cat <<END >>$tmp/aq/suites
+    }
 ]
 END
 }
@@ -144,21 +270,24 @@ t-archive-updated () {
                        "filename" => "$4",
                };
                END {
-                       print to_json \@v or die $!;
+                       my $json = JSON->new->canonical();
+                       print $json->encode(\@v) or die $!;
                }
        '
 }
 
 t-archive-process-incoming () {
-       mv incoming/${p}_${v}[._]* mirror/pool/main/
-       t-archive-query
+       local suite=$1
+       mv $tmp/incoming/${p}_* $tmp/mirror/pool/main/
+       t-archive-query "$suite"
 }
 
 t-archive-query () {
+       local suite=${1-sid}
        local dscf=main/${p}_${v}.dsc
-       local sha=`sha256sum <mirror/pool/$dscf`
-       echo "${v} ${sha%  -} $dscf" >>$tmp/aq/package.sid.${p}
-       t-archive-updated sid $p
+       local sha=`sha256sum <$tmp/mirror/pool/$dscf`
+       echo "${v} ${sha%  -} $dscf" >>$tmp/aq/package.$suite.${p}
+       t-archive-updated $suite $p
 }
 
 t-archive () {
@@ -173,13 +302,40 @@ t-archive () {
        (set -e; cd $tmp/extract; dpkg-source -x ../mirror/pool/main/$dscf)
 }
 
+t-git-dir-time-passes () {
+       touch -d 'last year' $dgitrepo
+}
+
+t-git-dir-check () {
+       local gitdir=$dgitrepo
+       case "$1" in
+       enoent)
+               if test -e "$gitdir"; then fail "$gitdir exists"; fi
+               return
+               ;;
+       public) wantstat='7[75]5' ;;
+       secret) wantstat='7[70]0' ;;
+       *)      fail "$1 t-git-dir-check ?" ;;
+       esac
+       gotstat=`stat -c%a $gitdir`
+       case "$gotstat" in
+       *$wantstat) return ;;
+       *)      fail "$gitdir has mode $gotstat, expected $wantstat" ;;
+       esac
+}
+
+t-rm-dput-dropping () {
+       rm -f $tmp/${p}_${v}_*.upload
+}
+
 t-dgit () {
        local dgit=${DGIT_TEST-dgit}
+       pwd
        : '
 {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{'
        $dgit --dgit=$dgit --dget:-u --dput:--config=$tmp/dput.cf \
                -dtest-dummy $DGIT_TEST_OPTS $DGIT_TEST_DEBUG \
-               -k39B13D8A "$@"
+               -k39B13D8A $t_dgit_xopts "$@"
        : '}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
 '
 }
@@ -188,6 +344,15 @@ t-diff-nogit () {
        diff --exclude=.git --exclude=.pc -ruN $*
 }
 
+t-files-notexist () {
+       local f
+       for f in "$@"; do
+               if [ -e $f ]; then
+                       fail "$f exists!"
+               fi
+       done
+}
+
 t-cloned-fetched-good () {
        t-diff-nogit ../extract/$p-${v%-*} .
        t-clean-on-branch dgit/sid
@@ -195,11 +360,11 @@ t-cloned-fetched-good () {
        t-refs-same \
                refs/heads/dgit/sid \
                refs/remotes/dgit/dgit/sid
-       t-refs-notexist dgit/unstable remotes/dgit/dgit/unstable
+       t-refs-notexist refs/dgit/unstable refs/remotes/dgit/dgit/unstable
 }
 
 t-output () {
-       printf "%s\n" "$1" >$tmp/t.want
+       printf "%s${1:+\n}" "$1" >$tmp/t.want
        shift
        "$@" >$tmp/t.got
        diff $tmp/t.want $tmp/t.got
@@ -209,14 +374,93 @@ t-clean-on-branch () {
        t-output "## $1" git status -b --porcelain
 }
 
+t-setup-done () {
+       local savevars=$1
+       local savedirs=$2
+       local importeval=$3
+
+       local import=IMPORT.${0##*/}
+       exec 4>$tmp/$import.new
+
+       local vn
+       for vn in $savevars; do
+               perl >&4 -I. -MDebian::Dgit -e '
+                       printf "%s=%s\n", $ARGV[0], shellquote $ARGV[1]
+               ' $vn "$(eval "printf '%s\n' \"\$$vn\"")"
+       done
+
+       (set -e; cd $tmp; tar cf $import.tar $savedirs)
+
+       printf >&4 "\n%s\n" "$importeval"
+
+       mv -f $tmp/$import.new $tmp/$import
+}
+
+t-setup-import () {
+       local setupname=$1
+
+       local setupsrc
+       local lock
+       if [ "x$tmpbase" = x ]; then
+               # ADTTMP was set on entry to tests/lib, so we
+               # are not sharing tmp area between tests
+               setupsrc="$tmp"
+               lock="$tmp/.dummy.lock"
+       else
+               setupsrc="$tmpbase/$setupname"
+               lock="$setupsrc.lock"
+       fi
+
+       local simport="$setupsrc/IMPORT.$setupname"
+
+       if ! [ -e "$simport" ]; then
+               with-lock-ex -w "$lock" \
+               xargs -0 -a $tmp/.save-env \
+               bash -xec '
+                       cd "$1"; shift
+                       setupname="$1"; shift
+                       simport="$1"; shift
+                       if [ -e "$simport" ]; then exit 0; fi
+                       env - "$@" \
+                       "tests/setup/$setupname"
+               ' x "$root" "$setupname" "$simport"
+       fi
+
+       if [ "x$setupsrc" != "x$tmp" ]; then
+               (set -e; cd $tmp; tar xf "$simport.tar")
+       fi
+
+       . "$simport"
+}
+
+t-git-get-ref-exact () {
+       local ref=$1
+       # does not dereference, unlike t-git-get-ref
+       case "$ref" in
+       refs/*) ;;
+       *) fail "t-git-get-ref-exact bad $ref" ;;
+       esac
+       git for-each-ref --format='%(objectname)' "[r]efs/${ref#refs/}"
+}
+
 t-git-get-ref () {
        local ref=$1
-       git show-ref -d $1 | perl -ne '
+       case "$ref" in
+       refs/*) ;;
+       *) fail "t-git-get-ref bad $ref" ;;
+       esac
+       (git show-ref -d $1 || test $? = 1) | perl -ne '
                $x = $1 if m#^(\w+) \Q'$1'\E(?:\^\{\})?$#;
                END { print "$x\n" if length $x; }
        '
 }
 
+t-ref-same-exact () {
+       local name="$1"
+       local val=`t-git-get-ref-exact $name`
+       t-ref-same-val "$name" $val
+}
+
 t-ref-same () {
        local name="$1"
        local val=`t-git-get-ref $name`
@@ -234,7 +478,8 @@ t-ref-same-val () {
        case "$t_ref_val" in
        '')             ;;
        "$val")         ;;
-       *)              fail "ref varies: $name: $val != $t_ref_val" ;;
+       *)              fail "ref varies: $name:\
+ ${val:-nothing} != ${t_ref_val:-nothing}" ;;
        esac
        t_ref_val="$val"
 }
@@ -253,7 +498,7 @@ t-refs-same () {
 t-refs-notexist () {
        local val
        for g in $*; do
-               val=`t-git-get-ref $g >$tmp/t.refx`
+               val=`t-git-get-ref $g`
                if [ "x$val" != x ]; then
                        fail "ref $g unexpectedly exists ($val)"
                fi
@@ -261,29 +506,180 @@ t-refs-notexist () {
 }
 
 t-v-tag () {
-       echo refs/tags/debian/${v//\~/_}
+       echo refs/tags/$tagpfx/${v//\~/_}
+}
+
+t-format-ref () {
+       git log -n1 --pretty=format:"$1" "$2"
+}
+
+t-sametree-parent () {
+       local ref=$1
+       local parent
+       local ctree=$(t-format-ref '%T' "$ref")
+       while :; do
+               local psame=''
+               for parent in $(t-format-ref '%P' "$ref"); do
+                       local ptree=$(t-format-ref '%T' "$parent")
+                       if [ "x$ptree" = "x$ctree" ]; then
+                               psame+=" $parent"
+                       fi
+               done
+               case "$psame" in ""|" * *") break ;; esac
+               ref="${psame# }"
+       done
+       echo "$ref"
+}
+
+t-check-pushed-master () {
+       local master=`t-git-get-ref refs/heads/master`
+       if [ x$master = x$t_ref_val ]; then return; fi
+       if [ x$master = x ]; then fail "failed to push master"; fi
+       # didn't update master, it must be not FF
+       local mbase=`t-git-merge-base $master $t_ref_val`
+       if [ x$mbase = x$master ]; then fail "failed to ff master"; fi
 }
 
 t-pushed-good () {
        local branch=$1
+       local suite=${2:-sid}
+       t-refs-same \
+               refs/heads/$branch
+       t-pushed-good-core
+}
+       
+t-pushed-good-core () {
        t-ref-dsc-dgit
        t-refs-same \
-               refs/heads/$branch \
                `t-v-tag` \
-               refs/remotes/dgit/dgit/sid
+               refs/remotes/dgit/dgit/$suite
        t-refs-notexist \
                refs/heads/dgit/unstable \
                refs/remotes/dgit/dgit/unstable
-       (set -e; cd $tmp/git/$p.git
+       (set -e; cd $dgitrepo
         t-refs-same \
-               refs/dgit/sid \
+               refs/dgit/$suite \
                `t-v-tag`
+        ${t_check_pushed_master:- : NOT-DRS-NO-CHECK-PUSHED-MASTER}
         t-refs-notexist \
                refs/dgit/unstable
        )
        git verify-tag `t-v-tag`
 }
 
+t-splitbrain-pushed-good--unpack () {
+       cd $tmp
+       rm -rf t-unpack
+       mkdir t-unpack
+       cd t-unpack
+       ln -s $tmp/mirror/pool/main/*.orig*.tar* .
+       ln -s $incoming_dsc .
+       ln -s ${incoming_dsc/.dsc/.debian.tar}* .
+       dpkg-source "$@" -x *.dsc
+       cd */.
+       git init
+       git fetch ../../$p "refs/tags/*:refs/tags/*"
+}
+
+t-splitbrain-pushed-good--checkprep () {
+       git add -Af .
+       git rm --cached -r --ignore-unmatch .pc
+}
+
+t-splitbrain-pushed-good--checkdiff () {
+       local tag=$1
+       t-splitbrain-pushed-good--checkprep
+       t-output "" git diff --stat --cached $tag
+}
+
+t-splitbrain-pushed-good-start () {
+       dep14tag=refs/tags/test-dummy/${v//\~/_}
+       dgittag=$(t-v-tag)
+       t-output "" git status --porcelain
+       t-ref-head
+       t-refs-same $dep14tag
+       (set -e; cd $dgitrepo; t-refs-same $dep14tag)
+       git merge-base --is-ancestor $dep14tag $dgittag
+
+       t-refs-same-start
+       t-pushed-good-core
+
+       t-incoming-dsc
+
+       t-splitbrain-pushed-good--unpack
+       t-splitbrain-pushed-good--checkdiff $dgittag
+}
+t-splitbrain-pushed-good-end-made-dep14 () {
+       t-splitbrain-pushed-good--checkdiff $dep14tag
+       cd $tmp/$p
+}
+
+t-splitbrain-rm-gitignore-patch () {
+       perl -i -pe '
+               next unless $_ eq "auto-gitignore\n";
+               die if $counter++;
+               chomp;
+               rename "debian/patches/$_", "../t-auto-gitignore" or die $!;
+               $_ = "";
+       ' debian/patches/series
+}
+
+t-gbp-pushed-good () {
+       local suite=${1:-sid}
+       t-splitbrain-pushed-good-start
+
+       # Right, now we want to check that the maintainer tree and
+       # the dgit tree differ in exactly the ways we expect.  We
+       # achieve this by trying to reconstruct the maintainer tree
+       # from the dgit tree.
+
+       # So, unpack it withut the patches applied
+       t-splitbrain-pushed-good--unpack --skip-patches
+
+       # dgit might have added a .gitignore patch, which we need to
+       # drop and remove
+       t-splitbrain-rm-gitignore-patch
+
+       # Now the result should differ only in non-debian/ .gitignores
+       t-splitbrain-pushed-good--checkprep
+       git diff --cached --name-only $dep14tag >../changed
+       perl -ne '
+               next if !m#^debian/# && m#(^|/)\.gitignore#;
+               die "$_ mismatch";
+       ' <../changed
+
+       # If we actually apply the gitignore patch by hand, it
+       # should be perfect:
+       if [ -f ../t-auto-gitignore ]; then
+               patch --backup-if-mismatch -p1 -u <../t-auto-gitignore
+       fi
+
+       t-splitbrain-pushed-good-end-made-dep14
+}
+
+t-unapplied-pushed-good () {
+       t-splitbrain-pushed-good-start
+       t-splitbrain-pushed-good--unpack --skip-patches
+       t-splitbrain-pushed-good-end-made-dep14
+}
+
+t-dpm-pushed-good () {
+       t-splitbrain-pushed-good-start
+       t-splitbrain-pushed-good--unpack
+       t-splitbrain-rm-gitignore-patch
+       t-splitbrain-pushed-good-end-made-dep14
+}
+
+t-commit-build-push-expect-log () {
+       local msg=$1
+       local mpat=$2
+       t-commit "$msg"
+       t-dgit build
+       LC_MESSAGES=C \
+       t-dgit push --new 2>&1 |tee $tmp/push.log
+       t-grep-mpat "$mpat" $tmp/push.log
+}
+
 t-822-field () {
        local file=$1
        local field=$2
@@ -297,18 +693,127 @@ t-822-field () {
        ' <$file
 }
 
-t-ref-dsc-dgit () {
+t-stunt-envvar () {
+       local var=$1
+       local tstunt=$2
+       eval '
+               case "$'$var'" in
+               "$tstunt:"*)    ;;
+               *":$tstunt:"*)  ;;
+               "")             '$var'="$tstunt" ;;
+               *)              '$var'="$tstunt:$'$var'" ;;
+               esac
+               export '$var'
+       '
+}
+
+t-tstunt () {
+       local tstunt=$tmp/tstunt
+       t-stunt-envvar PATH $tstunt
+       t-stunt-envvar PERLLIB $tstunt
+       local f
+       for f in "$@"; do
+               f="./$f"
+               local d="$tstunt/${f%/*}"
+               mkdir -p $d
+               ln -sf "$troot/tstunt/$f" "$d"/.
+       done
+}
+
+t-tstunt-parsechangelog () {
+       t-tstunt dpkg-parsechangelog Dpkg/Changelog/Parse.pm
+}
+
+t-incoming-dsc () {
        local dsc=${p}_${v}.dsc
-       local val=`t-822-field $tmp/incoming/$dsc Dgit`
-       perl -e '$_=shift @ARGV; die "$dsc Dgit $_ ?" unless m/^\w+\b/;' "$val"
-       t-ref-same-val $dsc "$val"
+       incoming_dsc=$tmp/incoming/$dsc
+}
+
+t-ref-dsc-dgit () {
+       t-incoming-dsc
+       local val=`t-822-field $incoming_dsc Dgit`
+       perl -e '$_=shift @ARGV; die "Dgit $_ ?" unless m/^\w+\b/;' "$val"
+       t-ref-same-val $incoming_dsc "$val"
 }
 
 t-apply-diff () {
        local v1=$1
        local v2=$2
-       (cd $troot/pkg-srcs; debdiff ${p}_${v1}.dsc ${p}_${v2}.dsc) \
-               | patch -p1 -u
+       (cd $troot/pkg-srcs;
+        debdiff ${p}_${v1}.dsc ${p}_${v2}.dsc || test $? = 1) \
+        | patch -p1 -u
+}
+
+t-gbp-unapplied-pq2qc () {
+       # does `gbp pq export'
+       # commits the resulting debian/patches on  qc/BRANCH
+       # leaves us on qc/BRANCH (eg "qc/quilt-tip"))
+       # qc/BRANCH is not fast-forwarding
+
+       gbp pq export
+
+       branch=`git symbolic-ref HEAD`
+       branch=${branch#refs/heads/}
+
+       case "$branch" in
+       */*) fail "unexpected branch $branch" ;;
+       esac
+
+       git branch -f qc/$branch
+       git checkout qc/$branch
+       git add debian/patches
+       git commit -m 'Commit patch queue'
+}
+
+t-git-pseudo-merge () {
+       # like   git merge -s ours
+       if [ ! "$git_pseuomerge_opts" ]; then
+               if git merge --help \
+                | grep -q allow-unrelated-histories; then
+                       git_pseuomerge_opts='--allow-unrelated-histories'
+               fi
+               git_pseuomerge_opts+=' -s ours'
+       fi
+       git merge $git_pseuomerge_opts "$@"
+}
+
+t-gbp-example-prep-no-ff () {
+       t-tstunt-parsechangelog
+       t-archive example 1.0-1
+       t-git-none
+       t-worktree 1.0
+
+       cd example
+
+       t-dgit fetch
+
+       git checkout -b patch-queue/quilt-tip-2 patch-queue/quilt-tip
+       gbp pq rebase
+
+       echo '/* some comment */' >>src.c
+       git add src.c
+       git commit -m 'Add a comment to an upstream file'
+
+       t-gbp-unapplied-pq2qc
+
+       t-commit 'some updates' 1.0-2
+}
+
+t-gbp-example-prep () {
+       t-gbp-example-prep-no-ff
+
+       t-git-pseudo-merge \
+               -m 'Pseudo-merge to make descendant of archive' \
+               remotes/dgit/dgit/sid
+}
+
+t-commit () {
+       local msg=$1
+       v=${2:-${majorv:-1}.$revision}
+       dch -v$v --distribution ${3:-unstable} "$1"
+       git add debian/changelog
+       debcommit
+       revision=$(( ${revision-0} + 1 ))
 }
 
 t-git-config () {
@@ -317,24 +822,40 @@ t-git-config () {
 
 t-drs () {
        export DGIT_TEST_TROOT=$troot
-       export DGIT_TEST_TMP=$tmp
  t-git-config dgit-distro.test-dummy.git-url "ext::$troot/drs-git-ext %S "
  t-git-config dgit-distro.test-dummy.git-check true
  t-git-config dgit-distro.test-dummy.git-create true
-       cp $root/tests/gnupg/{dd.gpg,dm.gpg,dm.txt} $tmp/.
-       cp $root/tests/suites $tmp/.
+ t-git-config dgit-distro.test-dummy.dgit-tag-format new,old,maint
+       cp $troot/gnupg/{dd.gpg,dm.gpg,dm.txt} $tmp/.
+       cp $troot/suites $tmp/.
+       cp $troot/suites $tmp/suites-master
+
+       export t_check_pushed_master=t-check-pushed-master
 
        drs_dispatch=$tmp/distro=test-dummy
        mkdir $drs_dispatch
-       ln -sf $root $drs_dispatch/dgit-live
+
+       if [ "x$DGIT_TEST_INTREE" != x ]; then
+               ln -sf "$DGIT_TEST_INTREE" $drs_dispatch/dgit-live
+       fi
+
        ln -sf $tmp/git $drs_dispatch/repos
-       ln -sf $tmp/suites $tmp/dm.txt $drs_dispatch/
+       ln -sf $tmp/suites $tmp/suites-master $tmp/dm.txt $drs_dispatch/
        mkdir -p $drs_dispatch/keyrings
        ln -sf $tmp/dd.gpg $drs_dispatch/keyrings/debian-keyring.gpg
        ln -sf $tmp/dm.gpg $drs_dispatch/keyrings/debian-maintainers.gpg
        ln -sf /bin/true $drs_dispatch/policy-hook
 }
 
+t-newtag () {
+ export tagpfx=archive/test-dummy
+ t-git-config dgit-distro.test-dummy.dgit-tag-format new,maint
+}
+t-oldtag () {
+ export tagpfx=test-dummy
+ t-git-config dgit-distro.test-dummy.dgit-tag-format old
+}
+
 t-dsd () {
        t-drs
  t-git-config dgit-distro.test-dummy.ssh "$troot/dsd-ssh"
@@ -356,21 +877,54 @@ t-policy-admin () {
        ${DGIT_INFRA_PFX}dgit-repos-admin-debian --repos $tmp/git "$@"
 }
 
+t-policy-nonexist () {
+       ln -sf no-such-file-or-directory $drs_dispatch/policy-hook
+}
+
+t-make-hook-link () {
+       local hook=$1 # in infra/
+       local linkpath=$2
+       hook=${DGIT_INFRA_PFX}$hook
+       case $hook in
+       */*)    ;;
+       *)      hook=`type -P $hook` ;;
+       esac
+       ln -sf "$hook" $linkpath
+}
+
+t-policy () {
+       local policyhook=$1
+       t-make-hook-link $policyhook $drs_dispatch/policy-hook
+}
+
 t-debpolicy () {
        t-dsd
-
-       ln -sf ${DGIT_INFRA_PFX}dgit-repos-policy-debian \
-               $drs_dispatch/policy-hook
+       t-policy dgit-repos-policy-debian
 
        mkdir $tmp/git
        t-policy-admin create-db
 }
 
+t-policy-periodic () {
+       ${DGIT_REPOS_SERVER_TEST-dgit-repos-server} \
+               test-dummy $drs_dispatch '' --cron
+}
+
+t-restrict () {
+       local restriction=$1
+       (cd $root; t-restriction-$restriction >&2)
+}
+
+t-dependencies () {
+       : "Hopefully installed: $*"
+}
+
 t-chain-test () {
        local ct=$1
        local d=${0%/*}
        cd $root
        export DGIT_TEST_TESTNAME="$testname"
+       export DGIT_TEST_TMPBASE="$tmpbase"
        export ADTTMP=$tmp
        exec "$d/$ct"
 }      
@@ -380,3 +934,8 @@ t-alt-test () {
        t-${t%%-*}
        t-chain-test "${t#*-}"
 }
+
+case "$0" in
+*/gnupg) ;;
+*)     t-setup-import gnupg    ;;
+esac