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 (options, args) = parser.parse_args() 95 try: 96 args = roslaunch.rlutil.resolve_launch_arguments(args) 97 except roslaunch.core.RLException as e: 98 print(str(e), file=sys.stderr) 99 sys.exit(1) 100 101 # make sure all loggers are configured properly 102 logfile_name = configure_logging() 103 logger = logging.getLogger('rostest') 104 import roslaunch.core 105 roslaunch.core.add_printlog_handler(logger.info) 106 roslaunch.core.add_printerrlog_handler(logger.error) 107 108 logger.info('rostest starting with options %s, args %s'%(options, args)) 109 if len(args) == 0: 110 parser.error("You must supply a test file argument to rostest.") 111 if len(args) != 1: 112 parser.error("rostest only accepts a single test file") 113 114 # compute some common names we'll be using to generate test names and files 115 test_file = args[0] 116 if options.pkg_dir and options.package: 117 # rosbuild2: the build system knows what package and directory, so let it tell us, 118 # instead of shelling back out to rospack 119 pkg_dir, pkg = options.pkg_dir, options.package 120 else: 121 pkg = rospkg.get_package_name(test_file) 122 r = rospkg.RosPack() 123 pkg_dir = r.get_path(pkg) 124 125 outname = rostest_name_from_path(pkg_dir, test_file) 126 127 # #1140 128 if not os.path.isfile(test_file): 129 results_file = xmlResultsFile(pkg, outname, True) 130 write_bad_filename_failure(test_file, results_file, outname) 131 parser.error("test file is invalid. Generated failure case result file in %s"%results_file) 132 133 try: 134 testCase = rostest.runner.createUnitTest(pkg, test_file) 135 suite = unittest.TestLoader().loadTestsFromTestCase(testCase) 136 137 if options.text_mode: 138 rostest.runner.setTextMode(True) 139 result = unittest.TextTestRunner(verbosity=2).run(suite) 140 else: 141 is_rostest = True 142 results_file = xmlResultsFile(pkg, outname, is_rostest) 143 xml_runner = createXMLRunner(pkg, outname, \ 144 results_file=results_file, \ 145 is_rostest=is_rostest) 146 result = xml_runner.run(suite) 147 finally: 148 # really make sure that all of our processes have been killed 149 test_parents = rostest.runner.getRostestParents() 150 for r in test_parents: 151 logger.info("finally rostest parent tearDown [%s]", r) 152 r.tearDown() 153 del test_parents[:] 154 from roslaunch.pmon import pmon_shutdown 155 logger.info("calling pmon_shutdown") 156 pmon_shutdown() 157 logger.info("... done calling pmon_shutdown") 158 159 # print config errors after test has run so that we don't get caught up in .xml results 160 config = rostest.runner.getConfig() 161 if config: 162 if config.config_errors: 163 print("\n[ROSTEST WARNINGS]"+'-'*62+'\n', file=sys.stderr) 164 for err in config.config_errors: 165 print(" * %s"%err, file=sys.stderr) 166 print('') 167 168 # summary is worthless if textMode is on as we cannot scrape .xml results 169 subtest_results = rostest.runner.getResults() 170 if not options.text_mode: 171 printRostestSummary(result, subtest_results) 172 else: 173 print("WARNING: overall test result is not accurate when --text is enabled") 174 175 if logfile_name: 176 print("rostest log file is in %s"%logfile_name) 177 178 if not result.wasSuccessful(): 179 sys.exit(1) 180 elif subtest_results.num_errors or subtest_results.num_failures: 181 sys.exit(2)
182 183 if __name__ == '__main__': 184 rostestmain() 185