Package rostest :: Module rostest_main

Source Code for Module rostest.rostest_main

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2008, Willow Garage, Inc. 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Willow Garage, Inc. nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32  # 
 33  # Revision $Id$ 
 34   
 35  from __future__ import print_function 
 36   
 37  # NOTE: this has not survived the many refactorings and roslaunch changes well. There are too many ugly globals and bad 
 38  # code organizational choices at this point, but it's not a high priority to cleanup. 
 39   
 40  import os 
 41  import sys 
 42  import time 
 43  import unittest 
 44  import logging 
 45   
 46  import roslaunch 
 47  import rospkg 
 48  import rosgraph.roslogging 
 49   
 50  from rostest.rostestutil import createXMLRunner, printRostestSummary, \ 
 51      xmlResultsFile, rostest_name_from_path 
 52  from rostest.rostest_parent import ROSTestLaunchParent 
 53   
 54  import rostest.runner 
 55   
 56  _NAME = 'rostest' 
 57   
58 -def configure_logging():
59 import socket 60 logfile_basename = 'rostest-%s-%s.log'%(socket.gethostname(), os.getpid()) 61 logfile_name = rosgraph.roslogging.configure_logging('rostest', filename=logfile_basename) 62 if logfile_name: 63 print("... logging to %s"%logfile_name) 64 return logfile_name
65
66 -def write_bad_filename_failure(test_file, results_file, outname):
67 # similar to rostest-check-results 68 results_file_dir = os.path.dirname(results_file) 69 if not os.path.isdir(results_file_dir): 70 os.makedirs(results_file_dir) 71 with open(results_file, 'w') as f: 72 d = {'test': outname, 'test_file': test_file } 73 f.write("""<?xml version="1.0" encoding="UTF-8"?> 74 <testsuite tests="1" failures="1" time="1" errors="0" name="%(test)s"> 75 <testcase name="test_ran" status="run" time="1" classname="Results"> 76 <failure message="rostest file [%(test_file)s] does not exist" type=""/> 77 </testcase> 78 </testsuite>"""%d)
79
80 -def rostestmain():
81 import roslaunch.rlutil 82 83 from optparse import OptionParser 84 parser = OptionParser(usage="usage: %prog [options] [package] <filename>", prog=_NAME) 85 parser.add_option("-t", "--text", 86 action="store_true", dest="text_mode", default=False, 87 help="Run with stdout output instead of XML output") 88 parser.add_option("--pkgdir", metavar="PKG_DIR", 89 dest="pkg_dir", default=None, 90 help="package dir") 91 parser.add_option("--package", metavar="PACKAGE", 92 dest="package", default=None, 93 help="package") 94 parser.add_option("--results-filename", metavar="RESULTS_FILENAME", 95 dest="results_filename", default=None, 96 help="results_filename") 97 (options, args) = parser.parse_args() 98 try: 99 args = roslaunch.rlutil.resolve_launch_arguments(args) 100 except roslaunch.core.RLException as e: 101 print(str(e), file=sys.stderr) 102 sys.exit(1) 103 104 # make sure all loggers are configured properly 105 logfile_name = configure_logging() 106 logger = logging.getLogger('rostest') 107 import roslaunch.core 108 roslaunch.core.add_printlog_handler(logger.info) 109 roslaunch.core.add_printerrlog_handler(logger.error) 110 111 logger.info('rostest starting with options %s, args %s'%(options, args)) 112 if len(args) == 0: 113 parser.error("You must supply a test file argument to rostest.") 114 if len(args) != 1: 115 parser.error("rostest only accepts a single test file") 116 117 # compute some common names we'll be using to generate test names and files 118 test_file = args[0] 119 if options.pkg_dir and options.package: 120 # rosbuild2: the build system knows what package and directory, so let it tell us, 121 # instead of shelling back out to rospack 122 pkg_dir, pkg = options.pkg_dir, options.package 123 else: 124 pkg = rospkg.get_package_name(test_file) 125 r = rospkg.RosPack() 126 pkg_dir = r.get_path(pkg) 127 128 if options.results_filename: 129 outname = options.results_filename 130 if '.' in outname: 131 outname = outname[:outname.rfind('.')] 132 else: 133 outname = rostest_name_from_path(pkg_dir, test_file) 134 135 # #1140 136 if not os.path.isfile(test_file): 137 results_file = xmlResultsFile(pkg, outname, True) 138 write_bad_filename_failure(test_file, results_file, outname) 139 parser.error("test file is invalid. Generated failure case result file in %s"%results_file) 140 141 try: 142 testCase = rostest.runner.createUnitTest(pkg, test_file) 143 suite = unittest.TestLoader().loadTestsFromTestCase(testCase) 144 145 if options.text_mode: 146 rostest.runner.setTextMode(True) 147 result = unittest.TextTestRunner(verbosity=2).run(suite) 148 else: 149 is_rostest = True 150 results_file = xmlResultsFile(pkg, outname, is_rostest) 151 xml_runner = createXMLRunner(pkg, outname, \ 152 results_file=results_file, \ 153 is_rostest=is_rostest) 154 result = xml_runner.run(suite) 155 finally: 156 # really make sure that all of our processes have been killed 157 test_parents = rostest.runner.getRostestParents() 158 for r in test_parents: 159 logger.info("finally rostest parent tearDown [%s]", r) 160 r.tearDown() 161 del test_parents[:] 162 from roslaunch.pmon import pmon_shutdown 163 logger.info("calling pmon_shutdown") 164 pmon_shutdown() 165 logger.info("... done calling pmon_shutdown") 166 167 # print config errors after test has run so that we don't get caught up in .xml results 168 config = rostest.runner.getConfig() 169 if config: 170 if config.config_errors: 171 print("\n[ROSTEST WARNINGS]"+'-'*62+'\n', file=sys.stderr) 172 for err in config.config_errors: 173 print(" * %s"%err, file=sys.stderr) 174 print('') 175 176 # summary is worthless if textMode is on as we cannot scrape .xml results 177 subtest_results = rostest.runner.getResults() 178 if not options.text_mode: 179 printRostestSummary(result, subtest_results) 180 else: 181 print("WARNING: overall test result is not accurate when --text is enabled") 182 183 if logfile_name: 184 print("rostest log file is in %s"%logfile_name) 185 186 if not result.wasSuccessful(): 187 sys.exit(1) 188 elif subtest_results.num_errors or subtest_results.num_failures: 189 sys.exit(2)
190 191 if __name__ == '__main__': 192 rostestmain() 193