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