Package rostest

Source Code for Package rostest

  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: __init__.py 12086 2010-11-10 00:19:43Z kwc $ 
 34   
 35  from __future__ import with_statement 
 36   
 37  """ 
 38  Interface for using rostest from other Python code as well as running 
 39  Python unittests with additional reporting mechanisms and rosbuild 
 40  (CMake) integration. 
 41  """ 
 42   
 43  import sys 
 44   
 45  XML_OUTPUT_FLAG = '--gtest_output=xml:' #use gtest-compatible flag 
 46   
47 -def is_subscriber(topic, subscriber_id):
48 """ 49 Predicate to check whether or not master think subscriber_id 50 subscribes to topic. 51 @return: True if still register as a subscriber 52 @rtype: bool 53 """ 54 import roslib.scriptutil as scriptutil 55 return scriptutil.is_subscriber(topic, subscriber_id)
56
57 -def is_publisher(topic, publisher_id):
58 """ 59 Predicate to check whether or not master think publisher_id 60 publishes topic. 61 @return: True if still register as a publisher 62 @rtype: bool 63 """ 64 import roslib.scriptutil as scriptutil 65 return scriptutil.is_publisher(topic, publisher_id)
66
67 -def rosrun(package, test_name, test, sysargs=None):
68 """ 69 Run a rostest/unittest-based integration test. 70 71 @param package: name of package that test is in 72 @type package: str 73 @param test_name: name of test that is being run 74 @type test_name: str 75 @param test: test class 76 @type test: unittest.TestCase 77 @param sysargs: command-line args. If not specified, this defaults to sys.argv. rostest 78 will look for the --text and --gtest_output parameters 79 @type sysargs: list 80 """ 81 if sysargs is None: 82 # lazy-init sys args 83 import sys 84 sysargs = sys.argv 85 86 #parse sysargs 87 result_file = None 88 for arg in sysargs: 89 if arg.startswith(XML_OUTPUT_FLAG): 90 result_file = arg[len(XML_OUTPUT_FLAG):] 91 text_mode = '--text' in sysargs 92 coverage_mode = '--cov' in sysargs 93 if coverage_mode: 94 _start_coverage(package) 95 96 # lazy-import so that these don't affect coverage tests 97 from rostestutil import createXMLRunner, printSummary 98 import unittest 99 import rospy 100 101 suite = unittest.TestLoader().loadTestsFromTestCase(test) 102 if text_mode: 103 result = unittest.TextTestRunner(verbosity=2).run(suite) 104 else: 105 result = createXMLRunner(package, test_name, result_file).run(suite) 106 if coverage_mode: 107 _stop_coverage(package) 108 printSummary(result) 109 110 # shutdown any node resources in case test forgets to 111 rospy.signal_shutdown('test complete') 112 if not result.wasSuccessful(): 113 import sys 114 sys.exit(1)
115 116 # TODO: rename to rosrun -- migrating name to avoid confusion and enable easy xmlrunner use 117 run = rosrun 118
119 -def unitrun(package, test_name, test, sysargs=None, coverage_packages=None):
120 """ 121 Wrapper routine from running python unitttests with 122 JUnit-compatible XML output. This is meant for unittests that do 123 not not need a running ROS graph (i.e. offline tests only). 124 125 This enables JUnit-compatible test reporting so that 126 test results can be reported to higher-level tools. 127 128 @param package: name of ROS package that is running the test 129 @type package: str 130 @param coverage_packages: list of Python package to compute coverage results for. Defaults to package 131 @type coverage_packages: [str] 132 """ 133 if sysargs is None: 134 # lazy-init sys args 135 import sys 136 sysargs = sys.argv 137 138 import unittest 139 140 if coverage_packages is None: 141 coverage_packages = [package] 142 143 #parse sysargs 144 result_file = None 145 for arg in sysargs: 146 if arg.startswith(XML_OUTPUT_FLAG): 147 result_file = arg[len(XML_OUTPUT_FLAG):] 148 text_mode = '--text' in sysargs 149 150 coverage_mode = '--cov' in sysargs or '--covhtml' in sysargs 151 if coverage_mode: 152 _start_coverage(coverage_packages) 153 154 # lazy-import after coverage tests begin 155 from rostestutil import createXMLRunner, printSummary 156 157 suite = unittest.TestLoader().loadTestsFromTestCase(test) 158 if text_mode: 159 result = unittest.TextTestRunner(verbosity=2).run(suite) 160 else: 161 result = createXMLRunner(package, test_name, result_file).run(suite) 162 if coverage_mode: 163 cov_html_dir = 'covhtml' if '--covhtml' in sysargs else None 164 _stop_coverage(coverage_packages, html=cov_html_dir) 165 printSummary(result) 166 167 if not result.wasSuccessful(): 168 import sys 169 sys.exit(1)
170 171 # coverage instance 172 _cov = None
173 -def _start_coverage(packages):
174 global _cov 175 try: 176 import coverage 177 try: 178 _cov = coverage.coverage() 179 # load previous results as we need to accumulate 180 _cov.load() 181 _cov.start() 182 except coverage.CoverageException: 183 print >> sys.stderr, "WARNING: you have an older version of python-coverage that is not support. Please update to the version provided by 'easy_install coverage'" 184 except ImportError, e: 185 print >> sys.stderr, """WARNING: cannot import python-coverage, coverage tests will not run. 186 To install coverage, run 'easy_install coverage'""" 187 try: 188 # reload the module to get coverage 189 for package in packages: 190 if package in sys.modules: 191 reload(sys.modules[package]) 192 except ImportError, e: 193 print >> sys.stderr, "WARNING: cannot import '%s', will not generate coverage report"%package 194 return
195
196 -def _stop_coverage(packages, html=None):
197 """ 198 @param packages: list of packages to generate coverage reports for 199 @type packages: [str] 200 @param html: (optional) if not None, directory to generate html report to 201 @type html: str 202 """ 203 if _cov is None: 204 return 205 import sys, os 206 try: 207 _cov.stop() 208 # accumulate results 209 _cov.save() 210 211 # - update our own .coverage-modules file list for 212 # coverage-html tool. The reason we read and rewrite instead 213 # of append is that this does a uniqueness check to keep the 214 # file from growing unbounded 215 if os.path.exists('.coverage-modules'): 216 with open('.coverage-modules','r') as f: 217 all_packages = set([x for x in f.read().split('\n') if x.strip()] + packages) 218 else: 219 all_packages = set(packages) 220 with open('.coverage-modules','w') as f: 221 f.write('\n'.join(all_packages)+'\n') 222 223 try: 224 # list of all modules for html report 225 all_mods = [] 226 227 # iterate over packages to generate per-package console reports 228 for package in packages: 229 pkg = __import__(package) 230 m = [v for v in sys.modules.values() if v and v.__name__.startswith(package)] 231 all_mods.extend(m) 232 233 # generate overall report and per module analysis 234 _cov.report(m, show_missing=0) 235 for mod in m: 236 res = _cov.analysis(mod) 237 print "\n%s:\nMissing lines: %s"%(res[0], res[3]) 238 239 if html: 240 241 print "="*80+"\ngenerating html coverage report to %s\n"%html+"="*80 242 _cov.html_report(all_mods, directory=html) 243 except ImportError, e: 244 print >> sys.stderr, "WARNING: cannot import '%s', will not generate coverage report"%package 245 except ImportError, e: 246 print >> sys.stderr, """WARNING: cannot import python-coverage, coverage tests will not run. 247 To install coverage, run 'easy_install coverage'"""
248 249 250 #502: backwards compatibility for unbuilt rostest packages
251 -def rostestmain():
252 #NOTE: this is importing from rostest.rostest 253 from rostest.rostest_main import rostestmain as _main 254 _main()
255