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 with_statement 
 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 roslib.packages  
 48  import roslib.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.baretest 
 55  import rostest.runner 
 56   
 57  _NAME = 'rostest' 
 58   
59 -def configure_logging():
60 import socket 61 logfile_basename = 'rostest-%s-%s.log'%(socket.gethostname(), os.getpid()) 62 logfile_name = roslib.roslogging.configure_logging('rostest', filename=logfile_basename) 63 if logfile_name: 64 print "... logging to %s"%logfile_name 65 return logfile_name
66
67 -def write_bad_filename_failure(test_file, results_file, outname):
68 # similar to rostest-check-results 69 results_file_dir = os.path.dirname(results_file) 70 if not os.path.isdir(results_file_dir): 71 os.makedirs(results_file_dir) 72 with open(results_file, 'w') as f: 73 d = {'test': outname, 'test_file': test_file } 74 f.write("""<?xml version="1.0" encoding="UTF-8"?> 75 <testsuite tests="1" failures="1" time="1" errors="0" name="%(test)s"> 76 <testcase name="test_ran" status="run" time="1" classname="Results"> 77 <failure message="rostest file [%(test_file)s] does not exist" type=""/> 78 </testcase> 79 </testsuite>"""%d)
80
81 -def rostestmain():
82 import roslaunch.rlutil 83 84 # make sure all loggers are configured properly 85 logfile_name = configure_logging() 86 logger = logging.getLogger('rostest') 87 import roslaunch.core 88 roslaunch.core.add_printlog_handler(logger.info) 89 roslaunch.core.add_printerrlog_handler(logger.error) 90 91 from optparse import OptionParser 92 parser = OptionParser(usage="usage: %prog [options] [package] <filename>", prog=_NAME) 93 parser.add_option("-t", "--text", 94 action="store_true", dest="text_mode", default=False, 95 help="Run with stdout output instead of XML output") 96 parser.add_option("--bare", 97 action="store_true", dest="bare", default=False, 98 help="Run bare gtest-compatible executable instead of rostest") 99 parser.add_option("--bare-limit", metavar="TIME_LIMIT", 100 dest="bare_limit", default=60, 101 help="Set time limit for --bare executable") 102 parser.add_option("--bare-name", metavar="TEST_NAME", 103 dest="bare_name", default=None, 104 help="Test name for --bare executable") 105 parser.add_option("--pkgdir", metavar="PKG_DIR", 106 dest="pkg_dir", default=None, 107 help="package dir") 108 parser.add_option("--package", metavar="PACKAGE", 109 dest="package", default=None, 110 help="package") 111 (options, args) = parser.parse_args() 112 try: 113 if options.bare: 114 # no need to resolve arguments in this case 115 pass 116 else: 117 args = roslaunch.rlutil.resolve_launch_arguments(args) 118 except roslaunch.core.RLException, e: 119 print >> sys.stderr, str(e) 120 sys.exit(1) 121 122 logger.info('rostest starting with options %s, args %s'%(options, args)) 123 if len(args) == 0: 124 parser.error("You must supply a test file argument to rostest.") 125 if len(args) != 1 and not options.bare: 126 parser.error("rostest only accepts a single test file") 127 128 # compute some common names we'll be using to generate test names and files 129 test_file = args[0] 130 if options.pkg_dir and options.package: 131 # rosbuild2: the build system knows what package and directory, so let it tell us, 132 # instead of shelling back out to rospack 133 pkg_dir, pkg = options.pkg_dir, options.package 134 else: 135 pkg_dir, pkg = roslib.packages.get_dir_pkg(test_file) 136 137 outname = rostest_name_from_path(pkg_dir, test_file) 138 139 # #1140 140 if not options.bare and not os.path.isfile(test_file): 141 results_file = xmlResultsFile(pkg, outname, True) 142 write_bad_filename_failure(test_file, results_file, outname) 143 parser.error("test file is invalid. Generated failure case result file in %s"%results_file) 144 145 try: 146 if options.bare: 147 # TODO: does bare-retry make sense? 148 time_limit = float(options.bare_limit) if options.bare_limit else None 149 testCase = rostest.baretest.BareTestCase(test_file, args[1:], 150 rostest.runner.getResults(), retry=0, 151 time_limit=time_limit, test_name=options.bare_name, 152 package=pkg) 153 suite = unittest.TestSuite() 154 suite.addTest(testCase) 155 156 # override outname 157 if options.bare_name: 158 outname = options.bare_name 159 else: 160 testCase = rostest.runner.createUnitTest(pkg, test_file) 161 suite = unittest.TestLoader().loadTestsFromTestCase(testCase) 162 163 if options.text_mode: 164 rostest.runner.setTextMode(True) 165 result = unittest.TextTestRunner(verbosity=2).run(suite) 166 else: 167 is_rostest = True 168 results_file = xmlResultsFile(pkg, outname, is_rostest) 169 xml_runner = createXMLRunner(pkg, outname, \ 170 results_file=results_file, \ 171 is_rostest=is_rostest) 172 result = xml_runner.run(suite) 173 finally: 174 # really make sure that all of our processes have been killed 175 test_parents = rostest.runner.getRostestParents() 176 for r in test_parents: 177 logger.info("finally rostest parent tearDown [%s]", r) 178 r.tearDown() 179 del test_parents[:] 180 from roslaunch.pmon import pmon_shutdown 181 logger.info("calling pmon_shutdown") 182 pmon_shutdown() 183 logger.info("... done calling pmon_shutdown") 184 185 # print config errors after test has run so that we don't get caught up in .xml results 186 config = rostest.runner.getConfig() 187 if config: 188 if config.config_errors: 189 print >> sys.stderr, "\n[ROSTEST WARNINGS]"+'-'*62+'\n' 190 for err in config.config_errors: 191 print >> sys.stderr, " * %s"%err 192 print '' 193 194 # summary is worthless if textMode is on as we cannot scrape .xml results 195 subtest_results = rostest.runner.getResults() 196 if not options.text_mode: 197 printRostestSummary(result, subtest_results) 198 else: 199 print "WARNING: overall test result is not accurate when --text is enabled" 200 201 if logfile_name: 202 print "rostest log file is in %s"%logfile_name 203 204 if not result.wasSuccessful(): 205 sys.exit(1) 206 elif subtest_results.num_errors or subtest_results.num_failures: 207 sys.exit(2)
208 209 if __name__ == '__main__': 210 rostestmain() 211