2011-10-30 23:50:34 -03:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# APM automatic test suite
|
|
|
|
# Andrew Tridgell, October 2011
|
|
|
|
|
|
|
|
import pexpect, os, util, sys, shutil, arducopter
|
2011-11-09 08:45:12 -04:00
|
|
|
import optparse, fnmatch, time, glob, traceback
|
2011-10-30 23:50:34 -03:00
|
|
|
|
2011-11-01 08:31:01 -03:00
|
|
|
os.putenv('TMPDIR', util.reltopdir('tmp'))
|
2011-10-30 23:50:34 -03:00
|
|
|
|
|
|
|
def get_default_params(atype):
|
|
|
|
'''get default parameters'''
|
2011-11-07 07:55:21 -04:00
|
|
|
sil = util.start_SIL(atype, wipe=True)
|
2011-10-30 23:50:34 -03:00
|
|
|
mavproxy = util.start_MAVProxy_SIL(atype)
|
|
|
|
idx = mavproxy.expect(['Please Run Setup', 'Saved [0-9]+ parameters to (\S+)'])
|
|
|
|
if idx == 0:
|
|
|
|
# we need to restart it after eeprom erase
|
2011-11-09 00:45:18 -04:00
|
|
|
util.pexpect_close(mavproxy)
|
|
|
|
util.pexpect_close(sil)
|
2011-10-30 23:50:34 -03:00
|
|
|
sil = util.start_SIL(atype)
|
|
|
|
mavproxy = util.start_MAVProxy_SIL(atype)
|
|
|
|
idx = mavproxy.expect('Saved [0-9]+ parameters to (\S+)')
|
|
|
|
parmfile = mavproxy.match.group(1)
|
2011-11-01 08:31:01 -03:00
|
|
|
dest = util.reltopdir('../buildlogs/%s.defaults.txt' % atype)
|
2011-10-30 23:50:34 -03:00
|
|
|
shutil.copy(parmfile, dest)
|
2011-11-09 00:45:18 -04:00
|
|
|
util.pexpect_close(mavproxy)
|
|
|
|
util.pexpect_close(sil)
|
2011-10-30 23:50:34 -03:00
|
|
|
print("Saved defaults for %s to %s" % (atype, dest))
|
2011-11-09 01:15:53 -04:00
|
|
|
return True
|
2011-11-07 07:55:21 -04:00
|
|
|
|
|
|
|
def dump_logs(atype):
|
|
|
|
'''dump DataFlash logs'''
|
|
|
|
print("Dumping logs for %s" % atype)
|
|
|
|
sil = util.start_SIL(atype, CLI=True)
|
|
|
|
logfile = util.reltopdir('../buildlogs/%s.flashlog' % atype)
|
|
|
|
log = open(logfile, mode='w')
|
|
|
|
mavproxy = util.start_MAVProxy_SIL(atype, setup=True, logfile=log)
|
|
|
|
mavproxy.expect(']')
|
|
|
|
mavproxy.send("logs\n")
|
2011-11-07 08:56:59 -04:00
|
|
|
mavproxy.expect("logs enabled:")
|
|
|
|
mavproxy.expect("(\d+) logs")
|
|
|
|
numlogs = int(mavproxy.match.group(1))
|
2011-11-07 07:55:21 -04:00
|
|
|
mavproxy.expect("Log]")
|
2011-11-07 08:56:59 -04:00
|
|
|
for i in range(numlogs):
|
|
|
|
mavproxy.send("dump %u\n" % (i+1))
|
|
|
|
mavproxy.expect("logs enabled:")
|
|
|
|
mavproxy.expect("Log]")
|
2011-11-09 00:45:18 -04:00
|
|
|
util.pexpect_close(mavproxy)
|
|
|
|
util.pexpect_close(sil)
|
2011-11-07 07:55:21 -04:00
|
|
|
log.close()
|
|
|
|
print("Saved log for %s to %s" % (atype, logfile))
|
2011-11-09 01:15:53 -04:00
|
|
|
return True
|
2011-11-07 07:55:21 -04:00
|
|
|
|
2011-11-09 05:27:00 -04:00
|
|
|
def convert_gpx():
|
|
|
|
'''convert any mavlog files to GPX and KML'''
|
|
|
|
import glob
|
|
|
|
mavlog = glob.glob(util.reltopdir("../buildlogs/*.mavlog"))
|
|
|
|
for m in mavlog:
|
|
|
|
util.run_cmd(util.reltopdir("../pymavlink/examples/mavtogpx.py") + " --nofixcheck " + m)
|
|
|
|
gpx = m + '.gpx'
|
|
|
|
kml = m + '.kml'
|
|
|
|
util.run_cmd('gpsbabel -i gpx -f %s -o kml,units=m,floating=1 -F %s' % (gpx, kml), checkfail=False)
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2011-11-07 05:12:51 -04:00
|
|
|
def test_prerequesites():
|
|
|
|
'''check we have the right directories and tools to run tests'''
|
|
|
|
print("Testing prerequesites")
|
|
|
|
util.mkdir_p(util.reltopdir('../buildlogs'))
|
|
|
|
if not os.path.exists(util.reltopdir('../HILTest/hil_quad.py')):
|
|
|
|
print('''
|
|
|
|
You need to install HILTest in %s
|
|
|
|
|
|
|
|
You can get it from git://git.samba.org/tridge/UAV/HILTest.git
|
|
|
|
|
|
|
|
''' % util.reltopdir('../HILTest'))
|
2011-11-09 01:15:53 -04:00
|
|
|
return False
|
|
|
|
return True
|
2011-10-30 23:50:34 -03:00
|
|
|
|
|
|
|
|
|
|
|
############## main program #############
|
|
|
|
parser = optparse.OptionParser("autotest")
|
|
|
|
parser.add_option("--skip", type='string', default='', help='list of steps to skip (comma separated)')
|
|
|
|
parser.add_option("--list", action='store_true', default=False, help='list the available steps')
|
|
|
|
|
|
|
|
opts, args = parser.parse_args()
|
|
|
|
|
|
|
|
steps = [
|
2011-11-09 01:15:53 -04:00
|
|
|
'prerequesites',
|
|
|
|
'build1280.ArduPlane',
|
|
|
|
'build2560.ArduPlane',
|
2011-10-30 23:50:34 -03:00
|
|
|
'build.ArduPlane',
|
|
|
|
'defaults.ArduPlane',
|
2011-11-07 07:55:21 -04:00
|
|
|
'logs.ArduPlane',
|
2011-11-09 01:15:53 -04:00
|
|
|
'build1280.ArduCopter',
|
|
|
|
'build2560.ArduCopter',
|
2011-11-07 07:55:21 -04:00
|
|
|
'build.ArduCopter',
|
2011-10-30 23:50:34 -03:00
|
|
|
'defaults.ArduCopter',
|
2011-11-07 07:55:21 -04:00
|
|
|
'fly.ArduCopter',
|
|
|
|
'logs.ArduCopter',
|
2011-11-09 05:27:00 -04:00
|
|
|
'convertgpx',
|
2011-10-30 23:50:34 -03:00
|
|
|
]
|
|
|
|
|
|
|
|
skipsteps = opts.skip.split(',')
|
|
|
|
|
|
|
|
def skip_step(step):
|
|
|
|
'''see if a step should be skipped'''
|
|
|
|
for skip in skipsteps:
|
|
|
|
if fnmatch.fnmatch(step, skip):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2011-11-09 01:15:53 -04:00
|
|
|
def run_step(step):
|
|
|
|
'''run one step'''
|
|
|
|
if step == "prerequesites":
|
|
|
|
return test_prerequesites()
|
|
|
|
|
|
|
|
if step == 'build.ArduPlane':
|
|
|
|
return util.build_SIL('ArduPlane')
|
|
|
|
|
|
|
|
if step == 'build.ArduCopter':
|
|
|
|
return util.build_SIL('ArduCopter')
|
|
|
|
|
|
|
|
if step == 'build1280.ArduCopter':
|
|
|
|
return util.build_AVR('ArduCopter', board='mega')
|
|
|
|
|
|
|
|
if step == 'build2560.ArduCopter':
|
|
|
|
return util.build_AVR('ArduCopter', board='mega2560')
|
|
|
|
|
|
|
|
if step == 'build1280.ArduPlane':
|
|
|
|
return util.build_AVR('ArduPlane', board='mega')
|
|
|
|
|
|
|
|
if step == 'build2560.ArduPlane':
|
|
|
|
return util.build_AVR('ArduPlane', board='mega2560')
|
|
|
|
|
|
|
|
if step == 'defaults.ArduPlane':
|
|
|
|
return get_default_params('ArduPlane')
|
|
|
|
|
|
|
|
if step == 'defaults.ArduCopter':
|
|
|
|
return get_default_params('ArduCopter')
|
|
|
|
|
|
|
|
if step == 'logs.ArduPlane':
|
|
|
|
return dump_logs('ArduPlane')
|
|
|
|
|
|
|
|
if step == 'logs.ArduCopter':
|
|
|
|
return dump_logs('ArduCopter')
|
|
|
|
|
|
|
|
if step == 'fly.ArduCopter':
|
|
|
|
return arducopter.fly_ArduCopter()
|
|
|
|
|
2011-11-09 05:27:00 -04:00
|
|
|
if step == 'convertgpx':
|
|
|
|
return convert_gpx()
|
|
|
|
|
2011-11-09 01:15:53 -04:00
|
|
|
raise RuntimeError("Unknown step %s" % step)
|
|
|
|
|
2011-11-09 08:25:08 -04:00
|
|
|
class TestResult(object):
|
|
|
|
'''test result class'''
|
|
|
|
def __init__(self, name, result, elapsed):
|
|
|
|
self.name = name
|
|
|
|
self.result = result
|
|
|
|
self.elapsed = "%.1f" % elapsed
|
|
|
|
|
|
|
|
class TestFile(object):
|
|
|
|
'''test result file'''
|
|
|
|
def __init__(self, name, fname):
|
|
|
|
self.name = name
|
|
|
|
self.fname = fname
|
|
|
|
|
|
|
|
class TestResults(object):
|
|
|
|
'''test results class'''
|
|
|
|
def __init__(self):
|
|
|
|
self.date = time.asctime()
|
2011-11-09 08:43:25 -04:00
|
|
|
self.githash = util.loadfile(util.reltopdir('.git/refs/heads/master'))
|
2011-11-09 08:25:08 -04:00
|
|
|
self.tests = []
|
|
|
|
self.files = []
|
|
|
|
|
|
|
|
def add(self, name, result, elapsed):
|
|
|
|
'''add a result'''
|
|
|
|
self.tests.append(TestResult(name, result, elapsed))
|
|
|
|
|
|
|
|
def addfile(self, name, fname):
|
|
|
|
'''add a result file'''
|
|
|
|
self.files.append(TestFile(name, fname))
|
|
|
|
|
|
|
|
def addglob(self, name, pattern):
|
|
|
|
'''add a set of files'''
|
|
|
|
import glob
|
|
|
|
for f in glob.glob(util.reltopdir('../buildlogs/%s' % pattern)):
|
|
|
|
self.addfile(name, os.path.basename(f))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def write_webresults(results):
|
|
|
|
'''write webpage results'''
|
|
|
|
sys.path.insert(0, os.path.join(util.reltopdir("../pymavlink/generator")))
|
|
|
|
import mavtemplate
|
|
|
|
t = mavtemplate.MAVTemplate()
|
2011-11-09 09:23:46 -04:00
|
|
|
for h in glob.glob(util.reltopdir('Tools/autotest/web/*.html')):
|
|
|
|
html = util.loadfile(h)
|
|
|
|
f = open(util.reltopdir("../buildlogs/%s" % os.path.basename(h)), mode='w')
|
|
|
|
t.write(f, html, results)
|
|
|
|
f.close()
|
2011-11-09 09:31:50 -04:00
|
|
|
for f in glob.glob(util.reltopdir('Tools/autotest/web/*.png')):
|
|
|
|
shutil.copy(f, util.reltopdir('../buildlogs/%s' % os.path.basename(f)))
|
2011-11-09 08:25:08 -04:00
|
|
|
|
|
|
|
|
2011-11-09 01:15:53 -04:00
|
|
|
|
2011-11-09 00:45:18 -04:00
|
|
|
def run_tests(steps):
|
|
|
|
'''run a list of steps'''
|
|
|
|
|
2011-11-09 08:25:08 -04:00
|
|
|
results = TestResults()
|
|
|
|
|
2011-11-09 01:15:53 -04:00
|
|
|
passed = True
|
2011-11-09 02:16:20 -04:00
|
|
|
failed = []
|
2011-11-09 00:45:18 -04:00
|
|
|
for step in steps:
|
|
|
|
if skip_step(step):
|
|
|
|
continue
|
2011-11-09 01:15:53 -04:00
|
|
|
|
2011-11-09 08:25:08 -04:00
|
|
|
t1 = time.time()
|
2011-11-09 01:15:53 -04:00
|
|
|
print(">>>> RUNNING STEP: %s at %s" % (step, time.asctime()))
|
|
|
|
try:
|
|
|
|
if not run_step(step):
|
|
|
|
print(">>>> FAILED STEP: %s at %s" % (step, time.asctime()))
|
|
|
|
passed = False
|
2011-11-09 02:16:20 -04:00
|
|
|
failed.append(step)
|
2011-11-09 08:25:08 -04:00
|
|
|
results.add(step, "FAILED", time.time() - t1)
|
2011-11-09 01:15:53 -04:00
|
|
|
continue
|
|
|
|
except Exception, msg:
|
|
|
|
passed = False
|
2011-11-09 02:16:20 -04:00
|
|
|
failed.append(step)
|
2011-11-09 01:15:53 -04:00
|
|
|
print(">>>> FAILED STEP: %s at %s (%s)" % (step, time.asctime(), msg))
|
2011-11-09 08:43:25 -04:00
|
|
|
traceback.print_exc(file=sys.stdout)
|
2011-11-09 08:25:08 -04:00
|
|
|
results.add(step, "FAILED", time.time() - t1)
|
2011-11-09 08:43:25 -04:00
|
|
|
pass
|
2011-11-09 08:25:08 -04:00
|
|
|
results.add(step, "PASSED", time.time() - t1)
|
2011-11-09 01:15:53 -04:00
|
|
|
print(">>>> PASSED STEP: %s at %s" % (step, time.asctime()))
|
2011-11-09 02:16:20 -04:00
|
|
|
if not passed:
|
|
|
|
print("FAILED %u tests: %s" % (len(failed), failed))
|
2011-11-09 08:25:08 -04:00
|
|
|
|
|
|
|
results.addfile('Full Logs', 'autotest-output.txt')
|
|
|
|
results.addglob('DataFlash Log', '*.flashlog')
|
|
|
|
results.addglob("MAVLink log", '*.mavlog')
|
|
|
|
results.addglob("GPX track", '*.gpx')
|
|
|
|
results.addglob("KML track", '*.kml')
|
2011-11-09 09:17:31 -04:00
|
|
|
results.addfile('ArduPlane build log', 'ArduPlane.txt')
|
|
|
|
results.addfile('ArduPlane code size', 'ArduPlane.sizes.txt')
|
|
|
|
results.addfile('ArduPlane stack sizes', 'ArduPlane.framesizes.txt')
|
|
|
|
results.addfile('ArduCopter build log', 'ArduCopter.txt')
|
|
|
|
results.addfile('ArduCopter code size', 'ArduCopter.sizes.txt')
|
|
|
|
results.addfile('ArduCopter stack sizes', 'ArduCopter.framesizes.txt')
|
2011-11-09 08:25:08 -04:00
|
|
|
|
|
|
|
write_webresults(results)
|
|
|
|
|
2011-11-09 01:15:53 -04:00
|
|
|
return passed
|
2011-11-09 00:45:18 -04:00
|
|
|
|
2011-11-09 08:53:09 -04:00
|
|
|
|
|
|
|
lck = util.lock_file(util.reltopdir('../buildlogs/autotest.lck'))
|
|
|
|
if lck is None:
|
|
|
|
print("autotest is locked - exiting")
|
|
|
|
sys.exit(0)
|
|
|
|
|
2011-11-09 00:45:18 -04:00
|
|
|
try:
|
2011-11-09 01:15:53 -04:00
|
|
|
if not run_tests(steps):
|
|
|
|
sys.exit(1)
|
2011-11-09 00:45:18 -04:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
util.pexpect_close_all()
|
2011-11-09 01:15:53 -04:00
|
|
|
sys.exit(1)
|
2011-11-09 00:45:18 -04:00
|
|
|
except Exception:
|
|
|
|
# make sure we kill off any children
|
|
|
|
util.pexpect_close_all()
|
|
|
|
raise
|