tmpdir = None # pathstring on host
testbed = None # Testbed
errorcode = 0 # exit status that we are going to use
+timeouts = { 'short':10, 'install':300, 'test':300, 'build':3000 }
binaries = None # Binaries (.debs we have registered)
+build_essential = ["build-essential"]
#---------- output handling
#
# is done by forking off a copy of ourselves to do plumbing,
# which copy we wait for at the appropriate point.
+class DummyOpts:
+ def __init__(do): do.debuglevel = 0
+
+opts = DummyOpts()
trace_stream = None
+summary_stream = None
def pstderr(m):
print >>sys.stderr, m
else: ep.stream = trace_stream
ep._sp = None
else:
- ep._sp = subprocess.Popen(['tee','/dev/stderr'],
+ ep._sp = subprocess.Popen(['tee','-a','/dev/stderr'],
stdin=subprocess.PIPE, stdout=trace_stream,
close_fds=True)
ep.stream = ep._sp.stdin
ep.wait()
return (rc, output)
+def psummary(m):
+ if summary_stream is not None: print >>summary_stream, m
+
def preport(m):
print m
+ sys.stdout.flush()
if trace_stream is not None: print >>trace_stream, m
+ psummary(m)
def report(tname, result):
preport('%-20s %s' % (tname, result))
else: return p.path[tbp]+p.dir+'!'
out = p.what
if p.spec is not None:
- if p.spec_tbp: out += '#'
+ if not hasattr(p,'spec_tb'): out += '~'
+ elif p.spec_tbp: out += '#'
else: out += '='
out += p.spec
out += ':'
def _wrong(p, how):
xtra = ''
- if p.spec is not None: xtra = ' spec[%s]=%s' % (p.spec, p.spec_tb)
+ if p.spec is not None:
+ xtra = ' spec[%s]=%s' % (p.spec, getattr(p,'spec_tb',None))
raise ("internal error: %s (%s)" % (how, str(p)))
def _ensure_path(p, tbp):
def parse_args():
global opts
+ global n_non_actions # argh, stupid python scoping rules
usage = "%prog <options> --- <virt-server>..."
parser = OptionParser(usage=usage)
pa = parser.add_option
# actions (ie, test sets to run, sources to build, binaries to use):
def cb_action(op,optstr,value,parser, long,kindpath,is_act):
+ global n_non_actions
parser.largs.append((value,kindpath))
n_non_actions += not(is_act)
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)')
def cb_path(op,optstr,value,parser, constructor,long,dir):
name = long.replace('-','_')
- af = constructor(arghandling['tb'], value, long, dir)
+ af = constructor(long, value,arghandling['tb'])
setattr(parser.values, name, af)
def pa_path(long, constructor, help, dir=False):
pa('','--log-file', type='string', dest='logfile',
help='write the log LOGFILE, emptying it beforehand,'
' instead of using OUTPUT-DIR/log or TMPDIR/log')
+ pa('','--summary-file', type='string', dest='summary',
+ help='write a summary report to SUMMARY,'
+ ' emptying it beforehand')
pa('','--user', type='string', dest='user',
help='run tests as USER (needs root on testbed)')
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():
- global trace_stream, tmpdir
+ global trace_stream, tmpdir, summary_stream
if opts.tmpdir is not None:
rmtree('tmpdir(specified)',opts.tmpdir)
opts.logfile = opts.tmpdir + '/log'
if opts.logfile is not None:
trace_stream = open(opts.logfile, 'w', 0)
+ if opts.summary is not None:
+ summary_stream = open(opts.summary, 'w', 0)
debug('options: '+`opts`, 1)
def finalise_options():
- global opts, tb
+ global opts, tb, build_essential
if opts.user is None and 'root-on-testbed' not in testbed.caps:
opts.user = ''
if (opts.user or
'root-on-testbed' not in testbed.caps):
opts.gainroot = 'fakeroot'
+ build_essential += ['fakeroot']
if opts.gnupghome.startswith('~/'):
try: home = os.environ['HOME']
if not tb._need_reset_apt: return
what = 'aptget-update-reset'
cmdl = ['apt-get','-qy','update']
- rc = tb.execute(what, cmdl)
+ rc = tb.execute(what, cmdl, timeout=timeouts['install'])
if rc:
pstderr("\n" "warning: failed to restore"
" testbed apt cache, exit code %d" % rc)
(tb.modified, tb.deps_processed, deps_new), 1)
if 'revert' in tb.caps and (tb.modified or
[d for d in tb.deps_processed if d not in deps_new]):
+ for af in tb._ephemeral: af.read(False)
tb._debug('reset **')
tb.command('revert')
tb.blamed = []
tb.prepare1(deps_new)
tb.prepare2(deps_new)
def register_ephemeral(tb, af):
- if not getattr(af,'spec_tbp',False): tb._ephemeral.append(af)
+ tb._ephemeral.append(af)
def _install_deps(tb, deps_new):
tb._debug(' installing dependencies '+`deps_new`, 1)
tb.deps_processed = deps_new
]])
cmdl = ['python','-c',script]
what = 'install-deps'
- rc = testbed.execute(what+'-debinstall', cmdl, script=script)
+ rc = testbed.execute(what+'-debinstall', cmdl, script=script,
+ timeout=timeouts['install'])
if rc: badpkg('dependency install failed, exit code %d' % rc)
def needs_reset(tb):
tb._debug('needs_reset, previously=%s' % tb.modified, 1)
return rl[0]
def execute(tb, what, cmdl,
si='/dev/null', so='/dev/null', se=None, cwd=None,
- script=False, tmpdir=None):
+ script=False, tmpdir=None, timeout=timeouts['short']):
# Options for script:
# False - do not call debug_subprocess, no synch. reporting required
# None or string - call debug_subprocess with that value,
','.join(map(urllib.quote, cmdl)),
si, so, se_use, cwd]
+ if timeout is not None and timeout > 0:
+ cmdl.append('timeout=%d' % timeout)
+
if xdump is not None and 'execute-debug' in tb.caps: cmdl += [xdump]
if tmpdir is not None: cmdl.append('env=TMPDIR=%s' % tmpdir)
global errorcode, testbed
if stanzas == ():
report('*', 'SKIP no tests in this package')
+ errorcode |= 8
for stanza in stanzas:
tests = stanza[' tests']
if not tests:
for t in tests:
t.prepare()
t.run(tree)
- if 'breaks-testbed' in t.restrictions:
+ if 'breaks-testbed' in t.restriction_names:
testbed.needs_reset()
testbed.needs_reset()
t._debug('[----------------------------------------')
def stdouterr(oe):
idstr = t.what + '-' + oe
- if opts.output_dir is not None and opts.output_dir.tb:
+ if opts.output_dir is not None and opts.output_dir.spec_tbp:
use_dir = opts.output_dir
else:
use_dir = testbed.scratch
tf = af.read(True)
tmpdir = None
+ tree.read(True)
+
+ rc = testbed.execute('testchmod-'+t.what, ['chmod','+x','--',tf])
+ if rc: bomb('failed to chmod +x %s' % tf)
- if 'needs-root' not in t.restrictions:
- tf = opts.user_wrap(tf)
- tmpdir = '%s/%s-tmpdir' % (testbed.scratch.read(True), t.what)
+ if 'needs-root' not in t.restriction_names and opts.user is not None:
+ tfl = ['su',opts.user,'-c',tf]
+ tmpdir = '%s%s-tmpdir' % (testbed.scratch.read(True), t.what)
script = 'rm -rf -- "$1"; mkdir -- "$1"'
if opts.user: script += '; chown %s "$1"' % opts.user
+ if 'rw-build-tree' in t.restriction_names:
+ script += '; chown -R %s "$2"' % opts.user
rc = testbed.execute('mktmpdir-'+t.what,
- ['sh','-xec',script,'x',tmpdir])
+ ['sh','-xec',script,'x',tmpdir,tree.read(True)])
if rc: bomb("could not create test tmpdir `%s', exit code %d"
% (tmpdir, rc))
+ else:
+ tfl = [tf]
- rc = testbed.execute('test-'+t.what, [tf],
+ rc = testbed.execute('test-'+t.what, tfl,
so=so.write(True), se=se.write(True), cwd=tree.read(True),
- tmpdir=tmpdir)
+ tmpdir=tmpdir, timeout=timeouts['test'])
so_read = so.read()
se_read = se.read()
if stab.st_size != 0:
l = open(se_read).readline()
l = l.rstrip('\n \t\r')
- if len(l) > 40: l = l[:40] + '...'
+ if len(l) > 35: l = l[:35] + '...'
t.reportfail('status: %d, stderr: %s' % (rc, l))
t._debug(' - - - - - - - - - - stderr - - - - - - - - - -')
debug_file(se_read)
(et, q, tb) = ei
if et is Quit:
pstderr('adt-run: ' + q.m)
+ psummary('quitting: '+q.m)
return q.ec
else:
pstderr("adt-run: unexpected, exceptional, error:")
+ psummary('quitting: unexpected error, consult transcript')
traceback.print_exc(None, sys.stderr)
if trace_stream is not None:
traceback.print_exc(None, trace_stream)
'print res',
'print d.missingDeps',
'print d.requiredChanges',
- 'assert(res)',
+ 'if not res: raise "gdebi failed (%s, %s, %s): %s" % '+
+ ' (`res`, `d.missingDeps`, `d.requiredChanges`, '+
+ 'd._failureString)',
'cache.commit()',
''
]
what = 'apt-get-reinstall'
cmdl = (b.apt_get() + ['--reinstall','install'] +
[pkg for pkg in pkgs_reinstall])
- rc = testbed.execute(what, cmdl, script=None)
+ rc = testbed.execute(what, cmdl, script=None,
+ timeout=timeouts['install'])
if rc: badpkg("installation of basic binarries failed,"
" exit code %d" % rc)
what = 'apt-get-install-%s' % pkg
testbed.blame(pkg)
cmdl = b.apt_get() + ['install',pkg]
- rc = testbed.execute(what, cmdl, script=None)
+ rc = testbed.execute(what, cmdl, script=None,
+ timeout=timeouts['install'])
if rc: badpkg("installation of %s failed, exit code %d"
% (pkg, rc))
so = TemporaryFile('%s-%s-results' % (what,which))
rc = testbed.execute('%s-%s' % (what,which),
['sh','-ec',script]+xargs, script=script,
- so=so.write(True), cwd=cwd)
+ so=so.write(True), cwd=cwd,
+ timeout=timeouts['build'])
results = open(so.read()).read().rstrip('\n')
if len(results): results = results.split("\n")
else: results = []
- if rc: badpkg("%s failed with exit code %d" % (which,rc))
+ if rc: badpkg("rules %s failed with exit code %d" % (which,rc))
if results_lines is not None and len(results) != results_lines:
badpkg("got %d lines of results from %s where %d expected"
% (len(results), which, results_lines))
script = binaries.apt_pkg_gdebi_script('', [[
'from GDebi.DebPackage import DebPackage',
'd = DebPackage(cache)',
- 'res = d.satisfyDependsStr("dpkg-source")',
+ 'res = d.satisfyDependsStr("dpkg-dev")',
]])
cmdl = ['python','-c',script]
whatp = what+'-dpkgsource'
- rc = testbed.execute(what, cmdl, script=script)
+ rc = testbed.execute(what, cmdl, script=script,
+ timeout=timeouts['install'])
if rc: badpkg('dpkg-source install failed, exit code %d' % rc)
work = TemporaryDir(what+'-build')
for stanza in stanzas:
for t in stanza[' tests']:
if 'no-build-needed' not in t.feature_names:
- build_needed('test %s' % t.name)
+ build_needed('test %s' % t.tname)
for d in t.depends:
if '@' in d:
build_needed('test %s '
- 'dependency %s' % (t.name,d))
+ 'dependency %s' % (t.tname,d))
debug_b('build not needed')
built = False
],[
'from GDebi.DebPackage import DebPackage',
'd = DebPackage(cache)',
- 'res = d.satisfyDependsStr("build-essential")',
+ 'res = d.satisfyDependsStr("'+
+ ','.join(build_essential)+
+ '")',
]])
cmdl = ['python','-c',script]
whatp = what+'-builddeps'
- rc = testbed.execute(what, cmdl, script=script)
+ rc = testbed.execute(what, cmdl, script=script,
+ timeout=timeouts['install'])
if rc: badpkg('build-depends install failed,'
' exit code %d' % rc)
work.read(True)+os.path.basename(result_pwd),
True)
if act.ah['dsc_tests']:
- act.tests_tree.read()
testbed.register_ephemeral(act.work)
testbed.register_ephemeral(act.tests_tree)
- if not built: return
+ if not built:
+ act.blamed = []
+ return
act.blamed = copy.copy(testbed.blamed)
binaries = Binaries()
for act in opts.actions:
- testbed.register_ephemeral(act.af)
+ if act.af is not None and not act.af.spec_tbp:
+ testbed.register_ephemeral(act.af)
binaries.reset()
control_override = None
act.binaries = []
if act.kind.endswith('tree') or act.kind == 'dsc':
control_override = None
+ if act.kind == 'instantiate':
+ pass
debug_a1('builds done.')
debug_a3('run_tests ...')
run_tests(stanzas, act.af)
control_override = None
+ if act.kind == 'instantiate':
+ testbed.prepare([])
debug_a1('tests done.')
def main():