3 # adt-run <options>... --- <virt-server> [<virt-server-arg>...]
5 # invoke in toplevel of package (not necessarily built)
6 # with package installed
10 # 4 at least one test failed
11 # 8 no tests in this package
12 # 12 erroneous package
14 # 20 other unexpected failures including bad usage
26 from optparse import OptionParser
31 signal.signal(signal.SIGINT, signal.SIG_DFL) # undo stupid Python SIGINT thing
34 def __init__(q,ec,m): q.ec = ec; q.m = m
36 def bomb(m): raise Quit(20, "unexpected error: %s" % m)
37 def badpkg(m): raise Quit(12, "erroneous package: %s" % m)
41 if not opts.debug: return
42 print >>sys.stderr, 'atd-run: debug:', m
45 def __init__(p, tb, path, what, dir=False):
52 bomb("path %s specified as being in testbed but"
53 " not absolute: `%s'" % (what, p.p))
57 if p.dir: p.dirsfx = '/'
61 def append(p, suffix, what, dir=False):
62 return Path(p.tb, p.path() + suffix, what=what, dir=dir)
64 if p.tb: pfx = '/VIRT'
65 elif p.p[:1] == '/': pfx = '/HOST'
69 if not p.tb: return p.p
70 if p.local is not None: return p.local
72 p.local = tmpdir + '/tb.' + p.what
73 testbed.command('copyup', (p.path(), p.local + p.dirsfx))
78 usage = "%prog <options> -- <virt-server>..."
79 parser = OptionParser(usage=usage)
80 pa = parser.add_option
81 pe = parser.add_option
83 def cb_vserv(op,optstr,value,parser):
84 parser.values.vserver = list(parser.rargs)
87 def cb_path(op,optstr,value,parser, long,tb,dir):
88 name = long.replace('-','_')
89 parser.values.__dict__[name] = Path(tb, value, long, dir)
91 def pa_path(long, dir, help):
92 def papa_tb(long, ca, pahelp):
93 pa('', long, action='callback', callback=cb_path,
94 nargs=1, type='string', callback_args=ca,
95 help=(help % pahelp), metavar='PATH')
96 papa_tb('--'+long, (long, False, dir), 'host')
97 papa_tb('--'+long+'-tb',(long, True, dir), 'testbed')
99 pa_path('build-tree', True, 'use build tree from PATH on %s')
100 pa_path('control', False, 'read control file PATH on %s')
102 pa('-d', '--debug', action='store_true', dest='debug');
103 pa('','--user', type='string',
104 help='run tests as USER (needs root on testbed)')
106 class SpecialOption(optparse.Option): pass
107 vs_op = SpecialOption('','--VSERVER-DUMMY')
108 vs_op.action = 'callback'
112 vs_op.callback = cb_vserv
113 vs_op.callback_args = ( )
114 vs_op.callback_kwargs = { }
115 vs_op.help = 'introduces virtualisation server and args'
116 vs_op._short_opts = []
117 #vs_op._long_opts = ['--DUMMY']
118 vs_op._long_opts = ['---']
122 (opts,args) = parser.parse_args()
123 if not hasattr(opts,'vserver'):
124 parser.error('you must specifiy --- <virt-server>...')
126 if opts.build_tree is None:
127 opts.build_tree = Path(False, '.', 'build-tree', dir=True)
128 if opts.control is None:
129 opts.control = opts.build_tree.append(
130 'debian/tests/control', 'control')
139 tb.sp = subprocess.Popen(opts.vserver,
140 stdin=p, stdout=p, stderr=None)
144 if tb.sp is None: return
145 ec = tb.sp.returncode
152 tb.bomb('testbed gave exit status %d after quit' % ec)
154 if tb.scratch is not None: return
155 p = tb.commandr1('open')
156 tb.scratch = Path(True, p, 'tb-scratch', dir=True)
158 if tb.scratch is None: return
162 if tb.sp is not None:
166 if ec: print >>sys.stderr, ('adt-run: testbed failing,'
167 ' exit status %d' % ec)
169 raise Quit(16, 'testbed failed: %s' % m)
170 def send(tb, string):
173 print >>tb.sp.stdin, string
177 tb.bomb('cannot send to testbed: %s' %
178 formatexception_only(sys.last_type, sys.last_value))
179 def expect(tb, keyword, nresults=-1):
180 l = tb.sp.stdout.readline()
181 if not l: tb.bomb('unexpected eof from the testbed')
182 if not l.endswith('\n'): tb.bomb('unterminated line from the testbed')
186 if not ll: tb.bomb('unexpected whitespace-only line from the testbed')
188 if tb.lastsend is None:
189 tb.bomb("got banner `%s', expected `%s...'" %
192 tb.bomb("sent `%s', got `%s', expected `%s...'" %
193 (tb.lastsend, l, keyword))
195 if nresults >= 0 and len(ll) != nresults:
196 tb.bomb("sent `%s', got `%s' (%d result parameters),"
197 " expected %d result parameters" %
198 (string, l, len(ll), nresults))
200 def commandr(tb, cmd, nresults, args=()):
201 al = [cmd] + map(urllib.quote, args)
202 tb.send(string.join(al))
204 rl = map(urllib.unquote, ll)
206 def command(tb, cmd, args=()):
207 tb.commandr(cmd, 0, args)
208 def commandr1(tb, cmd, args=()):
209 rl = tb.commandr(cmd, 1, args)
214 control = file(opts.control.onhost(), 'r')
216 def badctrl(m): testbed.badpkg('tests/control line %d: %s' % (lno, m))
217 hmap = None # hmap[header_name][index] = (lno, value)
222 if hmap is None: continue
226 initre = regexp.compile('([A-Z][-0-9a-z]*)\s*\:\s*(.*)$')
228 l = control.readline()
231 if not l.endswith('\n'): badctrl('unterminated line')
232 if regexp.compile('\s*\#').match(l): continue
233 if not regexp.compile('\S').match(l): end_stanza(); continue
234 initmat = initre.match(l)
236 (hname, l) = initmat.groups()
237 hname = capwords(hname)
239 hmap = { ' lno' => lno }
240 if not haskey(hmap, hname): hmap[hname] = [ ]
241 hcurrent = hmap[hname]
242 elif regexp.compile('\s').match(l):
243 if not hcurrent: badctrl('unexpected continuation')
245 badctrl('syntax error')
246 hcurrent.append((lno, l))
249 def mergesplit(v): return string.join(v).split()
251 try: tests = stz['Tests']
253 report_unsupported_test('*',
254 'no Tests field (near control file line %d)'
257 tests = mergesplit(tests)
259 restrictions = mergesplit(stz.get('Restrictions',[]))
260 for rname in restrictions:
261 try: rr = globals()['Restriction_'+rname]
264 report_unsupported_test(t,
265 'unsupported restriction %s'
269 if rstr in ['needs-root
270 base['restrictions'] = restrictions
271 base.testsdir = oneonly(Tests-directory:
276 hmap[hname].append(l)
280 tb.badpkg('unterminated line in control')
283 def print_exception(ei, msgprefix=''):
284 if msgprefix: print >>sys.stderr, msgprefix
287 print >>sys.stderr, 'adt-run:', q.m
290 print >>sys.stderr, "adt-run: unexpected, exceptional, error:"
291 traceback.print_exc()
297 if tmpdir is not None:
298 rm_ec = subprocess.call(['rm','-rf','--',tmpdir])
299 if testbed is not None:
301 if rm_ec: bomb('rm -rf -- %s failed, code %d' % (tmpdir, ec))
303 print_exception(sys.exc_info(),
304 '\nadt-run: error cleaning up:\n')
312 tmpdir = tempfile.mkdtemp()
317 ec = print_exception(sys.exc_info(), '')