PageRenderTime 80ms CodeModel.GetById 53ms RepoModel.GetById 1ms app.codeStats 0ms

/Tools/autotest/autotest.py

https://github.com/arktools/ardupilotone
Python | 315 lines | 294 code | 12 blank | 9 comment | 9 complexity | dc34f5da24a3d8b859a3f1a9d7c1297e MD5 | raw file
  1. #!/usr/bin/env python
  2. # APM automatic test suite
  3. # Andrew Tridgell, October 2011
  4. import pexpect, os, sys, shutil, atexit
  5. import optparse, fnmatch, time, glob, traceback
  6. sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), 'pysim'))
  7. sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), 'pymavlink'))
  8. import util, arducopter, arduplane
  9. os.environ['PYTHONUNBUFFERED'] = '1'
  10. os.putenv('TMPDIR', util.reltopdir('tmp'))
  11. def get_default_params(atype):
  12. '''get default parameters'''
  13. sil = util.start_SIL(atype, wipe=True)
  14. mavproxy = util.start_MAVProxy_SIL(atype)
  15. print("Dumping defaults")
  16. idx = mavproxy.expect(['Please Run Setup', 'Saved [0-9]+ parameters to (\S+)'])
  17. if idx == 0:
  18. # we need to restart it after eeprom erase
  19. util.pexpect_close(mavproxy)
  20. util.pexpect_close(sil)
  21. sil = util.start_SIL(atype)
  22. mavproxy = util.start_MAVProxy_SIL(atype)
  23. idx = mavproxy.expect('Saved [0-9]+ parameters to (\S+)')
  24. parmfile = mavproxy.match.group(1)
  25. dest = util.reltopdir('../buildlogs/%s.defaults.txt' % atype)
  26. shutil.copy(parmfile, dest)
  27. util.pexpect_close(mavproxy)
  28. util.pexpect_close(sil)
  29. print("Saved defaults for %s to %s" % (atype, dest))
  30. return True
  31. def dump_logs(atype):
  32. '''dump DataFlash logs'''
  33. print("Dumping logs for %s" % atype)
  34. sil = util.start_SIL(atype, CLI=True)
  35. logfile = util.reltopdir('../buildlogs/%s.flashlog' % atype)
  36. log = open(logfile, mode='w')
  37. mavproxy = util.start_MAVProxy_SIL(atype, setup=True, logfile=log)
  38. mavproxy.send('\n\n\n')
  39. print("navigating menus")
  40. mavproxy.expect(']')
  41. mavproxy.send("logs\n")
  42. mavproxy.expect("logs enabled:")
  43. lognums = []
  44. i = mavproxy.expect(["No logs", "(\d+) logs"])
  45. if i == 0:
  46. numlogs = 0
  47. else:
  48. numlogs = int(mavproxy.match.group(1))
  49. for i in range(numlogs):
  50. mavproxy.expect("Log (\d+),")
  51. lognums.append(int(mavproxy.match.group(1)))
  52. mavproxy.expect("Log]")
  53. for i in range(numlogs):
  54. print("Dumping log %u (i=%u)" % (lognums[i], i))
  55. mavproxy.send("dump %u\n" % lognums[i])
  56. mavproxy.expect("logs enabled:", timeout=120)
  57. mavproxy.expect("Log]")
  58. util.pexpect_close(mavproxy)
  59. util.pexpect_close(sil)
  60. log.close()
  61. print("Saved log for %s to %s" % (atype, logfile))
  62. return True
  63. def build_all():
  64. '''run the build_all.sh script'''
  65. print("Running build_all.sh")
  66. if util.run_cmd(util.reltopdir('Tools/scripts/build_all.sh'), dir=util.reltopdir('.')) != 0:
  67. print("Failed build_all.sh")
  68. return False
  69. return True
  70. def convert_gpx():
  71. '''convert any mavlog files to GPX and KML'''
  72. import glob
  73. mavlog = glob.glob(util.reltopdir("../buildlogs/*.mavlog"))
  74. for m in mavlog:
  75. util.run_cmd(util.reltopdir("../pymavlink/examples/mavtogpx.py") + " --nofixcheck " + m)
  76. gpx = m + '.gpx'
  77. kml = m + '.kml'
  78. util.run_cmd('gpsbabel -i gpx -f %s -o kml,units=m,floating=1,extrude=1 -F %s' % (gpx, kml), checkfail=False)
  79. util.run_cmd('zip %s.kmz %s.kml' % (m, m), checkfail=False)
  80. return True
  81. def test_prerequesites():
  82. '''check we have the right directories and tools to run tests'''
  83. print("Testing prerequesites")
  84. util.mkdir_p(util.reltopdir('../buildlogs'))
  85. if not os.path.exists(util.reltopdir('../HILTest/hil_quad.py')):
  86. print('''
  87. You need to install HILTest in %s
  88. You can get it from git://git.samba.org/tridge/UAV/HILTest.git
  89. ''' % util.reltopdir('../HILTest'))
  90. return False
  91. return True
  92. ############## main program #############
  93. parser = optparse.OptionParser("autotest")
  94. parser.add_option("--skip", type='string', default='', help='list of steps to skip (comma separated)')
  95. parser.add_option("--list", action='store_true', default=False, help='list the available steps')
  96. parser.add_option("--viewerip", default=None, help='IP address to send MAVLink and fg packets to')
  97. parser.add_option("--experimental", default=False, action='store_true', help='enable experimental tests')
  98. opts, args = parser.parse_args()
  99. steps = [
  100. 'prerequesites',
  101. 'build1280.ArduPlane',
  102. 'build2560.ArduPlane',
  103. 'build.All',
  104. 'build.ArduPlane',
  105. 'defaults.ArduPlane',
  106. 'fly.ArduPlane',
  107. 'logs.ArduPlane',
  108. 'build1280.ArduCopter',
  109. 'build2560.ArduCopter',
  110. 'build.ArduCopter',
  111. 'defaults.ArduCopter',
  112. 'fly.ArduCopter',
  113. 'logs.ArduCopter',
  114. 'convertgpx',
  115. ]
  116. skipsteps = opts.skip.split(',')
  117. def skip_step(step):
  118. '''see if a step should be skipped'''
  119. for skip in skipsteps:
  120. if fnmatch.fnmatch(step, skip):
  121. return True
  122. return False
  123. def run_step(step):
  124. '''run one step'''
  125. if step == "prerequesites":
  126. return test_prerequesites()
  127. if step == 'build.ArduPlane':
  128. return util.build_SIL('ArduPlane')
  129. if step == 'build.ArduCopter':
  130. return util.build_SIL('ArduCopter')
  131. if step == 'build1280.ArduCopter':
  132. return util.build_AVR('ArduCopter', board='mega')
  133. if step == 'build2560.ArduCopter':
  134. return util.build_AVR('ArduCopter', board='mega2560')
  135. if step == 'build1280.ArduPlane':
  136. return util.build_AVR('ArduPlane', board='mega')
  137. if step == 'build2560.ArduPlane':
  138. return util.build_AVR('ArduPlane', board='mega2560')
  139. if step == 'defaults.ArduPlane':
  140. return get_default_params('ArduPlane')
  141. if step == 'defaults.ArduCopter':
  142. return get_default_params('ArduCopter')
  143. if step == 'logs.ArduPlane':
  144. return dump_logs('ArduPlane')
  145. if step == 'logs.ArduCopter':
  146. return dump_logs('ArduCopter')
  147. if step == 'fly.ArduCopter':
  148. return arducopter.fly_ArduCopter(viewerip=opts.viewerip)
  149. if step == 'fly.ArduPlane':
  150. return arduplane.fly_ArduPlane(viewerip=opts.viewerip)
  151. if step == 'build.All':
  152. return build_all()
  153. if step == 'convertgpx':
  154. return convert_gpx()
  155. raise RuntimeError("Unknown step %s" % step)
  156. class TestResult(object):
  157. '''test result class'''
  158. def __init__(self, name, result, elapsed):
  159. self.name = name
  160. self.result = result
  161. self.elapsed = "%.1f" % elapsed
  162. class TestFile(object):
  163. '''test result file'''
  164. def __init__(self, name, fname):
  165. self.name = name
  166. self.fname = fname
  167. class TestResults(object):
  168. '''test results class'''
  169. def __init__(self):
  170. self.date = time.asctime()
  171. self.githash = util.run_cmd('git rev-parse HEAD', output=True, dir=util.reltopdir('.')).strip()
  172. self.tests = []
  173. self.files = []
  174. def add(self, name, result, elapsed):
  175. '''add a result'''
  176. self.tests.append(TestResult(name, result, elapsed))
  177. def addfile(self, name, fname):
  178. '''add a result file'''
  179. self.files.append(TestFile(name, fname))
  180. def addglob(self, name, pattern):
  181. '''add a set of files'''
  182. import glob
  183. for f in glob.glob(util.reltopdir('../buildlogs/%s' % pattern)):
  184. self.addfile(name, os.path.basename(f))
  185. def write_webresults(results):
  186. '''write webpage results'''
  187. sys.path.insert(0, os.path.join(util.reltopdir("../pymavlink/generator")))
  188. import mavtemplate
  189. t = mavtemplate.MAVTemplate()
  190. for h in glob.glob(util.reltopdir('Tools/autotest/web/*.html')):
  191. html = util.loadfile(h)
  192. f = open(util.reltopdir("../buildlogs/%s" % os.path.basename(h)), mode='w')
  193. t.write(f, html, results)
  194. f.close()
  195. for f in glob.glob(util.reltopdir('Tools/autotest/web/*.png')):
  196. shutil.copy(f, util.reltopdir('../buildlogs/%s' % os.path.basename(f)))
  197. def run_tests(steps):
  198. '''run a list of steps'''
  199. results = TestResults()
  200. passed = True
  201. failed = []
  202. for step in steps:
  203. util.pexpect_close_all()
  204. if skip_step(step):
  205. continue
  206. t1 = time.time()
  207. print(">>>> RUNNING STEP: %s at %s" % (step, time.asctime()))
  208. try:
  209. if not run_step(step):
  210. print(">>>> FAILED STEP: %s at %s" % (step, time.asctime()))
  211. passed = False
  212. failed.append(step)
  213. results.add(step, '<span class="failed-text">FAILED</span>', time.time() - t1)
  214. continue
  215. except Exception, msg:
  216. passed = False
  217. failed.append(step)
  218. print(">>>> FAILED STEP: %s at %s (%s)" % (step, time.asctime(), msg))
  219. traceback.print_exc(file=sys.stdout)
  220. results.add(step, '<span class="failed-text">FAILED</span>', time.time() - t1)
  221. continue
  222. results.add(step, '<span class="passed-text">PASSED</span>', time.time() - t1)
  223. print(">>>> PASSED STEP: %s at %s" % (step, time.asctime()))
  224. if not passed:
  225. print("FAILED %u tests: %s" % (len(failed), failed))
  226. util.pexpect_close_all()
  227. results.addglob("Google Earth track", '*.kmz')
  228. results.addfile('Full Logs', 'autotest-output.txt')
  229. results.addglob('DataFlash Log', '*.flashlog')
  230. results.addglob("MAVLink log", '*.mavlog')
  231. results.addglob("GPX track", '*.gpx')
  232. results.addfile('ArduPlane build log', 'ArduPlane.txt')
  233. results.addfile('ArduPlane code size', 'ArduPlane.sizes.txt')
  234. results.addfile('ArduPlane stack sizes', 'ArduPlane.framesizes.txt')
  235. results.addfile('ArduPlane defaults', 'ArduPlane.defaults.txt')
  236. results.addfile('ArduCopter build log', 'ArduCopter.txt')
  237. results.addfile('ArduCopter code size', 'ArduCopter.sizes.txt')
  238. results.addfile('ArduCopter stack sizes', 'ArduCopter.framesizes.txt')
  239. results.addfile('ArduCopter defaults', 'ArduCopter.defaults.txt')
  240. write_webresults(results)
  241. return passed
  242. lck = util.lock_file(util.reltopdir('../buildlogs/autotest.lck'))
  243. if lck is None:
  244. print("autotest is locked - exiting")
  245. sys.exit(0)
  246. atexit.register(util.pexpect_close_all)
  247. try:
  248. if not run_tests(steps):
  249. sys.exit(1)
  250. except KeyboardInterrupt:
  251. util.pexpect_close_all()
  252. sys.exit(1)
  253. except Exception:
  254. # make sure we kill off any children
  255. util.pexpect_close_all()
  256. raise