chiark / gitweb /
* adt-run: new --instantiate option to allow package installation to be
authorIan Jackson <ian@anarres>
Fri, 23 Mar 2007 16:59:04 +0000 (16:59 +0000)
committerIan Jackson <ian@anarres>
Fri, 23 Mar 2007 16:59:04 +0000 (16:59 +0000)
  forced for testing.  (This is not an ideal approach - it's not very
  flexible - but works well enough for the current requirements.)
* adt-testreport-onepackage: new ability to test binary as well as
  source packages, using new --instantiate option.
* new `timeout=' option on `execute' virt server command.

debian/changelog
doc/README.virtualisation-server
runner/adt-run
runner/adt-testreport-onepackage
runner/onepackage-config
virt-subproc/VirtSubproc.py

index 87176ba08b86afeb9bad6df6964059e55fb3d572..6bcc368b7e8824a534bcd7ff74fd8b291400f0d7 100644 (file)
@@ -1,3 +1,14 @@
+autopkgtest (0.7.2~~iwj) unstable; urgency=low
+
+  * adt-run: new --instantiate option to allow package installation to be
+    forced for testing.  (This is not an ideal approach - it's not very
+    flexible - but works well enough for the current requirements.)
+  * adt-testreport-onepackage: new ability to test binary as well as
+    source packages, using new --instantiate option.
+  * new `timeout=' option on `execute' virt server command.
+
+ -- Ian Jackson <iwj@ubuntu.com>  Fri, 23 Mar 2007 16:58:42 +0000
+
 autopkgtest (0.7.2) feisty; urgency=low
 
   * adt-testreport-onepackage: new management script, with some
index ab7243cf66de12564bb13795cc097c74e8ffd155..e01137e591b0c3127622296ec0e496fa848288c9 100644 (file)
@@ -119,6 +119,19 @@ Protocol
                If this feature is available, execute-debug will
                be advertised.  Only one such plumbing is available.
 
+       timeout=<seconds>
+
+               Ensures that the whole execute command does not take
+               more than <seconds>.  If it does, the response is
+                       timeout
+               instead of `ok <exit-status>'.
+
+               An effort will be made to kill the processes on the
+               testbed but this is not guaranteed to be possible or
+               successful.  After an `execute' has timed out, the
+               testbed should probably be reverted with `revert' if
+               that facility is available.
+
 * Commands
        copydown <host-tree> <testbed-path>
        copyup <testbed-tree> <host-path>
index 8873757bb00bbf3336b50896b11bb2761dd9a384..403a9d3bdea705d7859ecf1ab64a432622a3a144 100755 (executable)
@@ -447,6 +447,15 @@ def parse_args():
               help='use binary package DEB according'
                    ' to most recent --binaries-* settings')
 
+       def cb_actnoarg(op,optstr,value,parser, largsentry):
+               parser.largs.append(largsentry)
+       pa('','--instantiate', action='callback', callback=cb_actnoarg,
+               callback_args=((None, ('instantiate',)),),
+               help='instantiate testbed now (during testing phase)'
+                    ' and install packages'
+                    ' selected for automatic installation, even'
+                    ' if this might apparently not be required otherwise')
+
        pa_action('override-control',   'CONTROL', ('control',), is_act=0,
               help='run tests from control file CONTROL instead,'
                    ' (applies to next test suite only)')
@@ -608,7 +617,8 @@ def parse_args():
                if kind == 'dsc': fwhatx = '/' + os.path.basename(pathstr)
                else: fwhatx = '-'+kind
 
-               af = constructor(what+fwhatx, pathstr, arghandling['tb'])
+               if pathstr is None: af = None
+               else: af = constructor(what+fwhatx, pathstr, arghandling['tb'])
                opts.actions.append(Action(kind, af, arghandling, what))
 
 def setup_trace():
@@ -1690,7 +1700,7 @@ def process_actions():
        binaries = Binaries()
 
        for act in opts.actions:
-               if not act.af.spec_tbp:
+               if act.af is not None and not act.af.spec_tbp:
                        testbed.register_ephemeral(act.af)
 
        binaries.reset()
@@ -1715,6 +1725,8 @@ def process_actions():
                        act.binaries = []
                if act.kind.endswith('tree') or act.kind == 'dsc':
                        control_override = None
+               if act.kind == 'instantiate':
+                       pass
 
        debug_a1('builds done.')
 
@@ -1750,6 +1762,8 @@ def process_actions():
                        debug_a3('run_tests ...')
                        run_tests(stanzas, act.af)
                        control_override = None
+               if act.kind == 'instantiate':
+                       testbed.prepare([])
        debug_a1('tests done.')
 
 def main():
index 2fc283d47b4bfea9e5be910d54e56f8117713749..d912fd74e5066d57547bc897a4efd91b3995f0bc 100755 (executable)
@@ -15,6 +15,8 @@ from="$salutation Jackson <ian@davenant.greenend.org.uk>"
 rsync=rsync
 disable=true
 interactive=true
+target=source
+arch=`dpkg --print-architecture`
 
 for config in "$@"; do
        case "$config" in
@@ -28,6 +30,23 @@ if $disable; then
        exit 1
 fi
 
+: ${destdirtail:=$distro-$target}
+: ${destdirfin:="$destdircommon$destdirtail"}
+
+case $target in
+source)
+       sources=Sources
+       descx=''
+       ;;
+binary-*)
+       sources=Packages
+       descx="${target#binary-}"
+       ;;
+*)
+       echo >&2 'target must be source or binary-*'
+       exit 1
+esac
+
 exec 3>&1
 printf >&3 "starting "
 
@@ -52,11 +71,13 @@ gurl () {
        curl -fsS "$1" >"$2"
 }
 
-gurl "$mirror/dists/$distro/$suite/source/Sources.gz" "$tmp"/_sources.gz
-zcat "$tmp"/_sources.gz >"$tmp"/_sources-in
+gurl "$mirror/dists/$distro/$suite/$target/$sources.gz" "$tmp"/_$sources.gz
+zcat "$tmp"/_$sources.gz >"$tmp"/_$sources-in
+
+lastinfo="$var"/lastinfo-$target
 
 now=`date +%s`
->>"$var"/last-info
+>>"$lastinfo"
 
 progress selecting
 
@@ -80,29 +101,45 @@ if [ "x$pkg" = x ]; then
        f2();
        f1();
        $best_score= -1;
+       sub scorepackage () {
+               return if $skip;
+               return if $score < $best_score
+                    or ($score==$best_score and \
+                        $package gt $best_package);
+               $best_score= $score;
+               $best_package= $package;
+       }
+       sub endpackage () {
+               return unless (defined $package
+                               or defined $version
+                               or defined $skip);
+               die unless defined $package;
+               die unless defined $version;
+               scorepackage();
+               undef $package;
+               undef $version;
+               undef $skip;
+       }
        while (<F>) {
                if (m/^Package: ($pre)$/) {
-                       die if length $package or length $version;
+                       die if defined $package;
                        $package= $1;
                } elsif (m/^Version: ($vre)$/) {
-                       die unless length $package;
-                       die if length $version;
+                       die if defined $version;
                        $version= $1;
                        $score= '$now' - $lasttime{$package};
                        $score= 1e7 if $score>1e7;
                        $score *= 5 if $lastver{$package} ne $version;
                        $score *= 10 unless $extras{$package} =~ m/ nt /;
-                       next if $score < $best_score
-                            or ($score==$best_score and \
-                                $package gt $best_package);
-                       $best_score= $score;
-                       $best_package= $package;
+               } elsif (m/^Architecture:.*/ &&
+                        !m/\s'$arch'\s/) {
+                       $skip= 1;
                } elsif (m/^$/) {
-                       die if length $package and !length $version;
-                       $package= $version= "";
+                       endpackage();
                }
        }
        f2();
+       endpackage();
        die unless length $best_package;
        open L, ">&4" or die $!;
        printf L "selected %s (age %s, score %d)\n",
@@ -112,13 +149,13 @@ if [ "x$pkg" = x ]; then
                : "<never-yet>",
                $best_score;
        print "$best_package\n" or die $!;
- ' "$var"/last-info "$tmp"/_sources-in`"
+ ' "$lastinfo" "$tmp"/_$sources-in`"
 else
        printf >&4 "package forced: %s\n" "$pkg"
 fi
 
 sed -n "/^Package: $pkg\$/,/^\$/p" \
- <"$tmp"/_sources-in >"$tmp"/_this-stanza
+ <"$tmp"/_$sources-in >"$tmp"/_this-stanza
 
 echo
 cat "$tmp"/_this-stanza
@@ -130,29 +167,42 @@ getfield () {
        `"'
 }
 
-getfield Directory
-getfield Version
-
-leafnames="`
-       sed -n '/^Files:/,/^([^ ].*)?$/{ /^ /{
-               s/^ [0-9a-z][0-9a-z]*  *[0-9][0-9]* //; p
-               }}' \
-        <"$tmp"/_this-stanza
-`"
-
 printf >&3 "selected \"%s\" " $pkg
 
 tp="$tmp/$pkg"
 mkdir "$tp" "$tp/src" "$tp/tmp" "$tp/out"
 
-for leafname in $leafnames; do
-       df="$tp/src/$leafname"
-       case "$leafname" in
-       */*|.*) echo >&2 "bad leafname: $leafname"; exit 1;;
-       *.dsc) dsc="$df";;
-       esac
-       gurl "$mirror/$pDirectory/$leafname" "$df"
-done
+getfield Version
+
+if test $target = source; then
+       getfield Directory
+       leafnames="`
+               sed -n '/^Files:/,/^([^ ].*)?$/{ /^ /{
+                       s/^ [0-9a-z][0-9a-z]*  *[0-9][0-9]* //; p
+                       }}' \
+                <"$tmp"/_this-stanza
+       `"
+       for leafname in $leafnames; do
+               df="$tp/src/$leafname"
+               case "$leafname" in
+               */*|.*) echo >&2 "bad leafname: $leafname"; exit 1;;
+               *.dsc) fot="$df";;
+               esac
+               gurl "$mirror/$pDirectory/$leafname" "$df"
+       done
+       testmode=--source
+       testmode2=''
+       desc="$pkg"
+       : ${upload_if_ok:=true}
+else
+       getfield Filename
+       fot="$tp/src/$pkg.deb"
+       gurl "$mirror/$pFilename" "$fot"
+       testmode='--binaries=install --binary'
+       testmode2=--instantiate
+       desc="$pkg $descx"
+       : ${upload_if_ok:=false}
+fi
 
 if [ "x$maintainer_email_override" = x ]; then
        getfield Maintainer
@@ -180,7 +230,7 @@ xrc adt-run --tmp-dir "$tp"/tmp                             \
        --log-file "$tp"/log                            \
        --summary "$tmp"/_summary                       \
        $adtrun_extra_opts                              \
-       --source "$dsc"                                 \
+       $testmode "$fot" $testmode2                     \
  ---                                                   \
  adt-virt-xenlvm                                       \
        $adtvirt_extra_opts                             \
@@ -195,8 +245,10 @@ upload=true
 extras=''
 
 case "$rc" in
-0)     summary='all OK';                       email=''                ;;
-2)     summary='OK (some skipped)';            email=''                ;;
+0)     summary='all OK';                       email=''
+                                       upload=$upload_if_ok            ;;
+2)     summary='OK (some skipped)';            email=''
+                                       upload=$upload_if_ok            ;;
 8)     summary='package declares no tests';    email=''
                                        upload=false; extras='nt'       ;;
 4|6)   summary='test(s) failed!';      email="$maintainer_email"       ;;
@@ -220,7 +272,7 @@ if $upload; then
 
        progress "uploading"
        printf >&3 "uploading"
-       $rsync -rltH --safe-links --delete "$tp" "$destrsynchead/$destdirtail/"
+       $rsync -rltH --safe-links --delete "$tp" "$destrsynchead/$destdirfin/"
        printf >&3 " "
 fi
 
@@ -231,9 +283,9 @@ if [ "x$email" != x ]; then
        cat >"$tmp"/_email <<END
 From: $from
 To: $email_addr
-Subject: autopkgtest $distro $pkg: $summary
+Subject: autopkgtest $distro $desc: $summary
 
- Test executed for:  $distro  $pkg
+ Test executed for:  $distro  $target  $pkg
  Outcome: $summary
 END
        sed -e 's/^/  /' "$tmp"/_summary >>"$tmp"/_email
@@ -272,7 +324,7 @@ The test log, which is intended to be sufficient to diagnose most
 failures, can be found below.  However, in case this is not
 sufficient, another copy can be found along with output files, saved
 temporary files, and so on, at:
- $desthttphead/$destdirtail/
+ $desthttphead/$destdirfin/
 
 If you have any questions about this service please contact me at:
  $from
@@ -284,14 +336,14 @@ $salutation
 END
 fi
 
-printf >>"$var"/log "package=%s rc=%s emailed='%s'\n" \
-       "$pkg" $rc "$email_addr"
+printf >>"$var"/log "%s=%s rc=%s emailed='%s'\n" \
+       "$target" "$pkg" $rc "$email_addr"
 
 if [ "x$ourx" = x0 ]; then
-       sed -e "/^$pkg /d" <"$var"/last-info >"$var"/last-info.new
+       sed -e "/^$pkg /d" <"$lastinfo" >"$lastinfo".new
        printf "%s %s %s %s\n" "$pkg" "$pVersion" "$now" "$extras" \
-               >>"$var"/last-info.new
-       mv "$var"/last-info.new "$var"/last-info
+               >>"$lastinfo".new
+       mv "$lastinfo".new "$lastinfo"
        progress "tested."
 else
        progress "fault ($ourx)."
index e864343f6fc6386373be29e8210907b9d3463097..883a7039be02299319372e819202d94425dc38e6 100644 (file)
@@ -2,4 +2,4 @@ cd /root/adt-play
 disable=false
 desthttphead=http://www.chiark.greenend.org.uk/~ijackson/
 destrsynchead=ijackson@login.chiark.greenend.org.uk:public-html/
-destdirtail=autopkgtest-output/$distro
+destdircommon=autopkgtest-output/
index 32af6d5aeb3e0685aecd995b1f44201831b01235..8a4216c1694c45f46ef035afa247df70f1140862 100644 (file)
@@ -35,10 +35,19 @@ debuglevel = None
 progname = "<VirtSubproc>"
 devnull_read = file('/dev/null','r')
 caller = __main__
+copy_timeout = 300
 
 class Quit:
        def __init__(q,ec,m): q.ec = ec; q.m = m
 
+class Timeout: pass
+def alarm_handler(*a): raise Timeout()
+def timeout_start(to): signal.alarm(to)
+def timeout_stop(): signal.alarm(0)
+
+class FailedCmd:
+       def __init__(fc,e): fc.e = e
+
 def debug(m):
        if not debuglevel: return
        print >> sys.stderr, progname+": debug:", m
@@ -70,17 +79,19 @@ def cmd_close(c, ce):
 def preexecfn():
        caller.hook_forked_inchild()
 
-def execute_raw(what, instr, *popenargs, **popenargsk):
+def execute_raw(what, instr, timeout, *popenargs, **popenargsk):
        debug(" ++ %s" % string.join(popenargs[0]))
        sp = subprocess.Popen(preexec_fn=preexecfn, *popenargs, **popenargsk)
        if instr is None: popenargsk['stdin'] = devnull_read
+       timeout_start(timeout)
        (out, err) = sp.communicate(instr)
+       timeout_stop()
        if err: bomb("%s unexpectedly produced stderr output `%s'" %
                        (what, err))
        status = sp.wait()
        return (status, out)
 
-def execute(cmd_string, cmd_list=[], downp=False, outp=False):
+def execute(cmd_string, cmd_list=[], downp=False, outp=False, timeout=0):
        cmdl = cmd_string.split()
 
        if downp: perhaps_down = down
@@ -92,7 +103,8 @@ def execute(cmd_string, cmd_list=[], downp=False, outp=False):
        cmd = cmdl + cmd_list
        if len(perhaps_down): cmd = perhaps_down + [' '.join(cmd)]
 
-       (status, out) = execute_raw(cmdl[0], None, cmd, stdout=stdout)
+       (status, out) = execute_raw(cmdl[0], None, timeout,
+                               cmd, stdout=stdout)
 
        if status: bomb("%s%s failed (exit status %d)" %
                        ((downp and "(down) " or ""), cmdl[0], status))
@@ -148,6 +160,7 @@ def cmd_execute(c, ce):
        cmdnumargs(c, ce, 5, None)
        debug_re = regexp.compile('debug=(\d+)\-(\d+)$')
        debug_g = None
+       timeout = 0
        envs = []
        for kw in ce[6:]:
                if kw.startswith('debug='):
@@ -155,6 +168,9 @@ def cmd_execute(c, ce):
                        m = debug_re.match(kw)
                        if not m: bomb("invalid execute debug arg `%s'" % kw)
                        debug_g = m.groups()
+               elif kw.startswith('timeout='):
+                       try: timeout = int(kw[8:],0)
+                       except ValueError: bomb("invalid timeout arg `%s'" %kw)
                elif kw.startswith('env='):
                        es = kw[4:]; eq = es.find('=')
                        if eq <= 0: bomb("invalid env arg `%s'" % kw)
@@ -195,8 +211,13 @@ def cmd_execute(c, ce):
                "               os._exit(127)\n")
        cmdl = down_python_script(gobody)
 
-       (status, out) = execute_raw('sub-python', None, cmdl, stdout=stdout,
-                               stdin=devnull_read, stderr=subprocess.PIPE)
+       try:
+               (status, out) = execute_raw('sub-python', None, timeout,
+                               cmdl, stdout=stdout, stdin=devnull_read,
+                               stderr=subprocess.PIPE)
+       except Timeout:
+               raise FailedCmd(['timeout'])
+
        if out: bomb("sub-python unexpected produced stdout"
                        " visible to us `%s'" % out)
        return [`status`]
@@ -268,11 +289,15 @@ def copyupdown(c, ce, upp):
        debug(" +> %s" % string.join(cmdls[1]))
        subprocs[1] = subprocess.Popen(cmdls[1], stdin=subprocs[0].stdout,
                        stdout=deststdout, preexec_fn=preexecfn)
+       timeout_start(copy_timeout)
        for sdn in [1,0]:
                debug(" +"+"<>"[sdn]+"?");
                status = subprocs[sdn].wait()
-               if status: bomb("%s %s failed, status %d" %
-                       (wh, ['source','destination'][sdn], status))
+               if status:
+                       timeout_stop()
+                       bomb("%s %s failed, status %d" %
+                               (wh, ['source','destination'][sdn], status))
+       timeout_stop()
 
 def cmd_copydown(c, ce): copyupdown(c, ce, False)
 def cmd_copyup(c, ce): copyupdown(c, ce, True)
@@ -287,9 +312,12 @@ def command():
        debug('executing '+string.join(ce))
        try: f = globals()['cmd_'+c[0]]
        except KeyError: bomb("unknown command `%s'" % ce[0])
-       r = f(c, ce)
-       if not r: r = []
-       r.insert(0, 'ok')
+       try:
+               r = f(c, ce)
+               if not r: r = []
+               r.insert(0, 'ok')
+       except FailedCmd, fc:
+               r = fc.e
        print string.join(r)
 
 def cleanup():
@@ -345,6 +373,7 @@ def mainloop():
                sys.exit(16)
 
 def main():
+       signal.signal(signal.SIGALRM, alarm_handler)
        debug("down = %s" % string.join(down))
        ok()
        prepare()