Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/Tools/autotest/autotest.py
Views: 1798
#!/usr/bin/env python31"""2ArduPilot automatic test suite.34Andrew Tridgell, October 201156AP_FLAKE8_CLEAN7"""8from __future__ import print_function9import atexit10import fnmatch11import copy12import glob13import optparse14import os15import re16import shutil17import signal18import subprocess19import sys20import time21import traceback2223import blimp24import rover25import arducopter26import arduplane27import ardusub28import antennatracker29import quadplane30import balancebot31import sailboat32import helicopter3334import examples35from pysim import util36from pymavlink.generator import mavtemplate3738from vehicle_test_suite import Test3940tester = None414243def buildlogs_dirpath():44"""Return BUILDLOGS directory path."""45return os.getenv("BUILDLOGS", util.reltopdir("../buildlogs"))464748def buildlogs_path(path):49"""Return a string representing path in the buildlogs directory."""50bits = [buildlogs_dirpath()]51if isinstance(path, list):52bits.extend(path)53else:54bits.append(path)55return os.path.join(*bits)565758def build_all_filepath():59"""Get build_all.sh path."""60return util.reltopdir('Tools/scripts/build_all.sh')616263def build_all():64"""Run the build_all.sh script."""65print("Running build_all.sh")66if util.run_cmd(build_all_filepath(), directory=util.reltopdir('.')) != 0:67print("Failed build_all.sh")68return False69return True707172def build_binaries():73"""Run the build_binaries.py script."""74print("Running build_binaries.py")7576# copy the script (and various libraries used by the script) as it77# changes git branch, which can change the script while running78for thing in [79"board_list.py",80"build_binaries_history.py",81"build_binaries.py",82"build_sizes/build_sizes.py",83"generate_manifest.py",84"gen_stable.py",85]:86orig = util.reltopdir('Tools/scripts/%s' % thing)87copy = util.reltopdir('./%s' % os.path.basename(thing))88shutil.copy2(orig, copy)8990if util.run_cmd("./build_binaries.py", directory=util.reltopdir('.')) != 0:91print("Failed build_binaries.py")92return False93return True949596def build_examples(**kwargs):97"""Build examples."""98for target in 'Pixhawk1', 'navio', 'linux':99print("Running build.examples for %s" % target)100try:101util.build_examples(target, **kwargs)102except Exception as e:103print("Failed build_examples on board=%s" % target)104print(str(e))105return False106107return True108109110def build_unit_tests(**kwargs):111"""Build tests."""112for target in ['linux', 'sitl']:113print("Running build.unit_tests for %s" % target)114try:115util.build_tests(target, **kwargs)116except Exception as e:117print("Failed build.unit_tests on board=%s" % target)118print(str(e))119return False120121return True122123124def run_unit_test(test):125"""Run unit test file."""126print("Running (%s)" % test)127subprocess.check_call([test])128129130def run_unit_tests():131"""Run all unit tests files."""132success = True133fail_list = []134for target in ['linux', 'sitl']:135binary_dir = util.reltopdir(os.path.join('build',136target,137'tests',138))139tests = glob.glob("%s/*" % binary_dir)140for test in tests:141try:142run_unit_test(test)143except subprocess.CalledProcessError:144print("Exception running (%s)" % test)145fail_list.append(target + '/' + os.path.basename(test))146success = False147148print("Failing tests:")149for failure in fail_list:150print(" %s" % failure)151return success152153154def run_clang_scan_build():155"""Run Clang Scan-build utility."""156if util.run_cmd("scan-build python waf configure",157directory=util.reltopdir('.')) != 0:158print("Failed scan-build-configure")159return False160161if util.run_cmd("scan-build python waf clean",162directory=util.reltopdir('.')) != 0:163print("Failed scan-build-clean")164return False165166if util.run_cmd("scan-build python waf build",167directory=util.reltopdir('.')) != 0:168print("Failed scan-build-build")169return False170171return True172173174def param_parse_filepath():175"""Get param_parse.py script path."""176return util.reltopdir('Tools/autotest/param_metadata/param_parse.py')177178179def all_vehicles():180"""Get all vehicles name."""181return ('ArduPlane',182'ArduCopter',183'Rover',184'AntennaTracker',185'ArduSub',186'Blimp',187'AP_Periph',188)189190191def build_parameters():192"""Run the param_parse.py script."""193print("Running param_parse.py")194for vehicle in all_vehicles():195if util.run_cmd([param_parse_filepath(), '--vehicle', vehicle],196directory=util.reltopdir('.')) != 0:197print("Failed param_parse.py (%s)" % vehicle)198return False199return True200201202def mavtogpx_filepath():203"""Get mavtogpx script path."""204return util.reltopdir("modules/mavlink/pymavlink/tools/mavtogpx.py")205206207def convert_gpx():208"""Convert any tlog files to GPX and KML."""209mavlog = glob.glob(buildlogs_path("*.tlog"))210passed = True211for m in mavlog:212util.run_cmd(mavtogpx_filepath() + " --nofixcheck " + m)213gpx = m + '.gpx'214kml = m + '.kml'215try:216util.run_cmd('gpsbabel -i gpx -f %s '217'-o kml,units=m,floating=1,extrude=1 -F %s' %218(gpx, kml))219except subprocess.CalledProcessError:220passed = False221try:222util.run_cmd('zip %s.kmz %s.kml' % (m, m))223except subprocess.CalledProcessError:224passed = False225util.run_cmd("mavflightview.py --imagefile=%s.png %s" % (m, m))226return passed227228229def test_prerequisites():230"""Check we have the right directories and tools to run tests."""231print("Testing prerequisites")232util.mkdir_p(buildlogs_dirpath())233return True234235236def alarm_handler(signum, frame):237"""Handle test timeout."""238global results, opts, tester239try:240print("Alarm handler called")241if tester is not None:242if tester.rc_thread is not None:243tester.rc_thread_should_quit = True244tester.rc_thread.join()245tester.rc_thread = None246results.add('TIMEOUT',247'<span class="failed-text">FAILED</span>',248opts.timeout)249util.pexpect_close_all()250convert_gpx()251write_fullresults()252os.killpg(0, signal.SIGKILL)253except Exception:254pass255sys.exit(1)256257258def should_run_step(step):259"""See if a step should be skipped."""260for skip in skipsteps:261if fnmatch.fnmatch(step.lower(), skip.lower()):262return False263return True264265266__bin_names = {267"Copter": "arducopter",268"CopterTests1a": "arducopter",269"CopterTests1b": "arducopter",270"CopterTests1c": "arducopter",271"CopterTests1d": "arducopter",272"CopterTests1e": "arducopter",273274"CopterTests2a": "arducopter",275"CopterTests2b": "arducopter",276277"Plane": "arduplane",278"PlaneTests1a": "arduplane",279"PlaneTests1b": "arduplane",280281"Rover": "ardurover",282"Tracker": "antennatracker",283"Helicopter": "arducopter-heli",284"QuadPlane": "arduplane",285"Sub": "ardusub",286"Blimp": "blimp",287"BalanceBot": "ardurover",288"Sailboat": "ardurover",289"SITLPeriphUniversal": ("sitl_periph_universal", "AP_Periph"),290"SITLPeriphBattMon": ("sitl_periph_battmon", "AP_Periph"),291"CAN": "arducopter",292"BattCAN": "arducopter",293}294295296def binary_path(step, debug=False):297"""Get vehicle binary path."""298try:299vehicle = step.split(".")[1]300except Exception:301return None302303if vehicle not in __bin_names:304# cope with builds that don't have a specific binary305return None306307try:308(config_name, binary_name) = __bin_names[vehicle]309except ValueError:310config_name = "sitl"311binary_name = __bin_names[vehicle]312313binary = util.reltopdir(os.path.join('build',314config_name,315'bin',316binary_name))317if not os.path.exists(binary):318if os.path.exists(binary + ".exe"):319binary += ".exe"320else:321raise ValueError("Binary (%s) does not exist" % (binary,))322323return binary324325326def split_specific_test_step(step):327"""Extract test from argument."""328print('step=%s' % str(step))329m = re.match("((fly|drive|dive|test)[.][^.]+)[.](.*)", step)330if m is None:331return None332return ((m.group(1), m.group(3)))333334335def find_specific_test_to_run(step):336"""Find test to run in argument."""337t = split_specific_test_step(step)338if t is None:339return None340(testname, test) = t341return "%s.%s" % (testname, test)342343344tester_class_map = {345"test.Blimp": blimp.AutoTestBlimp,346"test.Copter": arducopter.AutoTestCopter,347"test.CopterTests1a": arducopter.AutoTestCopterTests1a, # 8m43s348"test.CopterTests1b": arducopter.AutoTestCopterTests1b, # 8m5s349"test.CopterTests1c": arducopter.AutoTestCopterTests1c, # 5m17s350"test.CopterTests1d": arducopter.AutoTestCopterTests1d, # 8m20s351"test.CopterTests1e": arducopter.AutoTestCopterTests1e, # 8m32s352"test.CopterTests2a": arducopter.AutoTestCopterTests2a, # 8m23s353"test.CopterTests2b": arducopter.AutoTestCopterTests2b, # 8m18s354"test.Plane": arduplane.AutoTestPlane,355"test.PlaneTests1a": arduplane.AutoTestPlaneTests1a,356"test.PlaneTests1b": arduplane.AutoTestPlaneTests1b,357"test.QuadPlane": quadplane.AutoTestQuadPlane,358"test.Rover": rover.AutoTestRover,359"test.BalanceBot": balancebot.AutoTestBalanceBot,360"test.Sailboat": sailboat.AutoTestSailboat,361"test.Helicopter": helicopter.AutoTestHelicopter,362"test.Sub": ardusub.AutoTestSub,363"test.Tracker": antennatracker.AutoTestTracker,364"test.CAN": arducopter.AutoTestCAN,365"test.BattCAN": arducopter.AutoTestBattCAN,366}367368supplementary_test_binary_map = {369"test.CAN": ["sitl_periph_universal:AP_Periph:0:Tools/autotest/default_params/periph.parm,Tools/autotest/default_params/quad-periph.parm", # noqa: E501370"sitl_periph_universal:AP_Periph:1:Tools/autotest/default_params/periph.parm"],371"test.BattCAN": [372"sitl_periph_battmon:AP_Periph:0:Tools/autotest/default_params/periph-battmon.parm,Tools/autotest/default_params/quad-periph.parm", # noqa: E501373],374}375376377def run_specific_test(step, *args, **kwargs):378"""Run a specific test."""379t = split_specific_test_step(step)380if t is None:381return []382(testname, test) = t383384tester_class = tester_class_map[testname]385global tester386tester = tester_class(*args, **kwargs)387388# print("Got %s" % str(tester))389for a in tester.tests():390if not isinstance(a, Test):391a = Test(a)392print("Got %s" % (a.name))393if a.name == test:394return tester.autotest(tests=[a], allow_skips=False, step_name=step), tester395print("Failed to find test %s on %s" % (test, testname))396sys.exit(1)397398399def run_step(step):400"""Run one step."""401# remove old logs402util.run_cmd('/bin/rm -f logs/*.BIN logs/LASTLOG.TXT')403404if step == "prerequisites":405return test_prerequisites()406407build_opts = {408"j": opts.j,409"debug": opts.debug,410"clean": not opts.no_clean,411"configure": not opts.no_configure,412"math_check_indexes": opts.math_check_indexes,413"ekf_single": opts.ekf_single,414"postype_single": opts.postype_single,415"extra_configure_args": opts.waf_configure_args,416"coverage": opts.coverage,417"force_32bit" : opts.force_32bit,418"ubsan" : opts.ubsan,419"ubsan_abort" : opts.ubsan_abort,420"num_aux_imus" : opts.num_aux_imus,421"dronecan_tests" : opts.dronecan_tests,422}423424if opts.Werror:425build_opts['extra_configure_args'].append("--Werror")426427vehicle_binary = None428board = "sitl"429if step == 'build.Plane':430vehicle_binary = 'bin/arduplane'431432if step == 'build.Rover':433vehicle_binary = 'bin/ardurover'434435if step == 'build.Copter':436vehicle_binary = 'bin/arducopter'437438if step == 'build.Blimp':439vehicle_binary = 'bin/blimp'440441if step == 'build.Tracker':442vehicle_binary = 'bin/antennatracker'443444if step == 'build.Helicopter':445vehicle_binary = 'bin/arducopter-heli'446447if step == 'build.Sub':448vehicle_binary = 'bin/ardusub'449450if step == 'build.SITLPeriphUniversal':451vehicle_binary = 'bin/AP_Periph'452board = 'sitl_periph_universal'453454if step == 'build.SITLPeriphBattMon':455vehicle_binary = 'bin/AP_Periph'456board = 'sitl_periph_battmon'457458if step == 'build.Replay':459return util.build_replay(board='SITL')460461if vehicle_binary is not None:462try:463binary = binary_path(step, debug=opts.debug)464os.unlink(binary)465except (FileNotFoundError, ValueError):466pass467return util.build_SITL(468vehicle_binary,469board=board,470**build_opts471)472473binary = binary_path(step, debug=opts.debug)474475# see if we need any supplementary binaries476supplementary_binaries = []477for k in supplementary_test_binary_map.keys():478if step.startswith(k):479# this test needs to use supplementary binaries480for supplementary_test_binary in supplementary_test_binary_map[k]:481a = supplementary_test_binary.split(':')482if len(a) != 4:483raise ValueError("Bad supplementary_test_binary %s" % supplementary_test_binary)484config_name = a[0]485binary_name = a[1]486instance_num = int(a[2])487param_file = a[3].split(",")488bin_path = util.reltopdir(os.path.join('build', config_name, 'bin', binary_name))489customisation = '-I {}'.format(instance_num)490sup_binary = {"binary" : bin_path,491"customisation" : customisation,492"param_file" : param_file}493supplementary_binaries.append(sup_binary)494# we are running in conjunction with a supplementary app495# can't have speedup496opts.speedup = 1.0497break498499fly_opts = {500"viewerip": opts.viewerip,501"use_map": opts.map,502"valgrind": opts.valgrind,503"callgrind": opts.callgrind,504"gdb": opts.gdb,505"gdb_no_tui": opts.gdb_no_tui,506"lldb": opts.lldb,507"gdbserver": opts.gdbserver,508"breakpoints": opts.breakpoint,509"disable_breakpoints": opts.disable_breakpoints,510"_show_test_timings": opts.show_test_timings,511"force_ahrs_type": opts.force_ahrs_type,512"num_aux_imus" : opts.num_aux_imus,513"replay": opts.replay,514"logs_dir": buildlogs_dirpath(),515"sup_binaries": supplementary_binaries,516"reset_after_every_test": opts.reset_after_every_test,517"build_opts": copy.copy(build_opts),518"generate_junit": opts.junit,519"enable_fgview": opts.enable_fgview,520}521if opts.speedup is not None:522fly_opts["speedup"] = opts.speedup523524# handle "test.Copter" etc:525if step in tester_class_map:526# create an instance of the tester class:527global tester528tester = tester_class_map[step](binary, **fly_opts)529# run the test and return its result and the tester itself530return tester.autotest(None, step_name=step), tester531532# handle "test.Copter.CPUFailsafe" etc:533specific_test_to_run = find_specific_test_to_run(step)534if specific_test_to_run is not None:535return run_specific_test(specific_test_to_run, binary, **fly_opts)536537if step == 'build.All':538return build_all()539540if step == 'build.Binaries':541return build_binaries()542543if step == 'build.examples':544return build_examples(**build_opts)545546if step == 'run.examples':547return examples.run_examples(debug=opts.debug, valgrind=False, gdb=False)548549if step == 'build.Parameters':550return build_parameters()551552if step == 'convertgpx':553return convert_gpx()554555if step == 'build.unit_tests':556return build_unit_tests(**build_opts)557558if step == 'run.unit_tests':559return run_unit_tests()560561if step == 'clang-scan-build':562return run_clang_scan_build()563564raise RuntimeError("Unknown step %s" % step)565566567class TestResult(object):568"""Test result class."""569570def __init__(self, name, result, elapsed):571"""Init test result class."""572self.name = name573self.result = result574self.elapsed = "%.1f" % elapsed575576577class TestFile(object):578"""Test result file."""579580def __init__(self, name, fname):581"""Init test result file."""582self.name = name583self.fname = fname584585586class TestResults(object):587"""Test results class."""588589def __init__(self):590"""Init test results class."""591self.date = time.asctime()592self.githash = util.get_git_hash()593self.tests = []594self.files = []595self.images = []596597def add(self, name, result, elapsed):598"""Add a result."""599self.tests.append(TestResult(name, result, elapsed))600601def addfile(self, name, fname):602"""Add a result file."""603self.files.append(TestFile(name, fname))604605def addimage(self, name, fname):606"""Add a result image."""607self.images.append(TestFile(name, fname))608609def addglob(self, name, pattern):610"""Add a set of files."""611for f in glob.glob(buildlogs_path(pattern)):612self.addfile(name, os.path.basename(f))613614def addglobimage(self, name, pattern):615"""Add a set of images."""616for f in glob.glob(buildlogs_path(pattern)):617self.addimage(name, os.path.basename(f))618619def generate_badge(self):620"""Get the badge template, populates and saves the result to buildlogs path."""621passed_tests = len([t for t in self.tests if "PASSED" in t.result])622total_tests = len(self.tests)623badge_color = "#4c1" if passed_tests == total_tests else "#e05d44"624625badge_text = "{0}/{1}".format(passed_tests, total_tests)626# Text length so it is not stretched by svg627text_length = len(badge_text) * 70628629# Load template file630template_path = 'Tools/autotest/web/autotest-badge-template.svg'631with open(util.reltopdir(template_path), "r") as f:632template = f.read()633634# Add our results to the template635badge = template.format(color=badge_color,636text=badge_text,637text_length=text_length)638with open(buildlogs_path("autotest-badge.svg"), "w") as f:639f.write(badge)640641642def copy_tree(f, t, dirs_exist_ok=False):643shutil.copytree(f, t, dirs_exist_ok=dirs_exist_ok)644645646def write_webresults(results_to_write):647"""Write webpage results."""648t = mavtemplate.MAVTemplate()649for h in glob.glob(util.reltopdir('Tools/autotest/web/*.html')):650html = util.loadfile(h)651f = open(buildlogs_path(os.path.basename(h)), mode='w')652t.write(f, html, results_to_write)653f.close()654for f in glob.glob(util.reltopdir('Tools/autotest/web/*.png')):655shutil.copy(f, buildlogs_path(os.path.basename(f)))656copy_tree(util.reltopdir("Tools/autotest/web/css"), buildlogs_path("css"), dirs_exist_ok=True)657results_to_write.generate_badge()658659660def write_fullresults():661"""Write out full results set."""662global results663results.addglob("Google Earth track", '*.kmz')664results.addfile('Full Logs', 'autotest-output.txt')665results.addglob('DataFlash Log', '*-log.bin')666results.addglob("MAVLink log", '*.tlog')667results.addglob("GPX track", '*.gpx')668669# results common to all vehicles:670vehicle_files = [671('{vehicle} core', '{vehicle}.core'),672('{vehicle} ELF', '{vehicle}.elf'),673]674vehicle_globs = [('{vehicle} log', '{vehicle}-*.BIN'), ]675for vehicle in all_vehicles():676subs = {'vehicle': vehicle}677for vehicle_file in vehicle_files:678description = vehicle_file[0].format(**subs)679filename = vehicle_file[1].format(**subs)680results.addfile(description, filename)681for vehicle_glob in vehicle_globs:682description = vehicle_glob[0].format(**subs)683glob = vehicle_glob[1].format(**subs)684results.addglob(description, glob)685686results.addglob("CopterAVC log", 'CopterAVC-*.BIN')687results.addfile("CopterAVC core", 'CopterAVC.core')688689results.addglob('APM:Libraries documentation', 'docs/libraries/index.html')690results.addglob('APM:Plane documentation', 'docs/ArduPlane/index.html')691results.addglob('APM:Copter documentation', 'docs/ArduCopter/index.html')692results.addglob('APM:Rover documentation', 'docs/Rover/index.html')693results.addglob('APM:Sub documentation', 'docs/ArduSub/index.html')694results.addglob('APM:Blimp documentation', 'docs/Blimp/index.html')695results.addglobimage("Flight Track", '*.png')696697write_webresults(results)698699700def run_tests(steps):701"""Run a list of steps."""702global results703704corefiles = glob.glob("core*")705corefiles.extend(glob.glob("ap-*.core"))706if corefiles:707print('Removing corefiles: %s' % str(corefiles))708for f in corefiles:709os.unlink(f)710711diagnostic_files = []712for p in "dumpstack.sh_*", "dumpcore.sh_*", "autotest-*tlog":713diagnostic_files.extend(glob.glob(p))714if diagnostic_files:715print('Removing diagnostic files: %s' % str(diagnostic_files))716for f in diagnostic_files:717os.unlink(f)718719passed = True720failed = []721failed_testinstances = dict()722for step in steps:723util.pexpect_close_all()724725t1 = time.time()726print(">>>> RUNNING STEP: %s at %s" % (step, time.asctime()))727try:728success = run_step(step)729testinstance = None730if isinstance(success, tuple):731(success, testinstance) = success732if success:733results.add(step, '<span class="passed-text">PASSED</span>',734time.time() - t1)735print(">>>> PASSED STEP: %s at %s" % (step, time.asctime()))736else:737print(">>>> FAILED STEP: %s at %s" % (step, time.asctime()))738passed = False739failed.append(step)740if testinstance is not None:741if failed_testinstances.get(step) is None:742failed_testinstances[step] = []743failed_testinstances[step].append(testinstance)744results.add(step, '<span class="failed-text">FAILED</span>',745time.time() - t1)746except Exception as msg:747passed = False748failed.append(step)749print(">>>> FAILED STEP: %s at %s (%s)" %750(step, time.asctime(), msg))751traceback.print_exc(file=sys.stdout)752results.add(step,753'<span class="failed-text">FAILED</span>',754time.time() - t1)755756global tester757if tester is not None and tester.rc_thread is not None:758if passed:759print("BAD: RC Thread still alive after run_step")760tester.rc_thread_should_quit = True761tester.rc_thread.join()762tester.rc_thread = None763764if not passed:765keys = failed_testinstances.keys()766if len(keys):767print("Failure Summary:")768for key in keys:769print(" %s:" % key)770for testinstance in failed_testinstances[key]:771for failure in testinstance.fail_list:772print(" " + str(failure))773774print("FAILED %u tests: %s" % (len(failed), failed))775776util.pexpect_close_all()777778write_fullresults()779780return passed781782783vehicle_list = ['Sub', 'Copter', 'Plane', 'Tracker', 'Rover', 'QuadPlane', 'BalanceBot', 'Helicopter', 'Sailboat', 'Blimp']784785786def list_subtests():787"""Print the list of tests and tests description for each vehicle."""788for vehicle in sorted(vehicle_list):789tester_class = tester_class_map["test.%s" % vehicle]790tester = tester_class("/bin/true", None)791subtests = tester.tests()792sorted_list = []793for subtest in subtests:794if str(type(subtest)) == "<class 'method'>":795subtest = Test(subtest)796sorted_list.append([subtest.name, subtest.description])797sorted_list.sort()798799print("%s:" % vehicle)800for subtest in sorted_list:801print(" %s: %s" % (subtest[0], subtest[1]))802print("")803804805def list_subtests_for_vehicle(vehicle_type):806"""Print the list of tests for a vehicle."""807# Check that we aren't in a sub test808if "Test" in vehicle_type:809vehicle_type = re.findall('[A-Z][a-z0-9]*', vehicle_type)[0]810if vehicle_type in vehicle_list:811tester_class = tester_class_map["test.%s" % vehicle_type]812tester = tester_class("/bin/true", None)813subtests = tester.tests()814sorted_list = []815for subtest in subtests:816if not isinstance(subtest, Test):817subtest = Test(subtest)818sorted_list.append([subtest.name, subtest.description])819sorted_list.sort()820for subtest in sorted_list:821print("%s " % subtest[0], end='')822print("") # needed to clear the trailing %823824825if __name__ == "__main__":826''' main program '''827os.environ['PYTHONUNBUFFERED'] = '1'828829if sys.platform != "darwin":830os.putenv('TMPDIR', util.reltopdir('tmp'))831832class MyOptionParser(optparse.OptionParser):833"""Custom option parse class."""834835def format_epilog(self, formatter):836"""Retun customized option parser epilog."""837return self.epilog838839parser = MyOptionParser(840"autotest", epilog=""841"e.g. autotest.py build.Rover test.Rover # test Rover\n"842"e.g. autotest.py build.Rover test.Rover build.Plane test.Plane # test Rover and Plane\n"843"e.g. autotest.py --debug --valgrind build.Rover test.Rover # test Rover under Valgrind\n"844"e.g. autotest.py --debug --gdb build.Tracker test.Tracker # run Tracker under gdb\n"845"e.g. autotest.py --debug --gdb build.Sub test.Sub.DiveManual # do specific Sub test\n"846)847parser.add_option("--autotest-server",848action='store_true',849default=False,850help='Run in autotest-server mode; dangerous!')851parser.add_option("--skip",852type='string',853default='',854help='list of steps to skip (comma separated)')855parser.add_option("--list",856action='store_true',857default=False,858help='list the available steps')859parser.add_option("--list-subtests",860action='store_true',861default=False,862help='list available subtests e.g. test.Copter')863parser.add_option("--viewerip",864default=None,865help='IP address to send MAVLink and fg packets to')866parser.add_option("--enable-fgview",867action='store_true',868help="Enable FlightGear output")869parser.add_option("--map",870action='store_true',871default=False,872help='show map')873parser.add_option("--experimental",874default=False,875action='store_true',876help='enable experimental tests')877parser.add_option("--timeout",878default=None,879type='int',880help='maximum runtime in seconds')881parser.add_option("--show-test-timings",882action="store_true",883default=False,884help="show how long each test took to run")885parser.add_option("--validate-parameters",886action="store_true",887default=False,888help="validate vehicle parameter files")889parser.add_option("--Werror",890action='store_true',891default=False,892help='configure with --Werror')893parser.add_option("--junit",894default=False,895action='store_true',896help='Generate Junit XML tests report')897898group_build = optparse.OptionGroup(parser, "Build options")899group_build.add_option("--no-configure",900default=False,901action='store_true',902help='do not configure before building',903dest="no_configure")904group_build.add_option("", "--waf-configure-args",905action="append",906dest="waf_configure_args",907type="string",908default=[],909help="extra arguments passed to waf in configure")910group_build.add_option("-j", default=None, type='int', help='build CPUs')911group_build.add_option("--no-clean",912default=False,913action='store_true',914help='do not clean before building',915dest="no_clean")916group_build.add_option("--debug",917default=None,918action='store_true',919help='make built SITL binaries debug binaries')920group_build.add_option("--no-debug",921default=None,922action='store_true',923help='do not make built SITL binaries debug binaries')924group_build.add_option("--coverage",925default=False,926action='store_true',927help='make built binaries coverage binaries')928group_build.add_option("--enable-math-check-indexes",929default=False,930action="store_true",931dest="math_check_indexes",932help="enable checking of math indexes")933group_build.add_option("--postype-single",934default=False,935action="store_true",936dest="postype_single",937help="force single precision copter position controller")938group_build.add_option("--ekf-single",939default=False,940action="store_true",941dest="ekf_single",942help="force single precision EKF")943group_build.add_option("--force-32bit",944default=False,945action='store_true',946dest="force_32bit",947help="compile sitl using 32-bit")948group_build.add_option("", "--ubsan",949default=False,950action='store_true',951dest="ubsan",952help="compile sitl with undefined behaviour sanitiser")953group_build.add_option("", "--ubsan-abort",954default=False,955action='store_true',956dest="ubsan_abort",957help="compile sitl with undefined behaviour sanitiser and abort on error")958group_build.add_option("--num-aux-imus",959dest="num_aux_imus",960default=0,961type='int',962help='number of auxiliary IMUs to simulate')963group_build.add_option("--enable-dronecan-tests",964default=False,965action='store_true',966dest="dronecan_tests",967help="enable dronecan tests")968parser.add_option_group(group_build)969970group_sim = optparse.OptionGroup(parser, "Simulation options")971group_sim.add_option("--speedup",972default=None,973type='int',974help='speedup to run the simulations at')975group_sim.add_option("--valgrind",976default=False,977action='store_true',978help='run ArduPilot binaries under valgrind')979group_sim.add_option("", "--callgrind",980action='store_true',981default=False,982help="enable valgrind for performance analysis (slow!!)")983group_sim.add_option("--gdb",984default=False,985action='store_true',986help='run ArduPilot binaries under gdb')987group_sim.add_option("--gdb-no-tui",988default=False,989action='store_true',990help='when running under GDB do NOT start in TUI mode')991group_sim.add_option("--gdbserver",992default=False,993action='store_true',994help='run ArduPilot binaries under gdbserver')995group_sim.add_option("--lldb",996default=False,997action='store_true',998help='run ArduPilot binaries under lldb')999group_sim.add_option("-B", "--breakpoint",1000type='string',1001action="append",1002default=[],1003help="add a breakpoint at given location in debugger")1004group_sim.add_option("--disable-breakpoints",1005default=False,1006action='store_true',1007help="disable all breakpoints before starting")1008group_sim.add_option("", "--force-ahrs-type",1009dest="force_ahrs_type",1010default=None,1011help="force a specific AHRS type (e.g. 10 for SITL-ekf")1012group_sim.add_option("", "--replay",1013action='store_true',1014help="enable replay logging for tests")1015parser.add_option_group(group_sim)10161017group_completion = optparse.OptionGroup(parser, "Completion helpers")1018group_completion.add_option("--list-vehicles",1019action='store_true',1020default=False,1021help='list available vehicles')1022group_completion.add_option("--list-vehicles-test",1023action='store_true',1024default=False,1025help='list available vehicle tester')1026group_completion.add_option("--list-subtests-for-vehicle",1027type='string',1028default="",1029help='list available subtests for a vehicle e.g Copter')1030group_completion.add_option("--reset-after-every-test",1031action='store_true',1032default=False,1033help='reset everything after every test run')1034parser.add_option_group(group_completion)10351036opts, args = parser.parse_args()10371038# canonicalise on opts.debug:1039if opts.debug is None and opts.no_debug is None:1040# default is to create debug SITL binaries1041opts.debug = True1042elif opts.debug is not None and opts.no_debug is not None:1043if opts.debug == opts.no_debug:1044raise ValueError("no_debug != !debug")1045elif opts.no_debug is not None:1046opts.debug = not opts.no_debug10471048if opts.timeout is None:1049opts.timeout = 54001050# adjust if we're running in a regime which may slow us down e.g. Valgrind1051if opts.valgrind:1052opts.timeout *= 101053elif opts.callgrind:1054opts.timeout *= 101055elif opts.gdb:1056opts.timeout = None10571058steps = [1059'prerequisites',1060'build.Binaries',1061'build.All',1062'build.Parameters',10631064'build.Replay',10651066'build.unit_tests',1067'run.unit_tests',1068'build.examples',1069'run.examples',10701071'build.Plane',1072'test.Plane',1073'test.QuadPlane',10741075'build.Rover',1076'test.Rover',1077'test.BalanceBot',1078'test.Sailboat',10791080'build.Copter',1081'test.Copter',10821083'build.Helicopter',1084'test.Helicopter',10851086'build.Tracker',1087'test.Tracker',10881089'build.Sub',1090'test.Sub',10911092'build.Blimp',1093'test.Blimp',10941095'build.SITLPeriphUniversal',1096'test.CAN',10971098'build.SITLPeriphBattMon',1099'test.BattCAN',11001101# convertgps disabled as it takes 5 hours1102# 'convertgpx',1103]11041105moresteps = [1106'test.CopterTests1a',1107'test.CopterTests1b',1108'test.CopterTests1c',1109'test.CopterTests1d',1110'test.CopterTests1e',11111112'test.CopterTests2a',1113'test.CopterTests2b',11141115'test.PlaneTests1a',1116'test.PlaneTests1b',11171118'clang-scan-build',1119]11201121# canonicalise the step names. This allows1122# backwards-compatability from the hodge-podge1123# fly.ArduCopter/drive.APMrover2 to the more common test.Copter1124# test.Rover1125step_mapping = {1126"build.ArduPlane": "build.Plane",1127"build.ArduCopter": "build.Copter",1128"build.APMrover2": "build.Rover",1129"build.ArduSub": "build.Sub",1130"build.AntennaTracker": "build.Tracker",1131"fly.ArduCopter": "test.Copter",1132"fly.ArduPlane": "test.Plane",1133"fly.QuadPlane": "test.QuadPlane",1134"dive.ArduSub": "test.Sub",1135"drive.APMrover2": "test.Rover",1136"drive.BalanceBot": "test.BalanceBot",1137"drive.balancebot": "test.BalanceBot",1138"fly.CopterAVC": "test.Helicopter",1139"test.AntennaTracker": "test.Tracker",1140"fly.ArduCopterTests1a": "test.CopterTests1a",1141"fly.ArduCopterTests1b": "test.CopterTests1b",1142"fly.ArduCopterTests1c": "test.CopterTests1c",1143"fly.ArduCopterTests1d": "test.CopterTests1d",1144"fly.ArduCopterTests1e": "test.CopterTests1e",11451146"fly.ArduCopterTests2a": "test.CopterTests2a",1147"fly.ArduCopterTests2b": "test.CopterTests2b",11481149}11501151# form up a list of bits NOT to run, mapping from old step names1152# to new step names as appropriate.1153skipsteps = opts.skip.split(',')1154new_skipsteps = []1155for skipstep in skipsteps:1156if skipstep in step_mapping:1157new_skipsteps.append(step_mapping[skipstep])1158else:1159new_skipsteps.append(skipstep)1160skipsteps = new_skipsteps11611162# ensure we catch timeouts1163signal.signal(signal.SIGALRM, alarm_handler)1164if opts.timeout is not None:1165signal.alarm(opts.timeout)11661167if opts.list:1168for step in steps:1169print(step)1170sys.exit(0)11711172if opts.list_subtests:1173list_subtests()1174sys.exit(0)11751176if opts.list_subtests_for_vehicle:1177list_subtests_for_vehicle(opts.list_subtests_for_vehicle)1178sys.exit(0)11791180if opts.list_vehicles_test:1181print(' '.join(__bin_names.keys()))1182sys.exit(0)11831184if opts.list_vehicles:1185print(' '.join(vehicle_list))1186sys.exit(0)11871188util.mkdir_p(buildlogs_dirpath())11891190lckfile = buildlogs_path('autotest.lck')1191print("lckfile=%s" % repr(lckfile))1192lck = util.lock_file(lckfile)11931194if lck is None:1195print("autotest is locked - exiting. lckfile=(%s)" % (lckfile,))1196sys.exit(0)11971198atexit.register(util.pexpect_close_all)11991200# provide backwards-compatability from (e.g.) drive.APMrover2 -> test.Rover1201newargs = []1202for arg in args:1203for _from, to in step_mapping.items():1204arg = re.sub("^%s" % _from, to, arg)1205newargs.append(arg)1206args = newargs12071208if len(args) == 0 and not opts.autotest_server:1209print("Steps must be supplied; try --list and/or --list-subtests or --help")1210sys.exit(1)12111212if len(args) > 0:1213# allow a wildcard list of steps1214matched = []1215for a in args:1216matches = [step for step in steps1217if fnmatch.fnmatch(step.lower(), a.lower())]1218x = find_specific_test_to_run(a)1219if x is not None:1220matches.append(x)12211222if a in moresteps:1223matches.append(a)12241225if not len(matches):1226print("No steps matched {}".format(a))1227sys.exit(1)1228matched.extend(matches)1229steps = matched12301231# skip steps according to --skip option:1232steps_to_run = [s for s in steps if should_run_step(s)]12331234results = TestResults()12351236try:1237if not run_tests(steps_to_run):1238sys.exit(1)1239except KeyboardInterrupt:1240print("KeyboardInterrupt caught; closing pexpect connections")1241util.pexpect_close_all()1242raise1243except Exception:1244# make sure we kill off any children1245util.pexpect_close_all()1246raise124712481249