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