# exec 2>&1 set -x set -o pipefail . tests/lib-core . tests/lib-restricts t-report-failure () { set +x rc=$1 cat <&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} 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##*/}}" 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` t-set-using-tmp env -0 >$tmp/.save-env ln -f $troot/ssh ssh export DEBCHANGE_VENDOR=dpkg mkdir -p $tmp/incoming cat <$tmp/dput.cf [test-dummy] method = local incoming = $tmp/incoming run_dinstall = 0 END : ${tagpfx:=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 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 -a "$edittree"/* . else tar xf "$tarfile" fi } t-worktree () { rm -rf $p t-untar $troot/worktrees/${p}_$1 } 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 (set -e; cd $tmp/git; t-untar $gs) } t-git-none () { mkdir -p $tmp/git (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=`t-git-merge-base $ancestor $now` if [ x$mbase != x$ancestor ]; then fail "not ff $ancestor..$now, $mbase != $ancestor" fi } t-prep-newpackage () { t-select-package $1 v=$2 t-archive-none $p t-git-none t-worktree $v cd $p 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 () { t-select-package $1 mkdir -p $tmp/aq/dsc_in_suite $tmp/mirror/pool/main : >$tmp/aq/suites local jsondelim="[" local suitespec for suitespec in $suitespecs; do local suite=${suitespec%%:*} local sname=${suitespec#*:} >$tmp/aq/package.$suite.$p t-archive-updated $suite $p >$tmp/aq/package.new.$p t-archive-updated new $p ln -sf $suite $tmp/aq/dsc_in_suite/$sname cat <>$tmp/aq/suites $jsondelim { "archive" : "ftp-master", "codename" : "$suite", "components" : [ "main", "contrib", "non-free" ], "name" : "$sname", "dakname" : "$sname" END jsondelim=" }," done cat <>$tmp/aq/suites } ] END } t-archive-updated () { local suite=$1 local p=$2 local suitedir=$tmp/aq/dsc_in_suite/$suite mkdir -p $suitedir perl <$tmp/aq/package.$suite.$p >$suitedir/$p -wne ' use JSON; use strict; our @v; m{^(\S+) (\w+) ([^ \t/]+)/(\S+)} or die; push @v, { "version" => "$1", "sha256sum" => "$2", "component" => "$3", "filename" => "$4", }; END { my $json = JSON->new->canonical(); print $json->encode(\@v) or die $!; } ' } t-archive-process-incoming () { local suite=$1 mv $tmp/incoming/${p}_${v}[._]* $tmp/mirror/pool/main/ t-archive-query "$suite" } t-archive-query () { local suite=${1-sid} local dscf=main/${p}_${v}.dsc local sha=`sha256sum <$tmp/mirror/pool/$dscf` echo "${v} ${sha% -} $dscf" >>$tmp/aq/package.$suite.${p} t-archive-updated $suite $p } t-archive () { t-archive-none $1 v=$2 local dscf=${p}_$2.dsc rm -f $tmp/mirror/pool/main/${p}_* ln $troot/pkg-srcs/${p}_${2%-*}* $tmp/mirror/pool/main/ t-archive-query rm -rf $tmp/extract mkdir $tmp/extract (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 $t_dgit_xopts "$@" : '}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ' } 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 t-refs-same-start t-refs-same \ refs/heads/dgit/sid \ refs/remotes/dgit/dgit/sid t-refs-notexist refs/dgit/unstable refs/remotes/dgit/dgit/unstable } t-output () { printf "%s${1:+\n}" "$1" >$tmp/t.want shift "$@" >$tmp/t.got diff $tmp/t.want $tmp/t.got } 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 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` t-ref-same-val "$name" $val } t-ref-head () { local val=`git rev-parse HEAD` t-ref-same-val HEAD $val } t-ref-same-val () { local name="$1" local val=$2 case "$t_ref_val" in '') ;; "$val") ;; *) fail "ref varies: $name:\ ${val:-nothing} != ${t_ref_val:-nothing}" ;; esac t_ref_val="$val" } t-refs-same-start () { t_ref_val='' } t-refs-same () { local g for g in $*; do t-ref-same $g done } t-refs-notexist () { local val for g in $*; do val=`t-git-get-ref $g` if [ "x$val" != x ]; then fail "ref $g unexpectedly exists ($val)" fi done } t-v-tag () { 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 \ `t-v-tag` \ refs/remotes/dgit/dgit/$suite t-refs-notexist \ refs/heads/dgit/unstable \ refs/remotes/dgit/dgit/unstable (set -e; cd $dgitrepo t-refs-same \ 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 perl -e ' use Dpkg::Control::Hash; my $h = new Dpkg::Control::Hash allow_pgp=>1; $h->parse(\*STDIN,"'"$file"'"); my $val = $h->{"'$field'"},"\n"; die "'"$file $field"'" unless defined $val; print $val,"\n"; ' <$file } 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 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 || 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 () { git config --global "$@" } t-drs () { export DGIT_TEST_TROOT=$troot 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 t-git-config dgit-distro.test-dummy.dgit-tag-format old,new 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 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/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 () { 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" t-git-config dgit-distro.test-dummy.git-check ssh-cmd t-git-config dgit-distro.test-dummy.git-create true t-git-config dgit-distro.test-dummy.git-url \ "ext::$troot/dsd-ssh X %S /dgit/test-dummy/repos" t-git-config dgit-distro.test-dummy.diverts.drs /drs t-git-config dgit-distro.test-dummy/drs.ssh "$troot/ssh" t-git-config dgit-distro.test-dummy/drs.git-url $tmp/git t-git-config dgit-distro.test-dummy/drs.git-check ssh-cmd t-git-config dgit-distro.test-dummy/drs.git-create ssh-cmd echo 'no-such-package* drs' >$drs_dispatch/diverts } 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 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" } t-alt-test () { local t=${0##*/} t-${t%%-*} t-chain-test "${t#*-}" } case "$0" in */gnupg) ;; *) t-setup-import gnupg ;; esac