$search
00001 # Software License Agreement (BSD License) 00002 # 00003 # Copyright (c) 2008, Willow Garage, Inc. 00004 # All rights reserved. 00005 # 00006 # Redistribution and use in source and binary forms, with or without 00007 # modification, are permitted provided that the following conditions 00008 # are met: 00009 # 00010 # * Redistributions of source code must retain the above copyright 00011 # notice, this list of conditions and the following disclaimer. 00012 # * Redistributions in binary form must reproduce the above 00013 # copyright notice, this list of conditions and the following 00014 # disclaimer in the documentation and/or other materials provided 00015 # with the distribution. 00016 # * Neither the name of Willow Garage, Inc. nor the names of its 00017 # contributors may be used to endorse or promote products derived 00018 # from this software without specific prior written permission. 00019 # 00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00024 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00031 # POSSIBILITY OF SUCH DAMAGE. 00032 # 00033 # Revision $Id: testSlave.py 1100 2008-05-29 20:23:54Z sfkwc $ 00034 00035 import os 00036 import sys 00037 import string 00038 import time 00039 import xmlrpclib 00040 00041 import rospy 00042 import roslib.rosenv 00043 import roslib.names 00044 from test_ros.rosclient import * 00045 00046 NODE_INTEGRATION_NAME = "node_integration_test" 00047 00048 _name = None 00049 ## set_node_name() must be called prior to the unit test so that the test harness knows its 00050 ## ROS name. 00051 def set_node_name(name): 00052 global _name 00053 _name = name 00054 00055 # Have to try as hard as possible to not use rospy code in testing rospy code, so this is 00056 # a reimplementation of the caller ID spec so that NodeApiTestCase knows its name 00057 ## reimplementation of caller ID spec separately from rospy 00058 def get_caller_id(): 00059 if _name is None: 00060 raise Exception("set_node_name has not been called yet") 00061 ros_ns = os.environ.get(roslib.rosenv.ROS_NAMESPACE, roslib.names.GLOBALNS) 00062 return roslib.names.ns_join(ros_ns, _name) 00063 00064 class _MasterTestCase(TestRosClient): 00065 00066 def __init__(self, *args): 00067 super(_MasterTestCase, self).__init__(*args) 00068 self.ns = os.environ.get(roslib.rosenv.ROS_NAMESPACE, roslib.names.GLOBALNS) 00069 self.caller_id = get_caller_id() 00070 00071 def setUp(self): 00072 super(_MasterTestCase, self).setUp() 00073 self.master_uri = os.environ.get(roslib.rosenv.ROS_MASTER_URI, None) 00074 self._checkUri(self.master_uri) 00075 self.master = xmlrpclib.ServerProxy(self.master_uri) 00076 00077 ## validates a URI as being http(s) 00078 def _checkUri(self, uri): 00079 import urlparse 00080 parsed = urlparse.urlparse(uri) 00081 self.assert_(parsed[0] in ['http', 'https'], 'protocol [%s] in [%s] invalid'%(parsed[0], uri)) 00082 self.assert_(parsed[1], 'host missing [%s]'%uri) 00083 if not sys.version.startswith('2.4'): #check not available on py24 00084 self.assert_(parsed.port, 'port missing/invalid [%s]'%uri) 00085 00086 ## Expects a single test node to be running with name 'test_node' and subscribed to 'test_string' 00087 class MasterApiTestCase(_MasterTestCase): 00088 00089 ## validate master.getMasterUri(caller_id) 00090 def _testGetMasterUri(self): 00091 # test with bad arity 00092 self.apiError(self.master.getMasterUri()) 00093 # test success 00094 uri = self.apiSuccess(self.master.getMasterUri(self.caller_id)) 00095 self._checkUri(uri) 00096 00097 # make sure we agree on ports 00098 import urlparse 00099 parsed = urlparse.urlparse(uri) 00100 parsed2 = urlparse.urlparse(self.master_uri) 00101 00102 self.assertEquals(parsed.port, parsed2.port, "expected ports do not match") 00103 00104 ## validate master.getPid(caller_id) 00105 def _testGetPid(self): 00106 # test with bad arity 00107 self.apiError(self.master.getPid()) 00108 # test success 00109 pid = self.apiSuccess(self.master.getPid(self.caller_id)) 00110 self.assert_(pid > 0) 00111 00112 ## validate master.getUri(caller_id) 00113 def _testGetUri(self): 00114 # test with bad arity 00115 self.apiError(self.master.getUri()) 00116 # test success 00117 uri = self.apiSuccess(self.master.getUri(self.caller_id)) 00118 self.assert_(type(uri) == str) 00119 00120 ## common test subroutine of both register and unregister tests. registers the common test cases 00121 def _subTestRegisterServiceSuccess(self): 00122 master = self.master 00123 00124 caller_id = '/service_node' 00125 caller_api = 'http://localhost:4567/' 00126 service_base = '/service' 00127 00128 # test success 00129 for i in xrange(0, 10): 00130 service_name = "%s-%s"%(service_base, i) 00131 service_api = 'rosrpc://localhost:123%s/'%i 00132 # register the service 00133 self.apiSuccess(master.registerService(caller_id, service_name, service_api, caller_api)) 00134 # test master state 00135 val = self.apiSuccess(master.lookupService(caller_id, service_name)) 00136 self.assertEquals(service_api, val) 00137 val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id)) 00138 self.assertEquals(caller_api, val) 00139 00140 _, _, srvs = self.apiSuccess(master.getSystemState(self.caller_id)) 00141 for j in xrange(0, i+1): 00142 jservice_name = "%s-%s"%(service_base, j) 00143 jentry = [jservice_name, [caller_id]] 00144 self.assert_(jentry in srvs, "master service list %s is missing %s"%(srvs, jentry)) 00145 00146 # TODO: have to test subscriber callback 00147 # TODO: validate with getSystemState() 00148 00149 ## validate master.registerService(caller_id, service, service_api, caller_api) 00150 def _testRegisterServiceSuccess(self): 00151 self._subTestRegisterServiceSuccess() 00152 00153 def _testUnregisterServiceSuccess(self): 00154 self._subTestRegisterServiceSuccess() 00155 master = self.master 00156 caller_id = '/service_node' 00157 caller_api = 'http://localhost:4567/' 00158 service_base = '/service' 00159 00160 for i in xrange(0, 10): 00161 service_name = "%s-%s"%(service_base, i) 00162 service_api = 'rosrpc://localhost:123%s/'%i 00163 00164 # unregister the service 00165 code, msg, val = master.unregisterService(caller_id, service_name, service_api) 00166 self.assertEquals(code, 1, "code != 1, return message was [%s]"%msg) 00167 00168 # test the master state 00169 self.apiError(master.lookupService(self.caller_id, service_name), "master has a reference to unregistered service. message from master for unregister was [%s]"%msg) 00170 00171 if i < 9: 00172 val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id)) 00173 self.assertEquals(caller_api, val, "master prematurely invalidated node entry for [%s] (lookupNode)"%caller_id) 00174 00175 _, _, srvs = self.apiSuccess(master.getSystemState(self.caller_id)) 00176 for j in xrange(0, i+1): 00177 jservice_name = "%s-%s"%(service_base, j) 00178 jentry = [jservice_name, [caller_id]] 00179 self.assert_(jentry not in srvs, "master service list %s should not have %s"%(srvs, jentry)) 00180 for j in xrange(i+1, 10): 00181 jservice_name = "%s-%s"%(service_base, j) 00182 jentry = [jservice_name, [caller_id]] 00183 self.assert_(jentry in srvs, "master service list %s is missing %s"%(srvs, jentry)) 00184 00185 # TODO: have to test subscriber callback 00186 00187 # Master's state should be zero'd out now 00188 00189 # - #457 make sure that lookupNode isn't returning stale info 00190 self.apiError(master.lookupNode(self.caller_id, caller_id), "master has a stale reference to unregistered service node API") 00191 _, _, srvs = self.apiSuccess(master.getSystemState(self.caller_id)) 00192 srvs = [s for s in srvs if not s[0].startswith('/rosout/')] 00193 self.assertEquals(0, len(srvs), "all services should have been unregistered: %s"%srvs) 00194 00195 def _testRegisterServiceInvalid(self): 00196 master = self.master 00197 00198 service = '/service' 00199 service_api = 'rosrpc://localhost:1234/' 00200 caller_api = 'http://localhost:4567/' 00201 00202 # test with bad arity 00203 self.apiError(master.registerService()) 00204 self.apiError(master.registerService(self.caller_id, service)) 00205 self.apiError(master.registerService(self.caller_id, service, service_api)) 00206 00207 # test with bad args 00208 self.apiError(master.registerService(self.caller_id, '', service_api, caller_api)) 00209 self.apiError(master.registerService(self.caller_id, service, '', caller_api)) 00210 self.apiError(master.registerService(self.caller_id, service, service_api, '')) 00211 00212 def _testUnregisterServiceInvalid(self): 00213 master = self.master 00214 00215 service = '/service' 00216 service_api = 'rosrpc://localhost:1234/' 00217 00218 # test with bad arity 00219 self.apiError(master.unregisterService()) 00220 self.apiError(master.unregisterService(self.caller_id, service)) 00221 00222 # test with bad args 00223 self.apiError(master.unregisterService(self.caller_id, '', service_api)) 00224 self.apiError(master.unregisterService(self.caller_id, service, '')) 00225 00226 def _testRegisterPublisherInvalid(self): 00227 master = self.master 00228 00229 topic = '/pub_topic' 00230 topic_type = 'std_msgs/String' 00231 caller_api = 'http://localhost:4567/' 00232 00233 # test with bad arity 00234 self.apiError(master.registerPublisher()) 00235 self.apiError(master.registerPublisher(self.caller_id, topic)) 00236 self.apiError(master.registerPublisher(self.caller_id, topic, topic_type)) 00237 00238 # test with bad args 00239 self.apiError(master.registerPublisher(self.caller_id, '', topic_type, caller_api)) 00240 self.apiError(master.registerPublisher(self.caller_id, topic, '', caller_api)) 00241 self.apiError(master.registerPublisher(self.caller_id, topic, topic_type, '')) 00242 00243 def _testUnregisterPublisherInvalid(self): 00244 master = self.master 00245 00246 topic = '/pub_topic' 00247 caller_api = 'http://localhost:4567/' 00248 00249 # test with bad arity 00250 self.apiError(master.unregisterPublisher()) 00251 self.apiError(master.unregisterPublisher(self.caller_id, topic)) 00252 00253 # test with bad args 00254 self.apiError(master.unregisterPublisher(self.caller_id, '', caller_api)) 00255 self.apiError(master.unregisterPublisher(self.caller_id, topic, '')) 00256 00257 def _testRegisterSubscriberInvalid(self): 00258 master = self.master 00259 00260 topic = '/sub_topic' 00261 topic_type = 'std_msgs/String' 00262 caller_api = 'http://localhost:4567/' 00263 00264 # test with bad arity 00265 self.apiError(master.registerSubscriber()) 00266 self.apiError(master.registerSubscriber(self.caller_id, topic)) 00267 self.apiError(master.registerSubscriber(self.caller_id, topic, topic_type)) 00268 00269 # test with bad args 00270 self.apiError(master.registerSubscriber(self.caller_id, '', topic_type, caller_api)) 00271 self.apiError(master.registerSubscriber(self.caller_id, topic, '', caller_api)) 00272 self.apiError(master.registerSubscriber(self.caller_id, topic, topic_type, '')) 00273 00274 def _testUnregisterSubscriberInvalid(self): 00275 master = self.master 00276 00277 topic = '/sub_topic' 00278 caller_api = 'http://localhost:4567/' 00279 00280 # test with bad arity 00281 self.apiError(master.registerSubscriber()) 00282 self.apiError(master.registerSubscriber(self.caller_id, topic)) 00283 00284 # test with bad args 00285 self.apiError(master.unregisterSubscriber(self.caller_id, '', caller_api)) 00286 self.apiError(master.unregisterSubscriber(self.caller_id, topic, '')) 00287 00288 ## common test subroutine of both register and unregister tests. registers the common test cases 00289 def _subTestRegisterPublisherSuccess(self): 00290 master = self.master 00291 00292 caller_id = '/pub_node' 00293 caller_api = 'http://localhost:4567/' 00294 topic_base = '/pub_topic' 00295 topic_type = 'std_msgs/String' 00296 00297 # test success 00298 for i in xrange(0, 10): 00299 topic_name = "%s-%s"%(topic_base, i) 00300 # register the topic 00301 self.apiSuccess(master.registerPublisher(caller_id, topic_name, topic_type, caller_api)) 00302 # test master state 00303 # - master knows caller_id 00304 val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id)) 00305 self.assertEquals(caller_api, val) 00306 # - master knows topic type 00307 val = self.apiSuccess(master.getPublishedTopics(self.caller_id, '/')) 00308 self.assert_([topic_name, topic_type] in val, "master does not know topic type: %s"%val) 00309 # - test new api as well 00310 val = self.apiSuccess(master.getTopicTypes(self.caller_id)) 00311 self.assert_([topic_name, topic_type] in val, "master does not know topic type: %s"%val) 00312 00313 pubs, _, _ = self.apiSuccess(master.getSystemState(self.caller_id)) 00314 for j in xrange(0, i+1): 00315 jtopic_name = "%s-%s"%(topic_base, j) 00316 jentry = [jtopic_name, [caller_id]] 00317 self.assert_(jentry in pubs, "master pub/sub list %s is missing %s"%(pubs, jentry)) 00318 00319 # TODO: have to test subscriber callback 00320 00321 ## #591: this test may change if we make registering '*' unsupported 00322 def _testRegisterPublisherTypes(self): 00323 master = self.master 00324 caller_id = '/pub_node' 00325 caller_api = 'http://localhost:4567/' 00326 topic_name = '/type_test_pub_topic' 00327 00328 # register anytype first 00329 val = self.apiSuccess(master.registerPublisher(caller_id, topic_name, '*', caller_api)) 00330 self.assertEquals([], val) # should report no subscribers 00331 val = self.apiSuccess(master.getPublishedTopics(self.caller_id, '/')) 00332 self.assert_([topic_name, '*'] in val, "master is not reporting * as type: %s"%val) 00333 # - test new api as well 00334 val = self.apiSuccess(master.getTopicTypes(self.caller_id)) 00335 self.assert_([topic_name, '*'] in val, "master is not reporting * as type: %s"%val) 00336 00337 # register a grounded type and make sure that '*' can't overwrite it 00338 for t in ['std_msgs/String', '*']: 00339 val = self.apiSuccess(master.registerPublisher(caller_id, topic_name, t, caller_api)) 00340 self.assertEquals([], val) # should report no subscribers 00341 val = self.apiSuccess(master.getPublishedTopics(self.caller_id, '/')) 00342 self.assert_([topic_name, 'std_msgs/String'] in val, "master is not reporting std_msgs/String as type: %s"%val) 00343 00344 val = self.apiSuccess(master.getTopicTypes(self.caller_id)) 00345 self.assert_([topic_name, 'std_msgs/String'] in val, "master is not reporting std_msgs/String as type: %s"%val) 00346 00347 ## validate master.registerPublisher(caller_id, topic, topic_api, caller_api) 00348 def _testRegisterPublisherSuccess(self): 00349 self._subTestRegisterPublisherSuccess() 00350 00351 # a couple more test cases to verify that registerPublisher's return value is correct 00352 master = self.master 00353 topic = '/pub_topic-0' 00354 type = 'std_msgs/String' 00355 pub_caller_api = 'http://localhost:4567/' 00356 00357 subs = [] 00358 for i in xrange(5678, 5685): 00359 api = 'http://localhost:%s'%i 00360 subs.append(api) 00361 self.apiSuccess(master.registerSubscriber('/sub_node-%i'%i, topic, type, api)) 00362 val = self.apiSuccess(master.registerPublisher('/pub_node', topic, type, pub_caller_api)) 00363 self.assertEquals(subs, val) 00364 00365 def _testUnregisterPublisherSuccess(self): 00366 self._subTestRegisterPublisherSuccess() 00367 master = self.master 00368 caller_id = '/pub_node' 00369 caller_api = 'http://localhost:4567/' 00370 topic_base = '/pub_topic' 00371 00372 for i in xrange(0, 10): 00373 topic_name = "%s-%s"%(topic_base, i) 00374 00375 # unregister the topic 00376 code, msg, val = master.unregisterPublisher(caller_id, topic_name, caller_api) 00377 self.assertEquals(code, 1, "code != 1, return message was [%s]"%msg) 00378 00379 # test the master state 00380 if i < 9: 00381 val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id)) 00382 self.assertEquals(caller_api, val, "master prematurely invalidated node entry for [%s] (lookupNode)"%caller_id) 00383 00384 pubs, _, _ = self.apiSuccess(master.getSystemState(self.caller_id)) 00385 for j in xrange(0, i+1): 00386 jtopic_name = "%s-%s"%(topic_base, j) 00387 jentry = [jtopic_name, [caller_id]] 00388 self.assert_(jentry not in pubs, "master pub/sub list %s should not have %s"%(pubs, jentry)) 00389 for j in xrange(i+1, 10): 00390 jtopic_name = "%s-%s"%(topic_base, j) 00391 jentry = [jtopic_name, [caller_id]] 00392 self.assert_(jentry in pubs, "master pub/sub list %s is missing %s"%(pubs, jentry)) 00393 00394 # TODO: have to test subscriber callback 00395 00396 # - #457 make sure that lookupNode isn't returning stale info 00397 self.apiError(master.lookupNode(self.caller_id, caller_id), "master has a stale reference to unregistered topic node API. pubs are %s"%pubs) 00398 00399 ## common test subroutine of both register and unregister tests. registers the common test cases 00400 ## 'simple' test cases do not setup any publisher state to validate against 00401 def _subTestRegisterSubscriberSimpleSuccess(self): 00402 master = self.master 00403 00404 caller_id = '/sub_node' 00405 caller_api = 'http://localhost:4567/' 00406 topic_base = '/sub_topic' 00407 topic_type = 'std_msgs/String' 00408 00409 # test success 00410 for i in xrange(0, 10): 00411 topic_name = "%s-%s"%(topic_base, i) 00412 # register the topic 00413 self.apiSuccess(master.registerSubscriber(caller_id, topic_name, topic_type, caller_api)) 00414 # test master state 00415 # - master knows caller_id 00416 val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id)) 00417 self.assertEquals(caller_api, val) 00418 00419 # - master should know topic type 00420 val = self.apiSuccess(master.getTopicTypes(self.caller_id)) 00421 self.assert_([topic_name, topic_type] in val, "master does not know topic type: %s"%val) 00422 00423 _, subs, _ = self.apiSuccess(master.getSystemState(self.caller_id)) 00424 for j in xrange(0, i+1): 00425 jtopic_name = "%s-%s"%(topic_base, j) 00426 jentry = [jtopic_name, [caller_id]] 00427 self.assert_(jentry in subs, "master pub/sub list %s is missing %s"%(subs, jentry)) 00428 00429 ## validate master.registerSubscriber(caller_id, topic, topic_api, caller_api) 00430 def _testRegisterSubscriberSimpleSuccess(self): 00431 self._subTestRegisterSubscriberSimpleSuccess() 00432 00433 def _testUnregisterSubscriberSuccess(self): 00434 self._subTestRegisterSubscriberSimpleSuccess() 00435 master = self.master 00436 caller_id = '/sub_node' 00437 caller_api = 'http://localhost:4567/' 00438 topic_base = '/sub_topic' 00439 00440 for i in xrange(0, 10): 00441 topic_name = "%s-%s"%(topic_base, i) 00442 00443 # unregister the topic 00444 code, msg, val = master.unregisterSubscriber(caller_id, topic_name, caller_api) 00445 self.assertEquals(code, 1, "code != 1, return message was [%s]"%msg) 00446 00447 # test the master state 00448 if i < 9: 00449 val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id)) 00450 self.assertEquals(caller_api, val, "master prematurely invalidated node entry for [%s] (lookupNode)"%caller_id) 00451 00452 _, subs, _ = self.apiSuccess(master.getSystemState(self.caller_id)) 00453 for j in xrange(0, i+1): 00454 jtopic_name = "%s-%s"%(topic_base, j) 00455 jentry = [jtopic_name, [caller_id]] 00456 self.assert_(jentry not in subs, "master pub/sub list %s should not have %s"%(subs, jentry)) 00457 for j in xrange(i+1, 10): 00458 jtopic_name = "%s-%s"%(topic_base, j) 00459 jentry = [jtopic_name, [caller_id]] 00460 self.assert_(jentry in subs, "master pub/sub list %s is missing %s"%(subs, jentry)) 00461 00462 # - #457 make sure that lookupNode isn't returning stale info 00463 self.apiError(master.lookupNode(self.caller_id, caller_id), "master has a stale reference to unregistered topic node API. subs are %s"%subs) 00464 00465