master.py
Go to the documentation of this file.
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 try:
00040     from xmlrpc.client import ServerProxy
00041 except ImportError:
00042     from xmlrpclib import ServerProxy
00043 
00044 import rospy
00045 import rosgraph
00046 
00047 from rosclient import *
00048 
00049 NODE_INTEGRATION_NAME = "node_integration_test"
00050 
00051 _name = None
00052 ## set_node_name() must be called prior to the unit test so that the test harness knows its
00053 ## ROS name.
00054 def set_node_name(name):
00055     global _name
00056     _name = name
00057 
00058 # Have to try as hard as possible to not use rospy code in testing rospy code, so this is
00059 # a reimplementation of the caller ID spec so that NodeApiTestCase knows its name
00060 ## reimplementation of caller ID spec separately from rospy
00061 def get_caller_id():
00062     if _name is None:
00063         raise Exception("set_node_name has not been called yet")
00064     ros_ns = os.environ.get(rosgraph.ROS_NAMESPACE, rosgraph.names.GLOBALNS)
00065     return rosgraph.names.ns_join(ros_ns, _name)    
00066     
00067 class _MasterTestCase(TestRosClient):
00068 
00069     def __init__(self, *args):
00070         super(_MasterTestCase, self).__init__(*args)
00071         self.ns = os.environ.get(rosgraph.ROS_NAMESPACE, rosgraph.names.GLOBALNS)
00072         self.caller_id = get_caller_id()
00073         
00074     def setUp(self):
00075         super(_MasterTestCase, self).setUp()
00076         self.master_uri = os.environ.get(rosgraph.ROS_MASTER_URI, None)
00077         self._checkUri(self.master_uri)
00078         self.master = ServerProxy(self.master_uri)
00079 
00080     ## validates a URI as being http(s)
00081     def _checkUri(self, uri):
00082         import urlparse
00083         parsed = urlparse.urlparse(uri)
00084         self.assert_(parsed[0] in ['http', 'https'], 'protocol [%s] in [%s] invalid'%(parsed[0], uri))
00085         self.assert_(parsed[1], 'host missing [%s]'%uri)
00086         if not sys.version.startswith('2.4'): #check not available on py24
00087             self.assert_(parsed.port, 'port missing/invalid [%s]'%uri)        
00088     
00089 ## Expects a single test node to be running with name 'test_node' and subscribed to 'test_string'
00090 class MasterApiTestCase(_MasterTestCase):
00091 
00092     ## validate master.getMasterUri(caller_id)
00093     def _testGetMasterUri(self):
00094         # test with bad arity
00095         self.apiError(self.master.getMasterUri())
00096         # test success        
00097         uri = self.apiSuccess(self.master.getMasterUri(self.caller_id))
00098         self._checkUri(uri)
00099 
00100         # make sure we agree on ports
00101         import urlparse
00102         parsed = urlparse.urlparse(uri)
00103         parsed2 = urlparse.urlparse(self.master_uri)        
00104         
00105         self.assertEquals(parsed.port, parsed2.port, "expected ports do not match")
00106 
00107     ## validate master.getPid(caller_id)        
00108     def _testGetPid(self):
00109         # test with bad arity
00110         self.apiError(self.master.getPid())
00111         # test success        
00112         pid = self.apiSuccess(self.master.getPid(self.caller_id))
00113         self.assert_(pid > 0)
00114 
00115     ## validate master.getUri(caller_id)        
00116     def _testGetUri(self):
00117         # test with bad arity
00118         self.apiError(self.master.getUri())
00119         # test success        
00120         uri = self.apiSuccess(self.master.getUri(self.caller_id))
00121         self.assert_(type(uri) == str)
00122         
00123     ## common test subroutine of both register and unregister tests. registers the common test cases
00124     def _subTestRegisterServiceSuccess(self):
00125         master = self.master
00126         
00127         caller_id = '/service_node'
00128         caller_api = 'http://localhost:4567/'                
00129         service_base = '/service'
00130         
00131         # test success        
00132         for i in range(0, 10):
00133             service_name = "%s-%s"%(service_base, i)
00134             service_api = 'rosrpc://localhost:123%s/'%i
00135             # register the service
00136             self.apiSuccess(master.registerService(caller_id, service_name, service_api, caller_api))
00137             # test master state
00138             val = self.apiSuccess(master.lookupService(caller_id, service_name))
00139             self.assertEquals(service_api, val)
00140             val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id)) 
00141             self.assertEquals(caller_api, val)
00142 
00143             _, _, srvs = self.apiSuccess(master.getSystemState(self.caller_id))
00144             for j in range(0, i+1):
00145                 jservice_name = "%s-%s"%(service_base, j)
00146                 jentry = [jservice_name, [caller_id]]
00147                 self.assert_(jentry in srvs, "master service list %s is missing %s"%(srvs, jentry))
00148 
00149         # TODO: have to test subscriber callback
00150         # TODO: validate with getSystemState()
00151 
00152     ## validate master.registerService(caller_id, service, service_api, caller_api) 
00153     def _testRegisterServiceSuccess(self):
00154         self._subTestRegisterServiceSuccess()
00155 
00156     def _testUnregisterServiceSuccess(self):
00157         self._subTestRegisterServiceSuccess()
00158         master = self.master
00159         caller_id = '/service_node'
00160         caller_api = 'http://localhost:4567/'                
00161         service_base = '/service'
00162 
00163         for i in range(0, 10):
00164             service_name = "%s-%s"%(service_base, i)
00165             service_api = 'rosrpc://localhost:123%s/'%i
00166 
00167             # unregister the service
00168             code, msg, val = master.unregisterService(caller_id, service_name, service_api)
00169             self.assertEquals(code, 1, "code != 1, return message was [%s]"%msg)
00170 
00171             # test the master state
00172             self.apiError(master.lookupService(self.caller_id, service_name), "master has a reference to unregistered service. message from master for unregister was [%s]"%msg)
00173 
00174             if i < 9:
00175                 val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id))
00176                 self.assertEquals(caller_api, val, "master prematurely invalidated node entry for [%s] (lookupNode)"%caller_id)
00177             
00178             _, _, srvs = self.apiSuccess(master.getSystemState(self.caller_id))
00179             for j in range(0, i+1):
00180                 jservice_name = "%s-%s"%(service_base, j)
00181                 jentry = [jservice_name, [caller_id]]
00182                 self.assert_(jentry not in srvs, "master service list %s should not have %s"%(srvs, jentry))
00183             for j in range(i+1, 10):
00184                 jservice_name = "%s-%s"%(service_base, j)
00185                 jentry = [jservice_name, [caller_id]]
00186                 self.assert_(jentry in srvs, "master service list %s is missing %s"%(srvs, jentry))
00187 
00188             # TODO: have to test subscriber callback
00189             
00190         # Master's state should be zero'd out now
00191         
00192         #  - #457 make sure that lookupNode isn't returning stale info
00193         self.apiError(master.lookupNode(self.caller_id, caller_id), "master has a stale reference to unregistered service node API")
00194         _, _, srvs = self.apiSuccess(master.getSystemState(self.caller_id))
00195         srvs = [s for s in srvs if not s[0].startswith('/rosout/') and not s[0].endswith('/get_loggers') and not s[0].endswith('/set_logger_level')]
00196         self.assertEquals(0, len(srvs), "all services should have been unregistered: %s"%srvs)
00197 
00198     def _testRegisterServiceInvalid(self):
00199         master = self.master
00200         
00201         service = '/service'
00202         service_api = 'rosrpc://localhost:1234/'
00203         caller_api = 'http://localhost:4567/'                
00204 
00205         # test with bad arity
00206         self.apiError(master.registerService())
00207         self.apiError(master.registerService(self.caller_id, service))
00208         self.apiError(master.registerService(self.caller_id, service, service_api))
00209 
00210         # test with bad args
00211         self.apiError(master.registerService(self.caller_id, '', service_api, caller_api))
00212         self.apiError(master.registerService(self.caller_id, service, '', caller_api))        
00213         self.apiError(master.registerService(self.caller_id, service, service_api, ''))                
00214         
00215     def _testUnregisterServiceInvalid(self):
00216         master = self.master
00217         
00218         service = '/service'
00219         service_api = 'rosrpc://localhost:1234/'
00220 
00221         # test with bad arity
00222         self.apiError(master.unregisterService())
00223         self.apiError(master.unregisterService(self.caller_id, service))
00224 
00225         # test with bad args
00226         self.apiError(master.unregisterService(self.caller_id, '', service_api))
00227         self.apiError(master.unregisterService(self.caller_id, service, ''))        
00228 
00229     def _testRegisterPublisherInvalid(self):
00230         master = self.master
00231         
00232         topic = '/pub_topic'
00233         topic_type = 'test_rosmaster/String'        
00234         caller_api = 'http://localhost:4567/'                
00235 
00236         # test with bad arity
00237         self.apiError(master.registerPublisher())
00238         self.apiError(master.registerPublisher(self.caller_id, topic))
00239         self.apiError(master.registerPublisher(self.caller_id, topic, topic_type))
00240 
00241         # test with bad args
00242         self.apiError(master.registerPublisher(self.caller_id, '',    topic_type, caller_api))
00243         self.apiError(master.registerPublisher(self.caller_id, topic, '',         caller_api))        
00244         self.apiError(master.registerPublisher(self.caller_id, topic, topic_type, ''))
00245 
00246     def _testUnregisterPublisherInvalid(self):
00247         master = self.master
00248         
00249         topic = '/pub_topic'
00250         caller_api = 'http://localhost:4567/'                
00251 
00252         # test with bad arity
00253         self.apiError(master.unregisterPublisher())
00254         self.apiError(master.unregisterPublisher(self.caller_id, topic))
00255 
00256         # test with bad args
00257         self.apiError(master.unregisterPublisher(self.caller_id, '',    caller_api))
00258         self.apiError(master.unregisterPublisher(self.caller_id, topic, ''))
00259 
00260     def _testRegisterSubscriberInvalid(self):
00261         master = self.master
00262         
00263         topic = '/sub_topic'
00264         topic_type = 'test_rosmaster/String'        
00265         caller_api = 'http://localhost:4567/'                
00266 
00267         # test with bad arity
00268         self.apiError(master.registerSubscriber())
00269         self.apiError(master.registerSubscriber(self.caller_id, topic))
00270         self.apiError(master.registerSubscriber(self.caller_id, topic, topic_type))
00271 
00272         # test with bad args
00273         self.apiError(master.registerSubscriber(self.caller_id, '',    topic_type, caller_api))
00274         self.apiError(master.registerSubscriber(self.caller_id, topic, '',         caller_api))        
00275         self.apiError(master.registerSubscriber(self.caller_id, topic, topic_type, ''))
00276 
00277     def _testUnregisterSubscriberInvalid(self):
00278         master = self.master
00279         
00280         topic = '/sub_topic'
00281         caller_api = 'http://localhost:4567/'                
00282 
00283         # test with bad arity
00284         self.apiError(master.registerSubscriber())
00285         self.apiError(master.registerSubscriber(self.caller_id, topic))
00286 
00287         # test with bad args
00288         self.apiError(master.unregisterSubscriber(self.caller_id, '',    caller_api))
00289         self.apiError(master.unregisterSubscriber(self.caller_id, topic, ''))
00290 
00291     ## common test subroutine of both register and unregister tests. registers the common test cases
00292     def _subTestRegisterPublisherSuccess(self):
00293         master = self.master
00294         
00295         caller_id = '/pub_node'
00296         caller_api = 'http://localhost:4567/'                
00297         topic_base = '/pub_topic'
00298         topic_type = 'test_rosmaster/String'  
00299         
00300         # test success        
00301         for i in range(0, 10):
00302             topic_name = "%s-%s"%(topic_base, i)
00303             # register the topic
00304             self.apiSuccess(master.registerPublisher(caller_id, topic_name, topic_type, caller_api))
00305             # test master state
00306             # - master knows caller_id
00307             val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id))
00308             self.assertEquals(caller_api, val)
00309             # - master knows topic type
00310             val = self.apiSuccess(master.getPublishedTopics(self.caller_id, '/'))
00311             self.assert_([topic_name, topic_type] in val, "master does not know topic type: %s"%val)
00312             #   - test new api as well
00313             val = self.apiSuccess(master.getTopicTypes(self.caller_id))
00314             self.assert_([topic_name, topic_type] in val, "master does not know topic type: %s"%val)
00315 
00316             pubs, _, _ = self.apiSuccess(master.getSystemState(self.caller_id))
00317             for j in range(0, i+1):
00318                 jtopic_name = "%s-%s"%(topic_base, j)
00319                 jentry = [jtopic_name, [caller_id]]
00320                 self.assert_(jentry in pubs, "master pub/sub list %s is missing %s"%(pubs, jentry))
00321             
00322         # TODO: have to test subscriber callback
00323 
00324     ## #591: this test may change if we make registering '*' unsupported
00325     def _testRegisterPublisherTypes(self):
00326         master = self.master
00327         caller_id = '/pub_node'
00328         caller_api = 'http://localhost:4567/'                
00329         topic_name = '/type_test_pub_topic'
00330 
00331         # register anytype first
00332         val = self.apiSuccess(master.registerPublisher(caller_id, topic_name, '*', caller_api))
00333         self.assertEquals([], val) # should report no subscribers
00334         val = self.apiSuccess(master.getPublishedTopics(self.caller_id, '/'))
00335         self.assert_([topic_name, '*'] in val, "master is not reporting * as type: %s"%val)
00336         #  - test new api as well
00337         val = self.apiSuccess(master.getTopicTypes(self.caller_id))
00338         self.assert_([topic_name, '*'] in val, "master is not reporting * as type: %s"%val)
00339         
00340         # register a grounded type and make sure that '*' can't overwrite it
00341         for t in ['test_rosmaster/String', '*']:
00342             val = self.apiSuccess(master.registerPublisher(caller_id, topic_name, t, caller_api))   
00343             self.assertEquals([], val) # should report no subscribers
00344             val = self.apiSuccess(master.getPublishedTopics(self.caller_id, '/'))
00345             self.assert_([topic_name, 'test_rosmaster/String'] in val, "master is not reporting test_rosmaster/String as type: %s"%val)
00346 
00347             val = self.apiSuccess(master.getTopicTypes(self.caller_id))
00348             self.assert_([topic_name, 'test_rosmaster/String'] in val, "master is not reporting test_rosmaster/String as type: %s"%val)
00349         
00350     ## validate master.registerPublisher(caller_id, topic, topic_api, caller_api) 
00351     def _testRegisterPublisherSuccess(self):
00352         self._subTestRegisterPublisherSuccess()
00353 
00354         # a couple more test cases to verify that registerPublisher's return value is correct
00355         master = self.master
00356         topic = '/pub_topic-0'
00357         type = 'test_rosmaster/String'
00358         pub_caller_api = 'http://localhost:4567/'
00359         
00360         subs = []
00361         for i in range(5678, 5685):
00362             api = 'http://localhost:%s'%i
00363             subs.append(api)
00364             self.apiSuccess(master.registerSubscriber('/sub_node-%i'%i, topic, type, api))
00365             val = self.apiSuccess(master.registerPublisher('/pub_node', topic, type, pub_caller_api))            
00366             self.assertEquals(subs, val)
00367         
00368     def _testUnregisterPublisherSuccess(self):
00369         self._subTestRegisterPublisherSuccess()
00370         master = self.master
00371         caller_id = '/pub_node'
00372         caller_api = 'http://localhost:4567/' 
00373         topic_base = '/pub_topic'
00374 
00375         for i in range(0, 10):
00376             topic_name = "%s-%s"%(topic_base, i)
00377 
00378             # unregister the topic
00379             code, msg, val = master.unregisterPublisher(caller_id, topic_name, caller_api)
00380             self.assertEquals(code, 1, "code != 1, return message was [%s]"%msg)
00381 
00382             # test the master state
00383             if i < 9:
00384                 val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id))
00385                 self.assertEquals(caller_api, val, "master prematurely invalidated node entry for [%s] (lookupNode)"%caller_id)
00386 
00387             pubs, _, _ = self.apiSuccess(master.getSystemState(self.caller_id))
00388             for j in range(0, i+1):
00389                 jtopic_name = "%s-%s"%(topic_base, j)
00390                 jentry = [jtopic_name, [caller_id]]
00391                 self.assert_(jentry not in pubs, "master pub/sub list %s should not have %s"%(pubs, jentry))
00392             for j in range(i+1, 10):
00393                 jtopic_name = "%s-%s"%(topic_base, j)
00394                 jentry = [jtopic_name, [caller_id]]
00395                 self.assert_(jentry in pubs, "master pub/sub list %s is missing %s"%(pubs, jentry))
00396 
00397             # TODO: have to test subscriber callback
00398             
00399         #  - #457 make sure that lookupNode isn't returning stale info
00400         self.apiError(master.lookupNode(self.caller_id, caller_id), "master has a stale reference to unregistered topic node API. pubs are %s"%pubs)
00401 
00402     ## common test subroutine of both register and unregister tests. registers the common test cases
00403     ## 'simple' test cases do not setup any publisher state to validate against
00404     def _subTestRegisterSubscriberSimpleSuccess(self):
00405         master = self.master
00406         
00407         caller_id = '/sub_node'
00408         caller_api = 'http://localhost:4567/'                
00409         topic_base = '/sub_topic'
00410         topic_type = 'test_rosmaster/String'  
00411         
00412         # test success        
00413         for i in range(0, 10):
00414             topic_name = "%s-%s"%(topic_base, i)
00415             # register the topic
00416             self.apiSuccess(master.registerSubscriber(caller_id, topic_name, topic_type, caller_api))
00417             # test master state
00418             # - master knows caller_id
00419             val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id))
00420             self.assertEquals(caller_api, val)
00421 
00422             # - master should know topic type
00423             val = self.apiSuccess(master.getTopicTypes(self.caller_id))
00424             self.assert_([topic_name, topic_type] in val, "master does not know topic type: %s"%val)
00425             
00426             _, subs, _ = self.apiSuccess(master.getSystemState(self.caller_id))
00427             for j in range(0, i+1):
00428                 jtopic_name = "%s-%s"%(topic_base, j)
00429                 jentry = [jtopic_name, [caller_id]]
00430                 self.assert_(jentry in subs, "master pub/sub list %s is missing %s"%(subs, jentry))
00431             
00432     ## validate master.registerSubscriber(caller_id, topic, topic_api, caller_api) 
00433     def _testRegisterSubscriberSimpleSuccess(self):
00434         self._subTestRegisterSubscriberSimpleSuccess()
00435 
00436     def _testUnregisterSubscriberSuccess(self):
00437         self._subTestRegisterSubscriberSimpleSuccess()
00438         master = self.master
00439         caller_id = '/sub_node'
00440         caller_api = 'http://localhost:4567/' 
00441         topic_base = '/sub_topic'
00442 
00443         for i in range(0, 10):
00444             topic_name = "%s-%s"%(topic_base, i)
00445 
00446             # unregister the topic
00447             code, msg, val = master.unregisterSubscriber(caller_id, topic_name, caller_api)
00448             self.assertEquals(code, 1, "code != 1, return message was [%s]"%msg)
00449 
00450             # test the master state
00451             if i < 9:
00452                 val = self.apiSuccess(master.lookupNode(self.caller_id, caller_id))
00453                 self.assertEquals(caller_api, val, "master prematurely invalidated node entry for [%s] (lookupNode)"%caller_id)
00454 
00455             _, subs, _ = self.apiSuccess(master.getSystemState(self.caller_id))
00456             for j in range(0, i+1):
00457                 jtopic_name = "%s-%s"%(topic_base, j)
00458                 jentry = [jtopic_name, [caller_id]]
00459                 self.assert_(jentry not in subs, "master pub/sub list %s should not have %s"%(subs, jentry))
00460             for j in range(i+1, 10):
00461                 jtopic_name = "%s-%s"%(topic_base, j)
00462                 jentry = [jtopic_name, [caller_id]]
00463                 self.assert_(jentry in subs, "master pub/sub list %s is missing %s"%(subs, jentry))
00464 
00465         #  - #457 make sure that lookupNode isn't returning stale info
00466         self.apiError(master.lookupNode(self.caller_id, caller_id), "master has a stale reference to unregistered topic node API. subs are %s"%subs)
00467 
00468 


test_rosmaster
Author(s): Ken Conley
autogenerated on Tue Mar 7 2017 03:45:38