This commit is contained in:
Ivan
2022-04-05 11:42:28 +03:00
commit 6dc0eb0fcf
5565 changed files with 1200500 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
cmake_minimum_required(VERSION 2.8.3)
project(test_rospy)
find_package(catkin REQUIRED COMPONENTS genmsg rosunit rostest std_msgs test_rosmaster)
if(CATKIN_ENABLE_TESTING)
# messages are for integration testing only
add_message_files(DIRECTORY msg
FILES
ArrayVal.msg
EmbedTest.msg
Empty.msg
Floats.msg
HeaderHeaderVal.msg
HeaderVal.msg
PythonKeyword.msg
TestConstants.msg
TestFixedArray.msg
TransitiveImport.msg
TransitiveMsg1.msg
TransitiveMsg2.msg
Val.msg
NOINSTALL
)
add_service_files(DIRECTORY srv
FILES
ConstantsMultiplex.srv
EmptyReqSrv.srv
EmptyRespSrv.srv
EmptySrv.srv
ListReturn.srv
MultipleAddTwoInts.srv
StringString.srv
TransitiveSrv.srv
NOINSTALL
)
generate_messages(DEPENDENCIES std_msgs test_rosmaster)
endif()
catkin_package()
if(CATKIN_ENABLE_TESTING)
catkin_add_nosetests(test/unit)
# integration tests
# - accidentally wrote two integration tests for client param API. They are different enough that it's no harm in having both
add_rostest(test/rostest/client-param-server.test)
add_rostest(test/rostest/client-param-api-2.test)
add_rostest(test/rostest/services.test)
add_rostest(test/rostest/deregister.test)
add_rostest(test/rostest/pubsub-order.test)
add_rostest(test/rostest/embed-msg.test)
add_rostest(test/rostest/rospy.test)
add_rostest(test/rostest/rospy_sim_time.test)
add_rostest(test/rostest/node.test)
add_rostest(test/rostest/latch.test)
add_rostest(test/rostest/on_shutdown.test)
add_rostest(test/rostest/sub_to_multiple_pubs.test)
add_rostest(test/rostest/latch_unsubscribe.test)
endif()

View File

@@ -0,0 +1,2 @@
Val[] vals
#Val[10] vals_fixed

View File

@@ -0,0 +1,6 @@
std_msgs/String str1
std_msgs/Int32 int1
std_msgs/Int32[] ints
Val val
Val[] vals
ArrayVal[] arrayval

View File

View File

@@ -0,0 +1,2 @@
# exact copy of rospy_tutorials/Floats, used for testing
float32[] data

View File

@@ -0,0 +1,2 @@
Header header
HeaderVal val

View File

@@ -0,0 +1,2 @@
Header header
string val

View File

@@ -0,0 +1 @@
int32 yield

View File

@@ -0,0 +1,15 @@
float32 A=-123.0
float32 B=124.0
float64 C=125.0
int32 X=123
int32 Y=-123
uint32 Z=124
string FOO=foo
string SINGLEQUOTE='hi
string DOUBLEQUOTE="hello" there
string MULTIQUOTE="hello" 'goodbye'
string EXAMPLE="#comments" are ignored, and leading and trailing whitespace removed
string WHITESPACE= strip
string EMPTY=
bool TRUE=1
bool FALSE=0

View File

@@ -0,0 +1,16 @@
float32[1] f32_1
float32[3] f32_3
float64[1] f64_1
float64[3] f64_3
int8[1] i8_1
int8[3] i8_3
uint8[1] u8_1
uint8[3] u8_3
int32[1] i32_1
int32[3] i32_3
uint32[1] u32_1
uint32[3] u32_3
string[1] s_1
string[3] s_3
bool[1] b_1
bool[3] b_3

View File

@@ -0,0 +1,2 @@
# Bug #2133/2139: EmbedTest uses std_msgs, so TransitiveImport needs it as well
EmbedTest data

View File

@@ -0,0 +1,2 @@
TransitiveMsg2 msg2

View File

@@ -0,0 +1 @@
test_rosmaster/Composite data

View File

@@ -0,0 +1 @@
string val

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Revision $Id: gossipbot.py 1013 2008-05-21 01:08:56Z sfkwc $
## Simple talker demo that listens to std_msgs/Strings published
## to the 'chatter' topic
from __future__ import print_function
import sys
import rospy
from std_msgs.msg import String
def callback(data):
print(rospy.get_caller_id(), "I heard %s"%data.data)
def listener():
# in ROS, nodes are unique named. If two nodes with the same
# node are launched, the previous one is kicked off. The
# anonymous=True flag means that rospy will choose a unique
# name for our 'talker' node so that multiple talkers can
# run simultaenously.
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
if __name__ == '__main__':
listener()

View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Simple talker demo that listens to std_msgs/Strings published
## to the 'chatter' topic and shuts down afterwards
from __future__ import print_function
import rospy
from std_msgs.msg import String
def callback(data):
print(rospy.get_caller_id(), "I heard %s" % data.data)
rospy.signal_shutdown("Received %s, exiting now" % data.data)
def listener():
rospy.init_node('listener', anonymous=True)
rospy.sleep(rospy.get_param('delay', 0.0))
rospy.Subscriber("chatter", String, callback)
rospy.spin()
if __name__ == '__main__':
listener()

View File

@@ -0,0 +1,65 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Utility node for testing. Listens to chatter and when it gets a
## message it starts rebroadcasting on 'listenerpublisher'. Unlike
## the normal listener, listenerpublisher is NOT anonymous.
from __future__ import print_function
import sys
import rospy
from std_msgs.msg import *
_publishing = False
_pub = None
def start_publishing():
global _pub
if _pub is not None:
return
print("registering onto listenerpublisher")
_pub = rospy.Publisher("listenerpublisher", String)
def callback(data):
print(rospy.get_caller_id(), "I heard %s"%data.data)
start_publishing()
print("publishing", data.data)
_pub.publish(String(data.data))
def listener():
rospy.init_node("listenerpublisher")
rospy.Subscriber("chatter", String, callback)
rospy.spin()
if __name__ == '__main__':
listener()

View File

@@ -0,0 +1,66 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Utility node for testing. Listens to chatter and when it gets a
## message it starts rebroadcasting on 'listenerpublisher'. Unlike
## the normal listener, listenerpublisher is NOT anonymous.
from __future__ import print_function
import sys
import rospy
from test_rospy.msg import EmbedTest
_publishing = False
_pub = None
def start_publishing():
global _pub
if _pub is not None:
return
print("registering onto listenerpublisher")
_pub = rospy.Publisher("listenerpublisher", EmbedTest)
def callback(data):
print(rospy.get_caller_id(), "I heard %s, %s, %s"%(data.str1.data, data.int1.data, data.val.val))
start_publishing()
print("re-publishing")
_pub.publish(data)
def listener():
rospy.init_node("listenerpublisher_embed")
rospy.Subscriber("chatter", EmbedTest, callback)
rospy.spin()
if __name__ == '__main__':
listener()

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Simple talker demo that published std_msgs/Strings messages
## to the 'chatter' topic
import rospy
from std_msgs.msg import String
pub = None
# publish a message to subscribers when we die
def talker_shutdown():
print("I'm dead!")
pub.publish("I'm dead!")
def talker():
global pub
pub = rospy.Publisher('chatter', String)
rospy.init_node('talker', anonymous=True)
# register talker_shutdown() to be called when rospy exits
rospy.on_shutdown(talker_shutdown)
import time
time.sleep(2.0)
rospy.signal_shutdown('test done')
if __name__ == '__main__':
talker()

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Copy of talker demo for testing purposes. Publishes String to 'chatter'
NAME = 'talker'
import sys
import rospy
from std_msgs.msg import *
def talker():
pub = rospy.Publisher("chatter", String)
rospy.init_node(NAME, anonymous=True)
count = 0
while not rospy.is_shutdown():
str = "hello world %d"%count
print str
pub.publish(String(str))
count += 1
rospy.sleep(0.01)
if __name__ == '__main__':
talker()

View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Simple talker demo that publishes std_msg/Strings to the 'chatter' topic
PKG = 'test_rospy' # this package name
NAME = 'talker'
import sys
import time
import rospy
from std_msgs.msg import String
def talker():
# create our publish handle
pub = rospy.Publisher('chatter', String)
# in ROS, nodes are unique named. If two nodes with the same
# node are launched, the previous one is kicked off. The
# anonymous=True flag means that rospy will choose a unique
# name for our 'talker' node so that multiple talkers can
# run simultaenously.
rospy.init_node('talker', anonymous=True)
count = 0
while not rospy.is_shutdown():
start = time.time()
str = "hello world %d"%count
print(str)
pub.publish(String(str))
count += 1
time.sleep(0.1)
if __name__ == '__main__':
talker()

View File

@@ -0,0 +1,25 @@
<package>
<name>test_rospy</name>
<version>1.12.14</version>
<description>
rospy unit and integration test framework.
</description>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>BSD</license>
<url>http://ros.org/wiki/rospy</url>
<author>Ken Conley</author>
<buildtool_depend version_gte="0.5.68">catkin</buildtool_depend>
<build_depend>genmsg</build_depend>
<build_depend>rostest</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>test_rosmaster</build_depend>
<test_depend>python-numpy</test_depend>
<test_depend>python-psutil</test_depend>
<test_depend>rosbuild</test_depend>
<test_depend>rosgraph</test_depend>
<test_depend>rospy</test_depend>
</package>

View File

@@ -0,0 +1,33 @@
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# test_rospy initialization file

View File

@@ -0,0 +1,26 @@
byte BYTE_X=0
byte BYTE_Y=15
byte BYTE_Z=5
int32 INT32_X=0
int32 INT32_Y=-12345678
int32 INT32_Z=12345678
uint32 UINT32_X=0
uint32 UINT32_Y=12345678
uint32 UINT32_Z=1
float32 FLOAT32_X=0.0
float32 FLOAT32_Y=-3.14159
float32 FLOAT32_Z=12345.78
byte SELECT_X=1
byte SELECT_Y=2
byte SELECT_Z=3
byte selection
---
# test response constants as well
byte CONFIRM_X=1
byte CONFIRM_Y=2
byte CONFIRM_Z=3
byte select_confirm
byte ret_byte
int32 ret_int32
uint32 ret_uint32
float32 ret_float32

View File

@@ -0,0 +1,2 @@
---
int32 fake_secret

View File

@@ -0,0 +1,2 @@
int32 fake_secret
---

View File

@@ -0,0 +1 @@
---

View File

@@ -0,0 +1,7 @@
# test case for having single list return value
int32 a
int32 b
int32 c
int32 d
---
int32[] abcd

View File

@@ -0,0 +1,8 @@
# test case for having multiple return values
int32 a
int32 b
int32 c
int32 d
---
int32 ab
int32 cd

View File

@@ -0,0 +1,4 @@
std_msgs/String str
Val str2
---
std_msgs/String str

View File

@@ -0,0 +1,4 @@
test_rospy/TransitiveMsg1 msg
---
int32 a

View File

@@ -0,0 +1,19 @@
<launch>
<param name="param1" value="global_param1"/>
<param name="global_param" value="foo"/>
<!-- this is a test of search_param -->
<param name="parent_param" value="baz"/>
<group ns="test_ns">
<param name="param1" value="parent_param1"/>
<param name="parent_param" value="bar"/>
<param name="param_str" value="hello world"/>
<param name="param_int" value="1" type="int"/>
<param name="param_float" value="2." type="double"/>
<param name="param_bool" value="True" type="bool"/>
<test pkg="test_rospy" type="test_client_param_api.py" test-name="test_client_param_api">
<param name="param1" value="private_param1" />
</test>
</group>
</launch>

View File

@@ -0,0 +1,16 @@
<!-- test rospy.client param server methods -->
<launch>
<param name="string" value="string" />
<param name="int0" value="0" />
<param name="int10" value="10" />
<param name="float0" value="0.0" />
<param name="float10" value="10.0" />
<param name="namespace/string" value="namespaced string" />
<test test-name="rospy_client_param_server" pkg="test_rospy" type="test_client_param_server.py" />
</launch>

View File

@@ -0,0 +1,10 @@
<!-- test unregister methods of rospy topic API -->
<launch>
<node name="talker" pkg="test_rospy" type="talker.py">
<remap from="chatter" to="test_unsubscribe_chatter" />
</node>
<node name="listener" pkg="test_rospy" type="listener.py">
<remap from="chatter" to="test_unpublish_chatter" />
</node>
<test test-name="rospy_deregister" pkg="test_rospy" type="test_deregister.py" />
</launch>

View File

@@ -0,0 +1,5 @@
<!-- test messages within messages -->
<launch>
<node name="listenerpublisher" pkg="test_rospy" type="listenerpublisher_embed.py" />
<test test-name="rospy_embed_msg" pkg="test_rospy" type="test_embed_msg.py" />
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<node name="rostopic_pub" pkg="rostopic" type="rostopic" args="pub s std_msgs/String foo" />
<test test-name="test_latch" pkg="test_rospy" type="test_latch.py" />
</launch>

View File

@@ -0,0 +1,7 @@
<launch>
<node name="listener_once_1" pkg="test_rospy" type="listener_once.py" output="screen" />
<node name="listener_once_2" pkg="test_rospy" type="listener_once.py" output="screen">
<param name="delay" value="1.0" type="double" />
</node>
<test test-name="test_latch_unsubscribe" pkg="test_rospy" type="test_latch_unsubscribe.py" />
</launch>

View File

@@ -0,0 +1,24 @@
<launch>
<node name="test_node" pkg="test_rospy" type="test_node.py" />
<test test-name="test_rospy__global" pkg="test_rosmaster" type="test_node_api.py" />
<group>
<!-- test within same namespace with test_node renamed to 'test_node2' -->
<node pkg="test_rospy" type="test_node.py" name="test_node2" />
<test test-name="test_rospy__global_test_node2" pkg="test_rosmaster" type="test_node_api.py" args="--node=test_node2"/>
</group>
<!-- test with nodes within namespaces -->
<group ns="child_namespace">
<node name="test_node" pkg="test_rospy" type="test_node.py" />
<test test-name="test_rospy__child_namespace" pkg="test_rosmaster" type="test_node_api.py" />
<group ns="grandchild_namespace">
<node name="test_node" pkg="test_rospy" type="test_node.py" />
<test test-name="test_rospy__grandchild_namespace" pkg="test_rosmaster" type="test_node_api.py" />
</group>
</group>
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<node name="pos_node" pkg="test_rospy" type="publish_on_shutdown.py" />
<test test-name="on_shutdown" pkg="test_rospy" type="test_on_shutdown.py" />
</launch>

View File

@@ -0,0 +1,5 @@
<launch>
<!-- the gist of this test is to have a listener registered to a topic before the publisher comes online -->
<node name="listenerpublisher" pkg="test_rospy" type="listenerpublisher.py" />
<test test-name="rospy_pubsub_order" pkg="test_rospy" type="test_pubsub_order.py" />
</launch>

View File

@@ -0,0 +1,11 @@
<launch>
<param name="param" value="value" />
<group ns="group">
<param name="param" value="group_value" />
</group>
<node name="talker" pkg="test_rospy" type="talker.py" />
<node name="a2iserver" pkg="test_rosmaster" type="add_two_ints_server" />
<test test-name="rospy_client" pkg="test_rospy" type="test_rospy_client_online.py" />
<test test-name="rospy_timer" pkg="test_rospy" type="test_rospy_timer_online.py" />
</launch>

View File

@@ -0,0 +1,13 @@
<launch>
<param name="/use_sim_time" value="true" />
<param name="param" value="value" />
<group ns="group">
<param name="param" value="group_value" />
</group>
<node name="fake_time" pkg="test_rosmaster" type="fake_time.py" />
<node name="talker" pkg="test_rospy" type="talker.py" />
<node name="a2iserver" pkg="test_rosmaster" type="add_two_ints_server" />
<test test-name="rospy_client" pkg="test_rospy" type="test_rospy_client_online.py" />
</launch>

View File

@@ -0,0 +1,17 @@
<!-- test rospy services -->
<launch>
<node name="empty" pkg="test_rospy" type="test_empty_service.py" args="--service" />
<node name="before" pkg="test_rospy" type="test_service_order.py" args="--before" />
<node name="after" pkg="test_rospy" type="test_service_order.py" args="--after" />
<node name="basic" pkg="test_rospy" type="test_basic_services.py" args="--service" />
<test test-name="rospy_empty_service" pkg="test_rospy" type="test_empty_service.py" />
<test test-name="rospy_basic_services" pkg="test_rospy" type="test_basic_services.py" />
<test test-name="rospy_service_decl_order" pkg="test_rospy" type="test_service_order.py" />
<node name="fail_two_ints" pkg="test_rosmaster" type="fail_two_ints_server">
<remap from="add_two_ints" to="fail_two_ints" />
</node>
<test test-name="rospy_service_failure" pkg="test_rospy" type="test_service_failure.py" />
</launch>

View File

@@ -0,0 +1,103 @@
<launch>
<node name="talker1" pkg="test_rospy" type="talker.py" />
<node name="talker2" pkg="test_rospy" type="talker.py" />
<node name="talker3" pkg="test_rospy" type="talker.py" />
<node name="talker4" pkg="test_rospy" type="talker.py" />
<node name="talker5" pkg="test_rospy" type="talker.py" />
<node name="talker6" pkg="test_rospy" type="talker.py" />
<node name="talker7" pkg="test_rospy" type="talker.py" />
<node name="talker8" pkg="test_rospy" type="talker.py" />
<node name="talker9" pkg="test_rospy" type="talker.py" />
<node name="talker10" pkg="test_rospy" type="talker.py" />
<node name="talker11" pkg="test_rospy" type="talker.py" />
<node name="talker12" pkg="test_rospy" type="talker.py" />
<node name="talker13" pkg="test_rospy" type="talker.py" />
<node name="talker14" pkg="test_rospy" type="talker.py" />
<node name="talker15" pkg="test_rospy" type="talker.py" />
<node name="talker16" pkg="test_rospy" type="talker.py" />
<node name="talker17" pkg="test_rospy" type="talker.py" />
<node name="talker18" pkg="test_rospy" type="talker.py" />
<node name="talker19" pkg="test_rospy" type="talker.py" />
<node name="talker20" pkg="test_rospy" type="talker.py" />
<node name="talker21" pkg="test_rospy" type="talker.py" />
<node name="talker22" pkg="test_rospy" type="talker.py" />
<node name="talker23" pkg="test_rospy" type="talker.py" />
<node name="talker24" pkg="test_rospy" type="talker.py" />
<node name="talker25" pkg="test_rospy" type="talker.py" />
<node name="talker26" pkg="test_rospy" type="talker.py" />
<node name="talker27" pkg="test_rospy" type="talker.py" />
<node name="talker28" pkg="test_rospy" type="talker.py" />
<node name="talker29" pkg="test_rospy" type="talker.py" />
<node name="talker30" pkg="test_rospy" type="talker.py" />
<node name="talker31" pkg="test_rospy" type="talker.py" />
<node name="talker32" pkg="test_rospy" type="talker.py" />
<node name="talker33" pkg="test_rospy" type="talker.py" />
<node name="talker34" pkg="test_rospy" type="talker.py" />
<node name="talker35" pkg="test_rospy" type="talker.py" />
<node name="talker36" pkg="test_rospy" type="talker.py" />
<node name="talker37" pkg="test_rospy" type="talker.py" />
<node name="talker38" pkg="test_rospy" type="talker.py" />
<node name="talker39" pkg="test_rospy" type="talker.py" />
<node name="talker40" pkg="test_rospy" type="talker.py" />
<node name="talker41" pkg="test_rospy" type="talker.py" />
<node name="talker42" pkg="test_rospy" type="talker.py" />
<node name="talker43" pkg="test_rospy" type="talker.py" />
<node name="talker44" pkg="test_rospy" type="talker.py" />
<node name="talker45" pkg="test_rospy" type="talker.py" />
<node name="talker46" pkg="test_rospy" type="talker.py" />
<node name="talker47" pkg="test_rospy" type="talker.py" />
<node name="talker48" pkg="test_rospy" type="talker.py" />
<node name="talker49" pkg="test_rospy" type="talker.py" />
<node name="talker50" pkg="test_rospy" type="talker.py" />
<node name="talker51" pkg="test_rospy" type="talker.py" />
<node name="talker52" pkg="test_rospy" type="talker.py" />
<node name="talker53" pkg="test_rospy" type="talker.py" />
<node name="talker54" pkg="test_rospy" type="talker.py" />
<node name="talker55" pkg="test_rospy" type="talker.py" />
<node name="talker56" pkg="test_rospy" type="talker.py" />
<node name="talker57" pkg="test_rospy" type="talker.py" />
<node name="talker58" pkg="test_rospy" type="talker.py" />
<node name="talker59" pkg="test_rospy" type="talker.py" />
<node name="talker60" pkg="test_rospy" type="talker.py" />
<node name="talker61" pkg="test_rospy" type="talker.py" />
<node name="talker62" pkg="test_rospy" type="talker.py" />
<node name="talker63" pkg="test_rospy" type="talker.py" />
<node name="talker64" pkg="test_rospy" type="talker.py" />
<node name="talker65" pkg="test_rospy" type="talker.py" />
<node name="talker66" pkg="test_rospy" type="talker.py" />
<node name="talker67" pkg="test_rospy" type="talker.py" />
<node name="talker68" pkg="test_rospy" type="talker.py" />
<node name="talker69" pkg="test_rospy" type="talker.py" />
<node name="talker70" pkg="test_rospy" type="talker.py" />
<node name="talker71" pkg="test_rospy" type="talker.py" />
<node name="talker72" pkg="test_rospy" type="talker.py" />
<node name="talker73" pkg="test_rospy" type="talker.py" />
<node name="talker74" pkg="test_rospy" type="talker.py" />
<node name="talker75" pkg="test_rospy" type="talker.py" />
<node name="talker76" pkg="test_rospy" type="talker.py" />
<node name="talker77" pkg="test_rospy" type="talker.py" />
<node name="talker78" pkg="test_rospy" type="talker.py" />
<node name="talker79" pkg="test_rospy" type="talker.py" />
<node name="talker80" pkg="test_rospy" type="talker.py" />
<node name="talker81" pkg="test_rospy" type="talker.py" />
<node name="talker82" pkg="test_rospy" type="talker.py" />
<node name="talker83" pkg="test_rospy" type="talker.py" />
<node name="talker84" pkg="test_rospy" type="talker.py" />
<node name="talker85" pkg="test_rospy" type="talker.py" />
<node name="talker86" pkg="test_rospy" type="talker.py" />
<node name="talker87" pkg="test_rospy" type="talker.py" />
<node name="talker88" pkg="test_rospy" type="talker.py" />
<node name="talker89" pkg="test_rospy" type="talker.py" />
<node name="talker90" pkg="test_rospy" type="talker.py" />
<node name="talker91" pkg="test_rospy" type="talker.py" />
<node name="talker92" pkg="test_rospy" type="talker.py" />
<node name="talker93" pkg="test_rospy" type="talker.py" />
<node name="talker94" pkg="test_rospy" type="talker.py" />
<node name="talker95" pkg="test_rospy" type="talker.py" />
<node name="talker96" pkg="test_rospy" type="talker.py" />
<node name="talker97" pkg="test_rospy" type="talker.py" />
<node name="talker98" pkg="test_rospy" type="talker.py" />
<node name="talker99" pkg="test_rospy" type="talker.py" />
<node name="listener" pkg="test_rospy" type="listener.py" />
<test test-name="sub_to_multiple_pubs" pkg="test_rospy" type="test_sub_to_multiple_pubs.py" />
</launch>

View File

@@ -0,0 +1,289 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Integration test for empty services to test serializers
## and transport
PKG = 'test_rospy'
NAME = 'basic_services'
import sys
import time
import math
import unittest
import rospy
import rostest
from test_rospy.srv import *
CONSTANTS_SERVICE_NAKED = 'constants_service_naked'
CONSTANTS_SERVICE_WRAPPED = 'constants_service_wrapped'
ADD_TWO_INTS_SERVICE_NAKED = 'a2i_naked'
ADD_TWO_INTS_SERVICE_WRAPPED = 'a2i_wrapped'
STRING_CAT_SERVICE_NAKED = 'string_lower_naked'
STRING_CAT_SERVICE_WRAPPED = 'string_lower_wrapped'
FAULTY_SERVICE = 'faulty_service'
FAULTY_SERVICE_RESULT = 'faulty_service_result'
#TODO:
STRING_SERVICE = 'string_service'
EMBEDDED_MSG_SERVICE = 'embedded_msg_service'
WAIT_TIMEOUT = 10.0 #s
def add_two_ints_wrapped(req):
from test_rosmaster.srv import AddTwoIntsResponse
return AddTwoIntsResponse(req.a + req.b)
def add_two_ints_naked(req):
return req.a + req.b
def string_cat_naked(req):
from std_msgs.msg import String
return String(req.str.data + req.str2.val)
def string_cat_wrapped(req):
from test_rospy.srv import StringStringResponse
from std_msgs.msg import String
return StringStringResponse(String(req.str.data + req.str2.val))
def handle_constants_wrapped(req):
cmr = ConstantsMultiplexRequest
Resp = ConstantsMultiplexResponse
if req.selection == cmr.SELECT_X:
# test w/o wrapper
return Resp(req.selection,
cmr.BYTE_X, cmr.INT32_X, cmr.UINT32_X, cmr.FLOAT32_X)
elif req.selection == cmr.SELECT_Y:
return Resp(req.selection,
cmr.BYTE_Y, cmr.INT32_Y, cmr.UINT32_Y, cmr.FLOAT32_Y)
elif req.selection == cmr.SELECT_Z:
return Resp(req.selection,
cmr.BYTE_Z, cmr.INT32_Z, cmr.UINT32_Z, cmr.FLOAT32_Z)
else:
print("test failed, req.selection not in (X,Y,Z)", req.selection)
def handle_constants_naked(req):
cmr = ConstantsMultiplexRequest
if req.selection == cmr.SELECT_X:
return req.selection,cmr.BYTE_X, cmr.INT32_X, cmr.UINT32_X, cmr.FLOAT32_X
elif req.selection == cmr.SELECT_Y:
return req.selection, cmr.BYTE_Y, cmr.INT32_Y, cmr.UINT32_Y, cmr.FLOAT32_Y
elif req.selection == cmr.SELECT_Z:
return req.selection, cmr.BYTE_Z, cmr.INT32_Z, cmr.UINT32_Z, cmr.FLOAT32_Z
else:
print("test failed, req.selection not in (X,Y,Z)", req.selection)
class UnexpectedException(Exception):
pass
class FaultyHandler(object):
def __init__(self):
self.test_call = False
def custom_error_handler(self, e, exc_type, exc_value, tb):
self.test_call = True
def call_handler(self, req):
raise UnexpectedException('Call raised an exception')
def result_handler(self, req):
resp = EmptyReqSrvResponse()
resp.fake_secret = 1 if self.test_call else 0
return resp
def services():
from test_rosmaster.srv import AddTwoInts
rospy.init_node(NAME)
s1 = rospy.Service(CONSTANTS_SERVICE_NAKED, ConstantsMultiplex, handle_constants_naked)
s2 = rospy.Service(CONSTANTS_SERVICE_WRAPPED, ConstantsMultiplex, handle_constants_wrapped)
s3 = rospy.Service(ADD_TWO_INTS_SERVICE_NAKED, AddTwoInts, add_two_ints_naked)
s4 = rospy.Service(ADD_TWO_INTS_SERVICE_WRAPPED, AddTwoInts, add_two_ints_wrapped)
s5 = rospy.Service(STRING_CAT_SERVICE_NAKED, StringString, string_cat_naked)
s6 = rospy.Service(STRING_CAT_SERVICE_WRAPPED, StringString, string_cat_wrapped)
faulty_handler = FaultyHandler()
s7 = rospy.Service(FAULTY_SERVICE, EmptySrv, faulty_handler.call_handler, error_handler=faulty_handler.custom_error_handler)
s8 = rospy.Service(FAULTY_SERVICE_RESULT, EmptyReqSrv, faulty_handler.result_handler)
rospy.spin()
class TestBasicServicesClient(unittest.TestCase):
# call with request instance style
def _test(self, name, srv, req):
rospy.wait_for_service(name, WAIT_TIMEOUT)
s = rospy.ServiceProxy(name, srv)
resp = s.call(req)
self.assert_(resp is not None)
return resp
# call with args style
def _test_req_naked(self, name, srv, args):
rospy.wait_for_service(name, WAIT_TIMEOUT)
s = rospy.ServiceProxy(name, srv)
resp = s.call(*args)
self.assert_(resp is not None)
return resp
# call with keyword style
def _test_req_kwds(self, name, srv, kwds):
rospy.wait_for_service(name, WAIT_TIMEOUT)
s = rospy.ServiceProxy(name, srv)
resp = s.call(**kwds)
self.assert_(resp is not None)
return resp
def test_calltype_mismatch(self):
try:
s = rospy.ServiceProxy(CONSTANTS_SERVICE_WRAPPED, ConstantsMultiplex)
s.call(EmptySrvRequest())
self.fail("rospy failed to raise TypeError when request type does not match service type")
except TypeError:
pass
def test_type_mismatch(self):
try:
self._test(CONSTANTS_SERVICE_WRAPPED, EmptySrv, EmptySrvRequest())
self.fail("Service failed to throw exception on type mismatch [sent EmptySrvRequest to ConstantsMultiplex service")
except rospy.ServiceException:
pass
def test_add_two_ints(self):
# add two ints checks single, integer return value, which is
# an interesting in the naked case
from test_rosmaster.srv import AddTwoInts, AddTwoIntsRequest
Cls = AddTwoInts
Req = AddTwoIntsRequest
for name in [ADD_TWO_INTS_SERVICE_NAKED, ADD_TWO_INTS_SERVICE_WRAPPED]:
resp_req = self._test(name, Cls, Req(1, 2))
resp_req_naked = self._test_req_naked(name, Cls, (1, 2))
resp_req_kwds = self._test_req_kwds(name, Cls, {'a': 3})
for resp in [resp_req, resp_req_naked, resp_req_kwds]:
self.assertEquals(3, resp.sum)
def test_String_String(self):
from std_msgs.msg import String
from test_rospy.srv import StringString, StringStringRequest
from test_rospy.msg import Val
Cls = StringString
Req = StringStringRequest
for name in [STRING_CAT_SERVICE_NAKED, STRING_CAT_SERVICE_WRAPPED]:
resp_req = self._test(name, Cls, Req(String('FOO'), Val('bar')))
resp_req_naked = self._test_req_naked(name, Cls, (String('FOO'), Val('bar'),))
resp_req_kwds = self._test_req_kwds(name, Cls, {'str': String('FOO'), 'str2': Val('bar')})
for resp in [resp_req, resp_req_naked, resp_req_kwds]:
self.assertEquals('FOObar', resp.str.data)
def test_String_String_unicode(self):
from std_msgs.msg import String
from test_rospy.srv import StringString, StringStringRequest
from test_rospy.msg import Val
Cls = StringString
Req = StringStringRequest
for name in [STRING_CAT_SERVICE_NAKED, STRING_CAT_SERVICE_WRAPPED]:
resp_req = self._test(name, Cls, Req(String(u'ロボット'), Val(u'机器人')))
resp_req_naked = self._test_req_naked(name, Cls, (String(u'ロボット'), Val(u'机器人'),))
resp_req_kwds = self._test_req_kwds(name, Cls, {'str': String(u'ロボット'), 'str2': Val(u'机器人')})
for resp in [resp_req, resp_req_naked, resp_req_kwds]:
self.assertEquals('ロボット机器人', resp.str.data) # if you send in unicode, you'll receive in str
def test_constants(self):
Cls = ConstantsMultiplex
Req = ConstantsMultiplexRequest
for name in [CONSTANTS_SERVICE_NAKED, CONSTANTS_SERVICE_WRAPPED]:
# test all three call forms
resp_req = self._test(name, Cls, Req(Req.SELECT_X))
resp_req_naked = self._test_req_naked(name, Cls, (Req.SELECT_X,))
resp_req_kwds = self._test_req_kwds(name, Cls, {'selection': Req.SELECT_X})
for resp in [resp_req, resp_req_naked, resp_req_kwds]:
self.assertEquals(ConstantsMultiplexResponse.CONFIRM_X,
resp.select_confirm)
self.assertEquals(Req.BYTE_X, resp.ret_byte)
self.assertEquals(Req.INT32_X, resp.ret_int32)
self.assertEquals(Req.UINT32_X, resp.ret_uint32)
self.assert_(math.fabs(Req.FLOAT32_X - resp.ret_float32) < 0.001)
resp = self._test(name, Cls,
ConstantsMultiplexRequest(Req.SELECT_Y))
self.assertEquals(ConstantsMultiplexResponse.CONFIRM_Y,
resp.select_confirm)
self.assertEquals(Req.BYTE_Y, resp.ret_byte)
self.assertEquals(Req.INT32_Y, resp.ret_int32)
self.assertEquals(Req.UINT32_Y, resp.ret_uint32)
self.assert_(math.fabs(Req.FLOAT32_Y - resp.ret_float32) < 0.001)
resp = self._test(name, Cls,
ConstantsMultiplexRequest(Req.SELECT_Z))
self.assertEquals(ConstantsMultiplexResponse.CONFIRM_Z,
resp.select_confirm)
self.assertEquals(Req.BYTE_Z, resp.ret_byte)
self.assertEquals(Req.INT32_Z, resp.ret_int32)
self.assertEquals(Req.UINT32_Z, resp.ret_uint32)
self.assert_(math.fabs(Req.FLOAT32_Z - resp.ret_float32) < 0.001)
def test_faulty_service(self):
rospy.wait_for_service(FAULTY_SERVICE, WAIT_TIMEOUT)
sproxy = rospy.ServiceProxy(FAULTY_SERVICE, EmptySrv)
rospy.wait_for_service(FAULTY_SERVICE_RESULT, WAIT_TIMEOUT)
sproxy_result = rospy.ServiceProxy(FAULTY_SERVICE_RESULT, EmptyReqSrv)
resp = sproxy_result.call(EmptyReqSrvRequest())
self.assertEquals(resp.fake_secret, 0)
try:
resp = sproxy.call(EmptySrvRequest())
self.assert_(False)
except rospy.ServiceException:
pass
resp = sproxy_result.call(EmptyReqSrvRequest())
self.assertEquals(resp.fake_secret, 1)
if __name__ == '__main__':
if '--service' in sys.argv:
services()
else:
rostest.run(PKG, 'rospy_basic_services', TestBasicServicesClient, sys.argv)

View File

@@ -0,0 +1,112 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Integration test for empty services to test serializers
## and transport
PKG = 'test_rospy'
NAME = 'test_param_api'
import sys
import time
import unittest
import rospy
import rostest
class TestClientParamApi(unittest.TestCase):
def test_param_api(self):
# test get_param_names
param_names = rospy.get_param_names()
for n in ['/param1', 'param1', '~param1', 'param_int', 'param_float']:
self.assert_(rospy.resolve_name(n) in param_names)
# test has_param
self.assert_(rospy.has_param('/run_id'))
self.assert_(rospy.has_param('/param1'))
self.assert_(rospy.has_param('param1'))
self.assert_(rospy.has_param('~param1'))
# test search_param
self.assertEquals(None, rospy.search_param('not_param1'))
self.assertEquals(rospy.resolve_name('~param1'), rospy.search_param('param1'))
self.assertEquals(rospy.resolve_name('parent_param'), rospy.search_param('parent_param'))
self.assertEquals("/global_param", rospy.search_param('global_param'))
# test get_param on params set in rostest file
self.assertEquals('global_param1', rospy.get_param('/param1'))
self.assertEquals('parent_param1', rospy.get_param('param1'))
self.assertEquals('private_param1', rospy.get_param('~param1'))
# - type tests
self.assertEquals(1, rospy.get_param('param_int'))
self.assertAlmostEquals(2., rospy.get_param('param_float'))
self.assertEquals(True, rospy.get_param('param_bool'))
self.assertEquals("hello world", rospy.get_param('param_str'))
# test default behavior get_param
try:
rospy.get_param('not_param1')
self.fail("should have raised KeyError")
except KeyError: pass
self.assertEquals('parent_param1', rospy.get_param('param1', 'foo'))
self.assertEquals('private_param1', rospy.get_param('~param1', 'foo'))
self.assertEquals('myval', rospy.get_param('not_param1', 'myval'))
self.assertEquals('myval', rospy.get_param('~not_param1', 'myval'))
self.assertEquals(None, rospy.get_param('not_param1', None))
self.assertEquals(None, rospy.get_param('~not_param1', None))
# test set/get roundtrips
vals = [ '1', 1, 1., [1, 2, 3, 4], {'a': 1, 'b': 2}]
for v in vals:
self.failIf(rospy.has_param("cp_param"))
try:
rospy.get_param('cp_param1')
self.fail("should have thrown KeyError")
except KeyError: pass
self.assertEquals(None, rospy.get_param('cp_param', None))
self.assertEquals("default", rospy.get_param('cp_param', "default"))
rospy.set_param("cp_param", v)
self.assert_(rospy.has_param("cp_param"))
self.assertEquals(v, rospy.get_param("cp_param"))
self.assertEquals(rospy.resolve_name('cp_param'), rospy.search_param('cp_param'))
# erase the param and recheck state
rospy.delete_param('cp_param')
self.failIf(rospy.has_param("cp_param"))
self.assertEquals(None, rospy.get_param('cp_param', None))
self.assertEquals("default", rospy.get_param('cp_param', "default"))
self.assertEquals(None, rospy.search_param('cp_param'))
if __name__ == '__main__':
rospy.init_node(NAME)
rostest.run(PKG, NAME, TestClientParamApi, sys.argv)

View File

@@ -0,0 +1,185 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Unit test of rospy.client APIs for parameter server access
PKG = 'test_rospy'
NAME = 'test_rospy_client_param_server'
import sys, time
import math
import unittest
import rospy
import rostest
from test_rospy.srv import *
def test_param_filter(params):
return [p for p in params if not p.startswith('/roslaunch') and p not in ['/run_id', '/rosdistro', '/rosversion']]
## Test the rospy.client parameter server API:
##- get_param
##- set_param
##- delete_param
##- has_param
##- get_param_names
class TestClientParamServer(unittest.TestCase):
## test get/has param against state initialized from rostest script
def test_get_has_param(self):
#test error conditions
try: rospy.get_param(None); self.fail("get_param(None) succeeded")
except: pass
try: rospy.get_param(''); self.fail("get_param('') succeeded")
except: pass
# should be keyerror
try: rospy.get_param('non-existent'); self.fail("get_param('non-existent') succeeded")
except: pass
try: rospy.has_param(None, 'foo'); self.fail("has_param(None) succeeded")
except: pass
try: rospy.has_param(''); self.fail("has_param('') succeeded")
except: pass
self.failIf(rospy.has_param('non-existent'), "has_param('non-existent') succeeded")
#validate get_param against values on the param server
rostest_tests = {
'string': "string",
'int0': 0,
'int10': 10,
'float0': 0.0,
'float10': 10.0,
"namespace/string": "namespaced string",
}
param_names = [rospy.resolve_name(k) for k in rostest_tests.keys()]
# test get parameter names
diff = set(param_names) ^ set(test_param_filter(rospy.get_param_names()))
self.failIf(diff, diff)
# test for existing and value
for k, v in rostest_tests.items():
self.assert_(rospy.has_param(k))
self.assert_(rospy.has_param(rospy.resolve_name(k)))
if not type(v) == float:
self.assertEqual(v, rospy.get_param(k))
self.assertEqual(v, rospy.get_param(rospy.resolve_name(k)))
else:
self.assertAlmostEqual(v, rospy.get_param(k), 1)
self.assertAlmostEqual(v, rospy.get_param(rospy.resolve_name(k)), 1)
def test_search_param(self):
try:
orig_caller_id = rospy.names.get_caller_id()
rospy.names._set_caller_id('/global_node')
self.assertEquals(None, rospy.search_param('search_param'))
rospy.set_param('/search_param', 1)
self.assertEquals('/search_param', rospy.search_param('search_param'))
rospy.names._set_caller_id('/level1/level2/relative_node')
self.assertEquals('/search_param', rospy.search_param('search_param'))
rospy.set_param('/level1/search_param', 2)
self.assertEquals('/level1/search_param', rospy.search_param('search_param'))
rospy.set_param('~search_param', 3)
# make sure that search starts in our private namespace first
self.assertEquals('/level1/level2/relative_node/search_param', rospy.search_param('search_param'))
finally:
rospy.names._set_caller_id(orig_caller_id)
def test_delete_param(self):
try: rospy.delete_param(None); self.fail("delete_param(None) succeeded")
except: pass
try: rospy.delete_param(''); self.fail("delete_param('') succeeded")
except: pass
rostest_tests = {
'dpstring': "string",
'dpint0': 0,
'dpint10': 10,
'dpfloat0': 0.0,
'dpfloat10': 10.0,
"dpnamespace/string": "namespaced string",
}
initial_params = rospy.get_param_names()
# implicitly depends on set param
for k, v in rostest_tests.items():
rospy.set_param(k, v)
# test delete
for k, v in rostest_tests.items():
self.assert_(rospy.has_param(k))
rospy.delete_param(k)
self.failIf(rospy.has_param(k))
self.failIf(rospy.has_param(rospy.resolve_name(k)))
try:
rospy.get_param(k)
self.fail("get_param should fail on deleted key")
except KeyError: pass
# make sure no new state
self.failIf(set(initial_params) ^ set(rospy.get_param_names()))
## test set_param separately
def test_set_param(self):
try: rospy.set_param(None, 'foo'); self.fail("set_param(None) succeeded")
except: pass
try: rospy.set_param('', 'foo'); self.fail("set_param('') succeeded")
except: pass
rostest_tests = {
'spstring': "string",
'spint0': 0,
'spint10': 10,
'spfloat0': 0.0,
'spfloat10': 10.0,
"spnamespace/string": "namespaced string",
}
initial_param_names = rospy.get_param_names()
param_names = [rospy.resolve_name(k) for k in rostest_tests.keys()]
for k, v in rostest_tests.items():
self.failIf(rospy.has_param(k))
self.failIf(rospy.has_param(rospy.resolve_name(k)))
rospy.set_param(k, v)
self.assert_(rospy.has_param(k))
self.assert_(rospy.has_param(rospy.resolve_name(k)))
self.assertEquals(v, rospy.get_param(k))
self.assertEquals(v, rospy.get_param(rospy.resolve_name(k)))
correct_state = set(initial_param_names + param_names)
self.failIf(correct_state ^ set(rospy.get_param_names()))
if __name__ == '__main__':
rospy.init_node(NAME)
rostest.run(PKG, NAME, TestClientParamServer, sys.argv)

View File

@@ -0,0 +1,184 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Integration test for empty services to test serializers
## and transport
from __future__ import print_function
PKG = 'test_rospy'
import sys
import time
import unittest
import gc
import weakref
import rospy
import rostest
from std_msgs.msg import String
from test_rospy.srv import EmptySrv
PUBTOPIC = 'test_unpublish_chatter'
SUBTOPIC = 'test_unsubscribe_chatter'
SERVICE = 'test_unregister_service'
TIMEOUT = 10.0 #seconds
_last_callback = None
def callback(data):
global _last_callback
print("message received", data.data)
_last_callback = data
try:
from xmlrpc.client import ServerProxy
except ImportError:
from xmlrpclib import ServerProxy
class TestDeregister(unittest.TestCase):
def test_unpublish(self):
node_proxy = ServerProxy(rospy.get_node_uri())
_, _, pubs = node_proxy.getPublications('/foo')
pubs = [p for p in pubs if p[0] != '/rosout']
self.assert_(not pubs, pubs)
print("Publishing ", PUBTOPIC)
pub = rospy.Publisher(PUBTOPIC, String, queue_size=1)
impl = weakref.ref(pub.impl)
topic = rospy.resolve_name(PUBTOPIC)
_, _, pubs = node_proxy.getPublications('/foo')
pubs = [p for p in pubs if p[0] != '/rosout']
self.assertEquals([[topic, String._type]], pubs, "Pubs were %s"%pubs)
# publish about 10 messages for fun
for i in range(0, 10):
pub.publish(String("hi [%s]"%i))
time.sleep(0.1)
# begin actual test by unsubscribing
pub.unregister()
# make sure no new messages are received in the next 2 seconds
timeout_t = time.time() + 2.0
while timeout_t < time.time():
time.sleep(1.0)
self.assert_(_last_callback is None)
# verify that close cleaned up master and node state
_, _, pubs = node_proxy.getPublications('/foo')
pubs = [p for p in pubs if p[0] != '/rosout']
self.assert_(not pubs, "Node still has pubs: %s"%pubs)
n = rospy.get_caller_id()
self.assert_(not rostest.is_publisher(topic, n), "publication is still active on master")
# verify that the impl was cleaned up
gc.collect()
self.assertIsNone(impl())
def test_unsubscribe(self):
global _last_callback
uri = rospy.get_node_uri()
node_proxy = ServerProxy(uri)
_, _, subscriptions = node_proxy.getSubscriptions('/foo')
self.assert_(not subscriptions, 'subscriptions present: %s'%str(subscriptions))
print("Subscribing to ", SUBTOPIC)
sub = rospy.Subscriber(SUBTOPIC, String, callback)
topic = rospy.resolve_name(SUBTOPIC)
_, _, subscriptions = node_proxy.getSubscriptions('/foo')
self.assertEquals([[topic, String._type]], subscriptions, "Subscriptions were %s"%subscriptions)
# wait for the first message to be received
timeout_t = time.time() + TIMEOUT
while _last_callback is None and time.time() < timeout_t:
time.sleep(0.1)
self.assert_(_last_callback is not None, "No messages received from talker")
# begin actual test by unsubscribing
sub.unregister()
# clear last callback data, i.e. last message received
_last_callback = None
timeout_t = time.time() + 2.0
# make sure no new messages are received in the next 2 seconds
while timeout_t < time.time():
time.sleep(1.0)
self.assert_(_last_callback is None)
# verify that close cleaned up master and node state
_, _, subscriptions = node_proxy.getSubscriptions('/foo')
self.assert_(not subscriptions, "Node still has subscriptions: %s"%subscriptions)
n = rospy.get_caller_id()
self.assert_(not rostest.is_subscriber(topic, n), "subscription is still active on master")
def test_unservice(self):
import rosgraph
master = rosgraph.Master('/test_dereg')
state = master.getSystemState()
_, _, srv = state
# filter out rosout services
#[['/rosout/set_logger_level', ['/rosout']], ['/rosout/get_loggers', ['/rosout']]]
srv = [s for s in srv if not s[0].startswith('/rosout/') and not s[0].endswith('/get_loggers') and not s[0].endswith('/set_logger_level')]
self.failIf(srv, srv)
print("Creating service ", SERVICE)
service = rospy.Service(SERVICE, EmptySrv, callback)
# we currently cannot interrogate a node's services, have to rely on master
# verify that master has service
state = master.getSystemState()
_, _, srv = state
srv = [s for s in srv if not s[0].startswith('/rosout/') and not s[0].endswith('/get_loggers') and not s[0].endswith('/set_logger_level')]
self.assertEquals(srv, [[rospy.resolve_name(SERVICE), [rospy.get_caller_id()]]])
# begin actual test by unsubscribing
service.shutdown()
time.sleep(1.0) # give API 1 second to sync with master
state = master.getSystemState()
_, _, srv = state
srv = [s for s in srv if not s[0].startswith('/rosout/') and not s[0].endswith('/get_loggers') and not s[0].endswith('/set_logger_level')]
self.failIf(srv, srv)
if __name__ == '__main__':
rospy.init_node('test_dereg', disable_rostime=True)
rostest.run(PKG, 'rospy_deregister', TestDeregister, sys.argv)

View File

@@ -0,0 +1,138 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Integration test for empty services to test serializers
## and transport
from __future__ import print_function
PKG = 'test_rospy'
NAME = 'test_embed_msg'
import sys
import time
import unittest
import rospy
import rostest
from std_msgs.msg import String, Int32
from test_rospy.msg import EmbedTest, Val, ArrayVal
PUBTOPIC = "chatter"
LPNODE = 'listenerpublisher'
LPTOPIC = 'listenerpublisher'
MSG = EmbedTest
TIMEOUT = 10.0 #seconds
class TestEmbedMsg(unittest.TestCase):
def setUp(self):
self.callback_data = None
def _test_embed_msg_callback(self, data):
self.callback_data = data
def test_embed_msg(self):
self.assert_(self.callback_data is None, "invalid test fixture")
# wait at most 5 seconds for listenerpublisher to be registered
timeout_t = time.time() + 5.0
while not rostest.is_subscriber(
rospy.resolve_name(PUBTOPIC),
rospy.resolve_name(LPNODE)) and time.time() < timeout_t:
time.sleep(0.1)
self.assert_(rostest.is_subscriber(
rospy.resolve_name(PUBTOPIC),
rospy.resolve_name(LPNODE)), "%s is not up"%LPNODE)
print("Publishing to ", PUBTOPIC)
pub = rospy.Publisher(PUBTOPIC, MSG)
rospy.Subscriber(LPTOPIC, MSG, self._test_embed_msg_callback)
# publish about 10 messages for fun
import random
val = random.randint(0, 109812312)
msg = "hi [%s]"%val
for i in range(0, 10):
# The test message could be better in terms of the values
# it assigns to leaf fields, but the main focus is trying
# to dig up edge conditions in the embeds, especially with
# respect to arrays and embeds.
pub.publish(
MSG(String(msg), Int32(val),
[Int32(val+1), Int32(val+2), Int32(val+3)],
Val(msg+msg),
[Val(msg), Val("two")],
[ArrayVal([Val("av1"), Val("av2")]), #[Val("%s"%i) for i in range(0, 10)]),
ArrayVal([]) #,[Val("%s"%i) for i in range(0, 10)]),
]
))
time.sleep(0.1)
# listenerpublisher is supposed to repeat our messages back onto /listenerpublisher,
# make sure we got it
self.assert_(self.callback_data is not None, "no callback data from listenerpublisher")
print("Got ", self.callback_data.str1.data, self.callback_data.int1.data)
errorstr = "callback msg field [%s] from listenerpublisher does not match"
self.assertEquals(msg, self.callback_data.str1.data,
errorstr%"str1.data")
self.assertEquals(val, self.callback_data.int1.data,
errorstr%"int1.data")
for i in range(1, 4):
self.assertEquals(val+i, self.callback_data.ints[i-1].data,
errorstr%"ints[i-1].data")
self.assertEquals(msg+msg, self.callback_data.val.val,
errorstr%"val.val")
self.assertEquals(msg, self.callback_data.vals[0].val,
errorstr%"vals[0].val")
self.assertEquals("two", self.callback_data.vals[1].val,
errorstr%"vals[1].val")
# #435: test array of arrays
self.assertEquals(2, len(self.callback_data.arrayval),
errorstr%"len arrayval")
self.assertEquals(2, len(self.callback_data.arrayval[0].vals),
errorstr%"len arrayval[0].vals")
self.assertEquals("av1", self.callback_data.arrayval[0].vals[0].val,
errorstr%"arrayval[0].vals[0].val")
self.assertEquals("av2", self.callback_data.arrayval[0].vals[1].val,
errorstr%"arrayval[0].vals[1].val")
self.assertEquals(0, len(self.callback_data.arrayval[1].vals),
errorstr%"len arrayval[1].vals")
if __name__ == '__main__':
rospy.init_node(NAME)
rostest.run(PKG, NAME, TestEmbedMsg, sys.argv)

View File

@@ -0,0 +1,121 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Integration test for empty services to test serializers
## and transport
PKG = 'test_rospy'
NAME = 'empty_service'
import sys, time
import unittest
import rospy, rostest
from test_rospy.srv import *
EMPTY_SERVICE = 'empty_service'
EMPTY_RETURN_SERVICE = 'empty_return_service'
EMPTY_REQ_SERVICE = 'empty_req_service'
EMPTY_RESP_SERVICE = 'empty_resp_service'
FAKE_SECRET = 123456
WAIT_TIMEOUT = 10.0 #s
def handle_empty(req):
print("Returning empty")
return EmptySrvResponse()
def handle_return_empty(req):
"print returning empty list"
return []
## handle empty request
def handle_empty_req(req):
print("Returning fake_secret")
return EmptyReqSrvResponse(FAKE_SECRET)
## handle empty response
def handle_empty_resp(req):
if req.fake_secret == FAKE_SECRET:
print("Request validated, returning empty")
return EmptyRespSrvResponse()
else:
print("Request did not validate, returning None")
def empty_service():
rospy.init_node(NAME)
s1 = rospy.Service(EMPTY_SERVICE, EmptySrv, handle_empty)
s2 = rospy.Service(EMPTY_REQ_SERVICE, EmptyReqSrv, handle_empty_req)
s3 = rospy.Service(EMPTY_RESP_SERVICE, EmptyRespSrv, handle_empty_resp)
s4 = rospy.Service(EMPTY_RETURN_SERVICE, EmptySrv, handle_return_empty)
rospy.spin()
class TestEmptyServiceClient(unittest.TestCase):
def _test(self, name, srv, req):
rospy.wait_for_service(name, WAIT_TIMEOUT)
s = rospy.ServiceProxy(name, srv)
resp = s.call(req)
self.assert_(resp is not None)
return resp
# test that __call__ and s.call() work with no-args on an empty request
def test_call_empty(self):
rospy.wait_for_service(EMPTY_REQ_SERVICE, WAIT_TIMEOUT)
s = rospy.ServiceProxy(EMPTY_REQ_SERVICE, EmptyReqSrv)
resp = s()
self.assertEquals(FAKE_SECRET, resp.fake_secret,
"fake_secret fields is not set as expected")
resp = s.call()
self.assertEquals(FAKE_SECRET, resp.fake_secret,
"fake_secret fields is not set as expected")
def test_empty(self):
self._test(EMPTY_SERVICE, EmptySrv, EmptySrvRequest())
# test that an empty return service handler can return an empty list
def test_return_empty(self):
self._test(EMPTY_RETURN_SERVICE, EmptySrv, EmptySrvRequest())
def test_empty_req(self):
resp = self._test(EMPTY_REQ_SERVICE, EmptyReqSrv,
EmptyReqSrvRequest())
self.assertEquals(FAKE_SECRET, resp.fake_secret,
"fake_secret fields is not set as expected")
def test_empty_resp(self):
self._test(EMPTY_RESP_SERVICE, EmptyRespSrv,
EmptyRespSrvRequest(FAKE_SECRET))
if __name__ == '__main__':
if '--service' in sys.argv:
empty_service()
else:
rostest.run(PKG, 'rospy_empty_service', TestEmptyServiceClient, sys.argv)

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
PKG = 'test_rospy'
NAME = 'test_latch'
import sys
import time
import unittest
from std_msgs.msg import String
class TestLatch(unittest.TestCase):
def setUp(self):
self.callback_invoked = {}
for i in range(0, 6):
self.callback_invoked[i] = False
def callback_args(self, msg, i):
self.assertEquals('foo', msg.data)
self.callback_invoked[i] = True
def callback(self, msg):
self.assertEquals('foo', msg.data)
self.callback_invoked[0] = True
def test_latch(self):
import rospy
# multi-part test. First check that we get latched message, then check
# that subscribers to same topic also receive latched message
# #1852
rospy.init_node(NAME)
s0 = rospy.Subscriber('s', String, self.callback)
# 20 seconds to receive first latched message
timeout_t = time.time() + 20.
print("waiting for 20 seconds")
while not self.callback_invoked[0] and \
not rospy.is_shutdown() and \
timeout_t > time.time():
time.sleep(0.2)
self.failIf(timeout_t < time.time(), "timeout exceeded")
self.failIf(rospy.is_shutdown(), "node shutdown")
self.assert_(self.callback_invoked[0], "callback not invoked")
# register three more callbacks, make sure they get invoked with message
# - callbacks are actually called inline, but in spirit of test, async callback is allowed
for i in range(1, 5):
self.failIf(self.callback_invoked[i])
s = rospy.Subscriber('s', String, self.callback_args, i)
timeout_t = time.time() + 0.5
while not self.callback_invoked[i] and \
not rospy.is_shutdown() and \
timeout_t > time.time():
time.sleep(0.1)
self.assert_(self.callback_invoked[i])
if __name__ == '__main__':
import rostest
rostest.run(PKG, NAME, TestLatch, sys.argv)

View File

@@ -0,0 +1,83 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
PKG = 'test_rospy'
NAME = 'test_latch_unsubscribe'
import os
import sys
import unittest
import psutil
from std_msgs.msg import String
def _get_connections(process_info):
if hasattr(process_info, 'connections'): # new naming
return process_info.connections()
elif hasattr(process_info, 'get_connections'): # old naming
return process_info.get_connections()
raise AttributeError('Wrong psutil version?')
def _get_connection_statii(process_info):
return (conn.status for conn in _get_connections(process_info))
class TestLatch(unittest.TestCase):
def setUp(self):
pass
def test_latch(self):
import rospy
proc_info = psutil.Process(os.getpid())
self.assertNotIn('CLOSE_WAIT', _get_connection_statii(proc_info),
'CLOSE_WAIT sockets already before the test. This '
'should not happen at all.')
rospy.init_node(NAME)
pub = rospy.Publisher('chatter', String, latch=True)
pub.publish(String("hello"))
rospy.sleep(0.5)
self.assertNotIn('CLOSE_WAIT', _get_connection_statii(proc_info),
'CLOSE_WAIT sockets after the subscriber exited. '
'(#107)')
rospy.sleep(1.5)
# also check for a second subscriber
self.assertNotIn('CLOSE_WAIT', _get_connection_statii(proc_info),
'CLOSE_WAIT sockets after the second subscriber '
'exited. (#107)')
if __name__ == '__main__':
import rostest
rostest.run(PKG, NAME, TestLatch, sys.argv)

View File

@@ -0,0 +1,89 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Simple talker demo that publishes std_msg/Strings to the 'chatter' topic
PKG = 'test_rospy'
NAME = 'test_node'
import sys
import rospy
import test_rosmaster.msg
# Copied from test_ros.test_node
#_required_publications = 'test_string_out', 'test_primitives_out', 'test_arrays_out', 'test_header_out'
#_required_subscriptions = 'test_string_in', 'test_primitives_in', 'test_arrays_in', 'test_header_in', 'probe_topic'
## pass-through callback that republishes message on \a pub.
## @param pub TopicPub: topic to republish incoming messages on
## @return fn: callback fn for TopicSub
def chain_callback(pub):
def chained_callback(data):
# special logic for handling TestHeader
if isinstance(data, test_rosmaster.msg.TestHeader):
if data.auto == 0:
new_data = test_rosmaster.msg.TestHeader()
# when auto is 0, must send 1234, 5678 as time
new_data.header.stamp = Time(1234, 5678)
# frame_id not really important
new_data.header.frame_id = 1234
else: # force auto-header timestamp
new_data = test_rosmaster.msg.TestHeader(None, rospy.caller_id(), data.auto)
data = new_data
data.caller_id = rospy.caller_id()
pub.publish(data)
def test_node():
# required publications
string_out = rospy.Publisher("test_string_out", test_rosmaster.msg.TestString)
primitives_out = rospy.Publisher("test_primitives_out", test_rosmaster.msg.TestPrimitives)
arrays_out = rospy.Publisher("test_arrays_out", test_rosmaster.msg.TestArrays)
header_out = rospy.Publisher("test_header_out", test_rosmaster.msg.TestHeader)
#required subs
rospy.Subscriber("test_string_in", test_rosmaster.msg.TestString, chain_callback(string_out))
rospy.Subscriber("test_primitives_in", test_rosmaster.msg.TestPrimitives, chain_callback(primitives_out))
rospy.Subscriber("test_arrays_in", test_rosmaster.msg.TestArrays, chain_callback(arrays_out))
rospy.Subscriber("test_header_in", test_rosmaster.msg.TestHeader, chain_callback(header_out))
# subscription with no publisher
probe_in = rospy.Subscriber("probe_topic", test_rosmaster.msg.TestString)
rospy.init_node(NAME)
rospy.spin()
if __name__ == '__main__':
test_node()

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Integration test for peer_subscribe_notify
from __future__ import print_function
PKG = 'test_rospy'
NAME = 'on_shutdown_test'
import sys
import time
import unittest
import rospy
import rostest
from std_msgs.msg import String
class TestOnShutdown(unittest.TestCase):
def __init__(self, *args):
super(TestOnShutdown, self).__init__(*args)
self.success = False
def callback(self, data):
print(rospy.get_caller_id(), "I heard %s"%data.data)
#greetings is only sent over peer_publish callback, so hearing it is a success condition
if "I'm dead" in data.data:
self.success = True
def test_notify(self):
rospy.Subscriber("chatter", String, self.callback)
rospy.init_node(NAME, anonymous=True)
timeout_t = time.time() + 10.0*1000 #10 seconds
while not rospy.is_shutdown() and not self.success and time.time() < timeout_t:
time.sleep(0.1)
self.assert_(self.success, str(self.success))
if __name__ == '__main__':
rostest.rosrun(PKG, NAME, TestOnShutdown, sys.argv)

View File

@@ -0,0 +1,100 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Integration test for empty services to test serializers
## and transport
from __future__ import print_function
PKG = 'test_rospy'
NAME = 'test_pubsub_order'
import sys
import time
import unittest
import rospy
import rostest
from std_msgs.msg import String
PUBTOPIC = "chatter"
LPNODE = 'listenerpublisher'
LPTOPIC = 'listenerpublisher'
MSG = String
TIMEOUT = 10.0 #seconds
class TestPubSubOrder(unittest.TestCase):
def setUp(self):
self.callback_data = None
def _test_subscriber_first_callback(self, data):
self.callback_data = data
## Test subscriber first makes sure that if a subscriber is up first
## that it is able to successfully receive messages from a new publisher
def test_subscriber_first(self):
self.assert_(self.callback_data is None, "invalid test fixture")
# wait at most 5 seconds for listenerpublisher to be registered
timeout_t = time.time() + 5.0
while not rostest.is_subscriber(
rospy.resolve_name(PUBTOPIC),
rospy.resolve_name(LPNODE)) and time.time() < timeout_t:
time.sleep(0.1)
self.assert_(rostest.is_subscriber(
rospy.resolve_name(PUBTOPIC),
rospy.resolve_name(LPNODE)), "%s is not up"%LPNODE)
print("Publishing to ", PUBTOPIC)
pub = rospy.Publisher(PUBTOPIC, MSG)
rospy.Subscriber(LPTOPIC, MSG, self._test_subscriber_first_callback)
# publish about 10 messages for fun
import random
val = random.randint(0, 109812312)
msg = "hi [%s]"%val
for i in range(0, 10):
pub.publish(MSG(msg))
time.sleep(0.1)
# listenerpublisher is supposed to repeat our messages back onto /listenerpublisher,
# make sure we got it
self.assert_(self.callback_data is not None, "no callback data from listenerpublisher")
self.assertEquals(msg, self.callback_data.data, "callback data from listenerpublisher does not match")
if __name__ == '__main__':
rospy.init_node(NAME)
rostest.run(PKG, NAME, TestPubSubOrder, sys.argv)

View File

@@ -0,0 +1,355 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
import random
import rosunit
from threading import Thread
class TestTask(Thread):
def __init__(self, task):
Thread.__init__(self)
self.task = task
self.success = False
self.done = False
self.value = None
def run(self):
try:
print("STARTING TASK")
self.value = self.task()
print("TASK HAS COMPLETED")
self.success = True
except:
import traceback
traceback.print_exc()
self.done = True
class TestRospyClientOnline(unittest.TestCase):
def __init__(self, *args):
unittest.TestCase.__init__(self, *args)
import rospy
rospy.init_node('test_rospy_online')
def test_log(self):
# we can't do anything fancy here like capture stdout as rospy
# grabs the streams before we do. Instead, just make sure the
# routines don't crash.
real_stdout = sys.stdout
real_stderr = sys.stderr
try:
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
sys.stdout = StringIO()
sys.stderr = StringIO()
import rospy
rospy.loginfo("test 1")
self.assert_("test 1" in sys.stdout.getvalue())
rospy.logwarn("test 2")
self.assert_("[WARN]" in sys.stderr.getvalue())
self.assert_("test 2" in sys.stderr.getvalue())
sys.stderr = StringIO()
rospy.logerr("test 3")
self.assert_("[ERROR]" in sys.stderr.getvalue())
self.assert_("test 3" in sys.stderr.getvalue())
sys.stderr = StringIO()
rospy.logfatal("test 4")
self.assert_("[FATAL]" in sys.stderr.getvalue())
self.assert_("test 4" in sys.stderr.getvalue())
# logXXX_throttle
for i in range(3):
sys.stdout = StringIO()
rospy.loginfo_throttle(3, "test 1")
if i == 0:
self.assert_("test 1" in sys.stdout.getvalue())
rospy.sleep(rospy.Duration(1))
elif i == 1:
self.assert_("" == sys.stdout.getvalue())
rospy.sleep(rospy.Duration(2))
else:
self.assert_("test 1" in sys.stdout.getvalue())
for i in range(3):
sys.stderr = StringIO()
rospy.logwarn_throttle(3, "test 2")
if i == 0:
self.assert_("test 2" in sys.stderr.getvalue())
rospy.sleep(rospy.Duration(1))
elif i == 1:
self.assert_("" == sys.stderr.getvalue())
rospy.sleep(rospy.Duration(2))
else:
self.assert_("test 2" in sys.stderr.getvalue())
for i in range(3):
sys.stderr = StringIO()
rospy.logerr_throttle(3, "test 3")
if i == 0:
self.assert_("test 3" in sys.stderr.getvalue())
rospy.sleep(rospy.Duration(1))
elif i == 1:
self.assert_("" == sys.stderr.getvalue())
rospy.sleep(rospy.Duration(2))
else:
self.assert_("test 3" in sys.stderr.getvalue())
for i in range(3):
sys.stderr = StringIO()
rospy.logfatal_throttle(3, "test 4")
if i == 0:
self.assert_("test 4" in sys.stderr.getvalue())
rospy.sleep(rospy.Duration(1))
elif i == 1:
self.assert_("" == sys.stderr.getvalue())
rospy.sleep(rospy.Duration(2))
else:
self.assert_("test 4" in sys.stderr.getvalue())
finally:
sys.stdout = real_stdout
sys.stderr = real_stderr
def test_wait_for_service(self):
# lazy-import for coverage
import rospy
import time
# test wait for service in success case
def task1():
rospy.wait_for_service('add_two_ints')
timeout_t = time.time() + 5.
t1 = TestTask(task1)
t1.start()
while not t1.done and time.time() < timeout_t:
time.sleep(0.5)
self.assert_(t1.success)
# test wait for service with timeout in success case
def task2():
rospy.wait_for_service('add_two_ints', timeout=1.)
timeout_t = time.time() + 5.
t2 = TestTask(task2)
t2.start()
while not t2.done and time.time() < timeout_t:
time.sleep(0.5)
self.assert_(t2.success)
# test wait for service in failure case
def task3():
# #2842 raising bounds from .1 to .3 for amazon VM
rospy.wait_for_service('fake_service', timeout=0.3)
timeout_t = time.time() + 2.
t3 = TestTask(task3)
t3.start()
while not t3.done and time.time() < timeout_t:
time.sleep(0.5)
self.assert_(t3.done)
self.failIf(t3.success)
def test_ServiceProxy_wait_for_service(self):
"""
Test ServiceProxy.wait_for_service
"""
# lazy-import for coverage
import rospy
import time
import test_rosmaster.srv
# test wait for service in success case
proxy = rospy.ServiceProxy('add_two_ints', test_rosmaster.srv.AddTwoInts)
class ProxyTask(object):
def __init__(self, proxy, timeout=None):
self.proxy = proxy
self.timeout = timeout
def __call__(self):
if self.timeout is None:
self.proxy.wait_for_service()
else:
self.proxy.wait_for_service(timeout=self.timeout)
timeout_t = time.time() + 5.
t1 = TestTask(ProxyTask(proxy))
t1.start()
while not t1.done and time.time() < timeout_t:
time.sleep(0.5)
self.assert_(t1.success)
# test wait for service with timeout in success case
timeout_t = time.time() + 5.
t2 = TestTask(ProxyTask(proxy, timeout=1.))
t2.start()
while not t2.done and time.time() < timeout_t:
time.sleep(0.5)
self.assert_(t2.success)
# test wait for service in failure case
fake_proxy = rospy.ServiceProxy('fake_service', test_rosmaster.srv.AddTwoInts)
timeout_t = time.time() + 2.
t3 = TestTask(ProxyTask(fake_proxy, timeout=0.1))
t3.start()
while not t3.done and time.time() < timeout_t:
time.sleep(0.5)
self.assert_(t3.done)
self.failIf(t3.success)
def test_sleep(self):
import rospy
import time
t = time.time()
rospy.sleep(0.1)
dur = time.time() - t
# #2842 raising bounds from .01 to .03 for amazon VM
# make sure sleep is approximately right
self.assert_(abs(dur - 0.1) < 0.03, dur)
t = time.time()
rospy.sleep(rospy.Duration.from_sec(0.1))
dur = time.time() - t
# make sure sleep is approximately right
self.assert_(abs(dur - 0.1) < 0.03, dur)
# sleep for neg duration
t = time.time()
rospy.sleep(rospy.Duration.from_sec(-10.))
dur = time.time() - t
# make sure returned immediately
self.assert_(abs(dur) < 0.1, dur)
def test_Rate(self):
import rospy
import time
t = time.time()
count = 0
r = rospy.Rate(10)
for x in range(10):
r.sleep()
dur = time.time() - t
# make sure sleep is approximately right
self.assert_(abs(dur - 1.0) < 0.5, dur)
def test_param_server(self):
# this isn't a parameter server test, just checking that the rospy bindings work
import rospy
try:
rospy.get_param('not_a_param')
self.fail("should have raised KeyError")
except KeyError: pass
self.assertEquals('default_val', rospy.get_param('not_a_param', 'default_val') )
p = rospy.get_param('/param')
self.assertEquals("value", p)
p = rospy.get_param('param')
self.assertEquals("value", p)
p = rospy.get_param('/group/param')
self.assertEquals("group_value", p)
p = rospy.get_param('group/param')
self.assertEquals("group_value", p)
self.assertEquals('/param', rospy.search_param('param'))
names = rospy.get_param_names()
self.assert_('/param' in names)
self.assert_('/group/param' in names)
for p in ['/param', 'param', 'group/param', '/group/param']:
self.assert_(rospy.has_param(p))
rospy.set_param('param2', 'value2')
self.assert_(rospy.has_param('param2'))
self.assertEquals('value2', rospy.get_param('param2'))
rospy.delete_param('param2')
self.failIf(rospy.has_param('param2'))
try:
rospy.get_param('param2')
self.fail("should have raised KeyError")
except KeyError: pass
def test_wait_for_message(self):
# lazy-import for coverage
import rospy
import std_msgs.msg
import time
# test standard wait for message
def task1():
return rospy.wait_for_message('chatter', std_msgs.msg.String)
timeout_t = time.time() + 5.
t1 = TestTask(task1)
t1.start()
while not t1.done and time.time() < timeout_t:
time.sleep(0.5)
self.assert_(t1.success)
self.assert_('hello' in t1.value.data)
# test wait for message with timeout
def task2():
return rospy.wait_for_message('chatter', std_msgs.msg.String, timeout=2.)
timeout_t = time.time() + 5.
t2 = TestTask(task2)
t2.start()
while not t2.done and time.time() < timeout_t:
time.sleep(0.5)
self.assert_(t2.success)
self.assert_('hello' in t2.value.data)
# test wait for message with timeout FAILURE
def task3():
# #2842 raising bounds from .1 to .3 for amazon VM
return rospy.wait_for_message('fake_topic', std_msgs.msg.String, timeout=.3)
timeout_t = time.time() + 2.
t3 = TestTask(task3)
t3.start()
while not t3.done and time.time() < timeout_t:
time.sleep(0.5)
self.failIf(t3.success)
self.assert_(t3.done)
self.assert_(t3.value is None)
if __name__ == '__main__':
rosunit.unitrun('test_rospy', sys.argv[0], TestRospyClientOnline, coverage_packages=['rospy.client', 'rospy.msproxy'])

View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function
import os
import sys
import unittest
import time
import rosunit
from threading import Thread
class TestRospyTimerOnline(unittest.TestCase):
def __init__(self, *args):
unittest.TestCase.__init__(self, *args)
import rospy
rospy.init_node('test_rospy_timer_online')
self.timer_callbacks = 0
self.timer_event = None
def test_sleep(self):
import rospy
import time
t = time.time()
rospy.sleep(0.1)
dur = time.time() - t
# #2842 raising bounds from .01 to .03 for amazon VM
# make sure sleep is approximately right
self.assert_(abs(dur - 0.1) < 0.03, dur)
t = time.time()
rospy.sleep(rospy.Duration.from_sec(0.1))
dur = time.time() - t
# make sure sleep is approximately right
self.assert_(abs(dur - 0.1) < 0.03, dur)
# sleep for neg duration
t = time.time()
rospy.sleep(rospy.Duration.from_sec(-10.))
dur = time.time() - t
# make sure returned immediately
self.assert_(abs(dur) < 0.1, dur)
def test_Rate(self):
import rospy
import time
t = time.time()
count = 0
r = rospy.Rate(10)
for x in range(10):
r.sleep()
dur = time.time() - t
# make sure sleep is approximately right
self.assert_(abs(dur - 1.0) < 0.5, dur)
def _Timer_callback(self, event):
self.timer_callbacks += 1
self.timer_event = event
def callback(event):
print('last_expected: ', event.last_expected)
print('last_real: ', event.last_real)
print('current_expected: ', event.current_expected)
print('current_real: ', event.current_real)
print('current_error: ', (event.current_real - event.current_expected).to_sec())
print('profile.last_duration:', event.last_duration)
if event.last_real:
print('last_error: ', (event.last_real - event.last_expected).to_sec(), 'secs')
def test_Timer(self):
import rospy
timer = rospy.Timer(rospy.Duration(1), self._Timer_callback)
time.sleep(10)
timer.shutdown()
# make sure we got an approximately correct number of callbacks
self.assert_(abs(self.timer_callbacks - 10) < 2)
# make sure error is approximately correct. the Timer
# implementation tracks error in accumulated real time.
ev = self.timer_event
self.assert_(ev is not None)
self.assert_(abs((ev.current_real - ev.current_expected).to_sec()) < 2.)
if __name__ == '__main__':
rosunit.unitrun('test_rospy', sys.argv[0], TestRospyTimerOnline, coverage_packages=['rospy.timer'])

View File

@@ -0,0 +1,91 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Integration test for empty services to test serializers
## and transport
PKG = 'test_rospy'
NAME = 'empty_service'
import sys, time
import unittest
import rostest
class TestServiceFailure(unittest.TestCase):
def test_persistent(self):
# fail_two_ints succeeds unless the first argument is -1.
# this makes sure, in the persistent case, that the proxy handle remains valid after a call
from test_rosmaster.srv import AddTwoInts
import rospy
rospy.wait_for_service('fail_two_ints', 10.)
p = rospy.ServiceProxy('fail_two_ints', AddTwoInts, persistent=True)
for a in [1, -1, 1, -1, -1, -1, -1, 1]:
try:
resp = p(a, 1)
if a == 1:
self.assertEquals(resp.sum, 2)
else:
self.fail("service call should have failed: %s,%s, %s"%(a, 1, resp.sum))
except rospy.ServiceException as e:
if a == -1:
# expected
pass
else:
self.fail("service call failed when it shouldn't have: %s"%str(e))
def test_non_persistent(self):
# fail_two_ints succeeds unless the first argument is -1.
# this makes sure, in the non-persistent case, that the proxy handle remains valid after a call
from test_rosmaster.srv import AddTwoInts
import rospy
rospy.wait_for_service('fail_two_ints', 10.)
p = rospy.ServiceProxy('fail_two_ints', AddTwoInts)
for a in [1, -1, 1, -1, -1, -1, -1, 1]:
try:
resp = p(a, 1)
if a == 1:
self.assertEquals(resp.sum, 2)
else:
self.fail("service call should have failed")
except rospy.ServiceException:
if a == -1:
# expected
pass
else:
self.fail("service call should have failed")
if __name__ == '__main__':
rostest.run(PKG, 'rospy_service_failure', TestServiceFailure, sys.argv)

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Integration test for empty services to test serializers
## and transport
PKG = 'test_rospy'
import sys, time
import unittest
import rospy, rostest
from test_rospy.srv import *
SERVICE_BEFORE = 'service_order_before'
SERVICE_AFTER = 'service_order_after'
FAKE_SECRET = 123456
WAIT_TIMEOUT = 10.0 #s
def handle_empty_req(req):
print("Returning fake_secret")
return EmptyReqSrvResponse(FAKE_SECRET)
def service_before():
s = rospy.Service(SERVICE_BEFORE, EmptyReqSrv, handle_empty_req)
rospy.init_node('service_before')
rospy.spin()
# #530: verify that init_node can occur after service declarations
def service_after():
rospy.init_node('service_after')
s = rospy.Service(SERVICE_AFTER, EmptyReqSrv, handle_empty_req)
rospy.spin()
class TestServiceOrder(unittest.TestCase):
def _test(self, name, srv, req):
rospy.wait_for_service(name, WAIT_TIMEOUT)
s = rospy.ServiceProxy(name, srv)
resp = s.call(req)
self.assert_(resp is not None)
return resp
def test_before(self):
resp = self._test(SERVICE_BEFORE, EmptyReqSrv,
EmptyReqSrvRequest())
self.assertEquals(FAKE_SECRET, resp.fake_secret,
"fake_secret fields is not set as expected")
def test_after(self):
resp = self._test(SERVICE_AFTER, EmptyReqSrv,
EmptyReqSrvRequest())
self.assertEquals(FAKE_SECRET, resp.fake_secret,
"fake_secret fields is not set as expected")
if __name__ == '__main__':
if '--before' in sys.argv:
service_before()
elif '--after' in sys.argv:
service_after()
else:
rostest.run(PKG, 'rospy_service_decl_order', TestServiceOrder, sys.argv)

View File

@@ -0,0 +1,107 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2013, Open Source Robotics Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Open Source Robotics Foundation, Inc. nor
# the names of its contributors may be used to endorse or promote
# products derived from this software without specific prior
# written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Integration test for subscribing to a topic with multiple publishers
from __future__ import print_function
PKG = 'test_rospy'
NAME = 'test_sub_to_multiple_pubs'
import socket
import sys
import time
import unittest
try:
from xmlrpc.client import ServerProxy
except ImportError:
from xmlrpclib import ServerProxy
import rosgraph
import rospy
import rostest
TOPIC = '/chatter'
TALKER_NODE = 'talker%d'
NUMBER_OF_TALKERS = 99
LISTENER_NODE = 'listener'
class TestPubSubToMultiplePubs(unittest.TestCase):
def test_subscribe_to_multiple_publishers(self):
# wait so that all connections are established
time.sleep(1.0)
# ensure that publishers are publishing
for i in range(1, NUMBER_OF_TALKERS + 1):
self.assert_(rostest.is_publisher(
rospy.resolve_name(TOPIC),
rospy.resolve_name(TALKER_NODE % i)), 'talker node %d is not up' % i)
# ensure that subscriber is subscribed
self.assert_(rostest.is_subscriber(
rospy.resolve_name(TOPIC),
rospy.resolve_name(LISTENER_NODE)), 'listener node is not up')
# check number of connections from subscriber to the topic
connections = 0
master = rosgraph.Master(NAME)
node_api = master.lookupNode(LISTENER_NODE)
if not node_api:
self.assert_(False, 'cannot contact [%s]: unknown node' % LISTENER_NODE)
socket.setdefaulttimeout(5.0)
node = ServerProxy(node_api)
code, _, businfo = node.getBusInfo(NAME)
if code != 1:
self.assert_(False, 'cannot get node information')
if businfo:
for info in businfo:
topic = info[4]
if len(info) > 5:
connected = info[5]
else:
connected = True # backwards compatibility
if connected:
if topic == TOPIC:
connections += 1
self.assert_(connections == NUMBER_OF_TALKERS, 'Found only %d connections instead of %d' % (connections, NUMBER_OF_TALKERS))
if __name__ == '__main__':
rospy.init_node(NAME)
rostest.run(PKG, NAME, TestPubSubToMultiplePubs, sys.argv)

View File

@@ -0,0 +1,393 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
try:
from cStringIO import StringIO
except ImportError:
from io import BytesIO as StringIO
import time
import random
import math
from roslib.message import SerializationError
class TestGenmsgPy(unittest.TestCase):
def test_PythonKeyword(self):
from test_rospy.msg import PythonKeyword
# the md5sum is pulled from the c++ message generator. The
# test here is that the Python msg generator didn't
# accidentally mutate a md5sum based on a message that has its
# fieldname remapped.
self.assertEquals(PythonKeyword._md5sum, "1330d6bbfad8e75334346fec949d5133")
## Utility for testing roundtrip serialization
## @param orig Message to test roundtrip serialization of
## @param blank Uninitialized instance of message to deserialize into
## @param float bool: if True, use almostEquals instead of equals
## comparison. This variant assumes only data field is named
## 'data'
def _test_ser_deser(self, orig, blank, float=False):
b = StringIO()
orig.serialize(b)
blank.deserialize(b.getvalue())
if not float:
self.assertEquals(orig, blank, str(orig)+" != "+str(blank))
else:
self.assertAlmostEquals(orig.data, blank.data, 5)
## #2133/2152
def test_test_rospy_TransitiveImport(self):
from test_rospy.msg import TransitiveImport
m = TransitiveImport()
# invoking serialize should be enough to expose issue. The bug
# was that genmsg_py was failing to include the imports of
# embedded messages. Because messages are flattened, this
# causes ImportErrors.
self._test_ser_deser(m, TransitiveImport())
def test_test_rospy_TestFixedArray(self):
from test_rospy.msg import TestFixedArray
m = TestFixedArray()
self.assertEquals([0.], m.f32_1)
self.assertEquals([0., 0., 0.], m.f32_3)
self.assertEquals([0.], m.f64_1)
self.assertEquals([0., 0., 0.], m.f64_3)
self.assertEquals([0], m.i8_1)
self.assertEquals([0, 0, 0], m.i8_3)
self.assertEquals(chr(0), m.u8_1)
self.assertEquals(chr(0)*3, m.u8_3)
self.assertEquals([0], m.i32_1)
self.assertEquals([0, 0, 0], m.i32_3)
self.assertEquals([0], m.u32_1)
self.assertEquals([0, 0, 0], m.u32_3)
self.assertEquals([''], m.s_1)
self.assertEquals(['', '', ''], m.s_3)
self._test_ser_deser(m, TestFixedArray())
m = TestFixedArray(i32_1 = [1])
c = TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals((1,), c.i32_1)
m = TestFixedArray(i32_3 = [-3, 2, 10])
c = TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals((-3, 2, 10), c.i32_3)
m = TestFixedArray(u32_1 = [1234])
c = TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals((1234,), c.u32_1)
m = TestFixedArray(u32_3 = [3, 2, 10])
c = TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals((3, 2, 10), c.u32_3)
# this could potentially fail due to floating point lossiness
m,c = TestFixedArray(f32_1 = [2.]), TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals((2.,), c.f32_1)
m,c = TestFixedArray(f32_3 = [1., 2., 3.]), TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals((1., 2., 3.), c.f32_3)
m,c = TestFixedArray(u8_1 = 'x'), TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals('x', c.u8_1)
m,c = TestFixedArray(u8_3 = 'xyz'), TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals('xyz', c.u8_3)
m,c = TestFixedArray(s_1 = ['']), TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals([''], c.s_1)
m,c = TestFixedArray(s_1 = ['blah blah blah']), TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals(['blah blah blah',], c.s_1)
m = TestFixedArray(s_3 = ['', 'x', 'xyz'])
c = TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals(['', 'x', 'xyz'], c.s_3)
for v in [True, False]:
m = TestFixedArray(b_1 = [v])
c = TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals([v], c.b_1)
m = TestFixedArray(b_3 = [True, False, True])
c = TestFixedArray()
self._test_ser_deser(m, c)
self.assertEquals([True, False, True], c.b_3)
#TODO: enable tests for auto-convert of uint8[] to string
def test_test_rospy_TestConstants(self):
from test_rospy.msg import TestConstants
self.assertEquals(-123.0, TestConstants.A)
self.assertEquals(124.0, TestConstants.B)
self.assertEquals(125.0, TestConstants.C)
self.assertEquals(123, TestConstants.X)
self.assertEquals(-123, TestConstants.Y)
self.assertEquals(124, TestConstants.Z)
self.assertEquals("'hi", TestConstants.SINGLEQUOTE)
self.assertEquals('"hello" there', TestConstants.DOUBLEQUOTE)
self.assertEquals('"hello" \'goodbye\'', TestConstants.MULTIQUOTE)
self.assertEquals('foo', TestConstants.FOO)
self.assertEquals('"#comments" are ignored, and leading and trailing whitespace removed',TestConstants.EXAMPLE)
self.assertEquals('strip', TestConstants.WHITESPACE)
self.assertEquals('', TestConstants.EMPTY)
self.assertEquals(True, TestConstants.TRUE)
self.assertEquals(False, TestConstants.FALSE)
def test_std_msgs_empty(self):
from std_msgs.msg import Empty
self.assertEquals(Empty(), Empty())
self._test_ser_deser(Empty(), Empty())
def test_std_msgs_Bool(self):
from std_msgs.msg import Bool
self.assertEquals(Bool(), Bool())
self._test_ser_deser(Bool(), Bool())
# default value should be False
self.assertEquals(False, Bool().data)
# test various constructor permutations
for v in [True, False]:
self.assertEquals(Bool(v), Bool(v))
self.assertEquals(Bool(v), Bool(data=v))
self.assertEquals(Bool(data=v), Bool(data=v))
self.assertNotEquals(Bool(True), Bool(False))
self._test_ser_deser(Bool(True), Bool())
self._test_ser_deser(Bool(False), Bool())
# validate type cast to bool
blank = Bool()
b = StringIO()
Bool(True).serialize(b)
blank.deserialize(b.getvalue())
self.assert_(blank.data)
self.assert_(type(blank.data) == bool)
b = StringIO()
Bool(True).serialize(b)
blank.deserialize(b.getvalue())
self.assert_(blank.data)
self.assert_(type(blank.data) == bool)
def test_std_msgs_String(self):
from std_msgs.msg import String
self.assertEquals(String(), String())
self.assertEquals('', String().data)
# default value should be empty string
self.assertEquals(String(''), String())
self.assertEquals(String(''), String(''))
self.assertEquals(String('foo'), String('foo'))
self.assertEquals(String('foo'), String(data='foo'))
self.assertEquals(String(data='foo'), String(data='foo'))
self.assertNotEquals(String('foo'), String('bar'))
self.assertNotEquals(String('foo'), String(data='bar'))
self.assertNotEquals(String(data='foo'), String(data='bar'))
self._test_ser_deser(String(''), String())
self._test_ser_deser(String('a man a plan a canal panama'), String())
def test_std_msgs_SignedInt(self):
from std_msgs.msg import Int8, Int16, Int32, Int64
for cls in [Int8, Int16, Int32, Int64]:
v = random.randint(1, 127)
self.assertEquals(cls(), cls())
self.assertEquals(0, cls().data)
self.assertEquals(cls(), cls(0))
self.assertEquals(cls(0), cls(0))
self.assertEquals(cls(v), cls(v))
self.assertEquals(cls(-v), cls(-v))
self.assertEquals(cls(v), cls(data=v))
self.assertEquals(cls(data=v), cls(data=v))
self.assertNotEquals(cls(v), cls())
self.assertNotEquals(cls(data=v), cls(data=-v))
self.assertNotEquals(cls(data=v), cls(data=v-1))
self.assertNotEquals(cls(data=v), cls(v-1))
self.assertNotEquals(cls(v), cls(v-1))
self._test_ser_deser(cls(), cls())
self._test_ser_deser(cls(0), cls())
self._test_ser_deser(cls(-v), cls())
self._test_ser_deser(cls(v), cls())
# rospy currently does not spot negative overflow due to the fact that Python's struct doesn't either
widths = [(8, Int8), (16, Int16), (32, Int32), (64, Int64)]
for w, cls in widths:
maxp = long(math.pow(2, w-1)) - 1
maxn = -long(math.pow(2, w-1)) + 1
self._test_ser_deser(cls(maxp), cls())
self._test_ser_deser(cls(maxn), cls())
try:
cls(maxp+1)._check_types()
self.fail("check_types should have noted width error[%s]: %s, %s"%(w, maxp+1, cls.__name__))
except SerializationError: pass
try:
cls(maxn-1)._check_types()
self.fail("check_types should have noted width error[%s]: %s, %s"%(w, maxn-1, cls.__name__))
except SerializationError: pass
def test_std_msgs_UnsignedInt(self):
from std_msgs.msg import UInt8, UInt16, UInt32, UInt64
for cls in [UInt8, UInt16, UInt32, UInt64]:
v = random.randint(1, 127)
self.assertEquals(cls(), cls())
self.assertEquals(0, cls().data)
self.assertEquals(cls(), cls(0))
self.assertEquals(cls(0), cls(0))
self.assertEquals(cls(v), cls(v))
self.assertEquals(cls(v), cls(data=v))
self.assertEquals(cls(data=v), cls(data=v))
self.assertNotEquals(cls(v), cls())
self.assertNotEquals(cls(data=v), cls(data=-v))
self.assertNotEquals(cls(data=v), cls(data=v-1))
self.assertNotEquals(cls(data=v), cls(v-1))
self.assertNotEquals(cls(v), cls(v-1))
self._test_ser_deser(cls(), cls())
self._test_ser_deser(cls(0), cls())
self._test_ser_deser(cls(v), cls())
try:
cls(-1)._check_types()
self.fail("check_types should have noted sign error[%s]: %s"%(w, cls.__name__))
except SerializationError: pass
# rospy currently does not spot negative overflow due to the fact that Python's struct doesn't either
widths = [(8, UInt8), (16, UInt16), (32, UInt32), (64, UInt64)]
for w, cls in widths:
maxp = long(math.pow(2, w)) - 1
self._test_ser_deser(cls(maxp), cls())
try:
cls(maxp+1)._check_types()
self.fail("check_types should have noted width error[%s]: %s, %s"%(w, maxp+1, cls.__name__))
except SerializationError: pass
def test_std_msgs_Float(self):
from std_msgs.msg import Float32, Float64
for cls in [Float32, Float64]:
self.assertEquals(cls(), cls())
self.assertEquals(0., cls().data)
self.assertEquals(cls(), cls(0.))
self.assertEquals(cls(0.), cls(0.))
self.assertEquals(cls(1.), cls(1.))
self.assertEquals(cls(1.), cls(data=1.))
self.assertEquals(cls(data=1.), cls(data=1.))
self.assertEquals(cls(math.pi), cls(math.pi))
self.assertEquals(cls(math.pi), cls(data=math.pi))
self.assertEquals(cls(data=math.pi), cls(data=math.pi))
self.assertNotEquals(cls(1.), cls())
self.assertNotEquals(cls(math.pi), cls())
self.assertNotEquals(cls(data=math.pi), cls(data=-math.pi))
self.assertNotEquals(cls(data=math.pi), cls(data=math.pi-1))
self.assertNotEquals(cls(data=math.pi), cls(math.pi-1))
self.assertNotEquals(cls(math.pi), cls(math.pi-1))
self._test_ser_deser(cls(), cls())
self._test_ser_deser(cls(0.), cls())
self._test_ser_deser(cls(1.), cls(), float=True)
self._test_ser_deser(cls(math.pi), cls(), float=True)
def test_std_msgs_MultiArray(self):
# multiarray is good test of embed plus array type
from std_msgs.msg import Int32MultiArray, MultiArrayDimension, MultiArrayLayout, UInt8MultiArray
dims = [MultiArrayDimension('foo', 1, 2), MultiArrayDimension('bar', 3, 4),\
MultiArrayDimension('foo2', 5, 6), MultiArrayDimension('bar2', 7, 8)]
for d in dims:
self.assertEquals(d, d)
# there was a bug with UInt8 arrays, so this is a regression
# test. the buff was with the uint8[] type consistency
buff = StringIO()
self.assertEquals(UInt8MultiArray(),UInt8MultiArray())
self.assertEquals('',UInt8MultiArray().data)
UInt8MultiArray().serialize(buff)
self.assertEquals(UInt8MultiArray(layout=MultiArrayLayout()),UInt8MultiArray())
UInt8MultiArray(layout=MultiArrayLayout()).serialize(buff)
data = ''.join([chr(i) for i in range(0, 100)])
v = UInt8MultiArray(data=data)
self._test_ser_deser(UInt8MultiArray(data=data),UInt8MultiArray())
self.assertEquals(Int32MultiArray(),Int32MultiArray())
self.assertEquals(Int32MultiArray(layout=MultiArrayLayout()),Int32MultiArray())
self.assertEquals(Int32MultiArray(layout=MultiArrayLayout(), data=[1, 2, 3]),Int32MultiArray(data=[1, 2, 3]))
self.assertEquals(Int32MultiArray(layout=MultiArrayLayout(), data=[1, 2, 3]),\
Int32MultiArray(layout=MultiArrayLayout(),data=[1, 2, 3]))
self.assertEquals(Int32MultiArray(layout=MultiArrayLayout(dim=[]), data=[1, 2, 3]),\
Int32MultiArray(layout=MultiArrayLayout(),data=[1, 2, 3]))
self.assertEquals(Int32MultiArray(layout=MultiArrayLayout([], 0), data=[1, 2, 3]),\
Int32MultiArray(layout=MultiArrayLayout(),data=[1, 2, 3]))
self.assertEquals(Int32MultiArray(layout=MultiArrayLayout(dim=[], data_offset=0), data=[1, 2, 3]),\
Int32MultiArray(layout=MultiArrayLayout(),data=[1, 2, 3]))
self.assertEquals(Int32MultiArray(layout=MultiArrayLayout(dim=dims, data_offset=0), data=[1, 2, 3]),\
Int32MultiArray(layout=MultiArrayLayout(dim=dims),data=[1, 2, 3]))
self.assertEquals(Int32MultiArray(layout=MultiArrayLayout(dims, 10), data=[1, 2, 3]),\
Int32MultiArray(layout=MultiArrayLayout(dim=dims,data_offset=10),data=[1, 2, 3]))
self.assertNotEquals(Int32MultiArray(data=[1, 2, 3]),Int32MultiArray(data=[4,5,6]))
self.assertNotEquals(Int32MultiArray(layout=MultiArrayLayout([], 1), data=[1, 2, 3]),\
Int32MultiArray(layout=MultiArrayLayout([], 0),data=[1, 2, 3]))
self.assertNotEquals(Int32MultiArray(layout=MultiArrayLayout([], 1), data=[1, 2, 3]),\
Int32MultiArray(layout=MultiArrayLayout(dim=[]),data=[1, 2, 3]))
self.assertNotEquals(Int32MultiArray(layout=MultiArrayLayout(dims, 10), data=[1, 2, 3]),\
Int32MultiArray(layout=MultiArrayLayout(dim=dims,data_offset=11),data=[1, 2, 3]))
self.assertNotEquals(Int32MultiArray(layout=MultiArrayLayout(dim=dims, data_offset=10), data=[1, 2, 3]),\
Int32MultiArray(layout=MultiArrayLayout(dim=dims[1:],data_offset=10),data=[1, 2, 3]))
self._test_ser_deser(Int32MultiArray(),Int32MultiArray())
self._test_ser_deser(Int32MultiArray(layout=MultiArrayLayout()),Int32MultiArray())
self._test_ser_deser(Int32MultiArray(data=[1, 2, 3]),Int32MultiArray())

View File

@@ -0,0 +1,73 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import time
import random
import math
from genpy import SerializationError
class TestGensrvPy(unittest.TestCase):
## Utility for testing roundtrip serialization
## @param orig Message to test roundtrip serialization of
## @param blank Uninitialized instance of message to deserialize into
## @param float bool: if True, use almostEquals instead of equals
## comparison. This variant assumes only data field is named
## 'data'
def _test_ser_deser(self, orig, blank, float=False):
b = StringIO()
orig.serialize(b)
blank.deserialize(b.getvalue())
if not float:
self.assertEquals(orig, blank, str(orig)+" != "+str(blank))
else:
self.assertAlmostEquals(orig.data, blank.data, 5)
## #2133/2139
def test_test_rospy_TransitiveImport(self):
from test_rospy.srv import TransitiveSrvRequest
m = TransitiveSrvRequest()
# invoking serialize should be enough to expose issue. The bug
# was that genmsg_py was failing to include the imports of
# embedded messages. Because messages are flattened, this
# causes ImportErrors.
self._test_ser_deser(m, TransitiveSrvRequest())

View File

@@ -0,0 +1,163 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
# test rospy API verifies that the rospy module exports the required symbols
class TestRospyApi(unittest.TestCase):
def test_msg(self):
# rospy.Message really only exists at the client level, as the internal
# implementation is built around the roslib reference, so we put the test here
import rospy
#trip wires against Message API
m = rospy.Message()
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
buff = StringIO()
m.serialize(buff)
self.assertEquals(0, buff.tell())
m.deserialize('')
def test_anymsg(self):
# rospy.AnyMsg really only exists at the client level as nothing within
# rospy uses its functionality.
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import rospy
import rospy.exceptions
#trip wires against AnyMsg API
m = rospy.AnyMsg()
try:
m.serialize(StringIO())
self.fail("AnyMsg should not allow serialization")
except rospy.exceptions.ROSException:
pass
teststr = 'foostr-%s'%time.time()
m.deserialize(teststr)
self.assertEquals(teststr, m._buff)
#test AnyMsg ctor error checking
try:
m = rospy.AnyMsg('foo')
self.fail("AnyMsg ctor should not allow args")
except: pass
def test_rospy_api(self):
import rospy
# just a laundry list of API methods to make sure that they still exist
# removed
try:
rospy.add_shutdown_hook
self.fail("add_shutdown_hookshould not longer be top-level API")
except AttributeError: pass
rospy.DEBUG
rospy.INFO
rospy.WARN
rospy.ERROR
rospy.FATAL
rospy.get_caller_id
rospy.get_name
rospy.get_master
rospy.get_namespace
rospy.get_published_topics
rospy.get_node_uri
rospy.get_ros_root
rospy.get_time
rospy.get_rostime
rospy.init_node
rospy.is_shutdown
rospy.logdebug
rospy.logerr
rospy.logfatal
rospy.loginfo
rospy.logout #deprecated
rospy.logwarn
rospy.logdebug_throttle
rospy.logerr_throttle
rospy.logfatal_throttle
rospy.loginfo_throttle
rospy.logwarn_throttle
rospy.myargv
rospy.on_shutdown
rospy.parse_rosrpc_uri
rospy.resolve_name
rospy.remap_name
rospy.signal_shutdown
rospy.sleep
rospy.spin
rospy.wait_for_message
rospy.wait_for_service
rospy.delete_param
rospy.get_param
rospy.get_param_names
rospy.has_param
rospy.set_param
rospy.search_param
rospy.AnyMsg
rospy.Duration
rospy.Header
rospy.MasterProxy
rospy.Message
rospy.Publisher
rospy.Rate
rospy.ROSException
rospy.ROSInternalException
rospy.ROSSerializationException
rospy.ServiceException
rospy.Service
rospy.ServiceProxy
rospy.SubscribeListener
rospy.Subscriber
rospy.Time
rospy.TransportException
rospy.TransportTerminated
rospy.TransportInitError

View File

@@ -0,0 +1,110 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
import random
import rosunit
import rospy
class TestRospyClient(unittest.TestCase):
def test_init_node(self):
failed = True
try:
# #1822
rospy.init_node('ns/node')
except ValueError:
failed = False
self.failIf(failed, "init_node allowed '/' in name")
failed = True
try:
rospy.init_node(name=None)
except ValueError:
failed = False
self.failIf(failed, "init_node allowed None as name")
failed = True
try:
rospy.init_node("")
except ValueError:
failed = False
self.failIf(failed, "init_node allowed empty string as name")
def test_spin(self):
failed = True
try:
rospy.spin()
except rospy.ROSInitException:
failed = False
self.failIf(failed, "spin() should failed if not initialized")
def test_myargv(self):
orig_argv = sys.argv
try:
from rospy.client import myargv
args = myargv()
self.assertEquals(args, sys.argv)
self.assertEquals(['foo', 'bar', 'baz'], myargv(['foo','bar', 'baz']))
self.assertEquals(['-foo', 'bar', '-baz'], myargv(['-foo','bar', '-baz']))
self.assertEquals(['foo'], myargv(['foo','bar:=baz']))
self.assertEquals(['foo'], myargv(['foo','-bar:=baz']))
finally:
sys.argv = orig_argv
def test_load_command_line_node_params(self):
from rospy.client import load_command_line_node_params
assert {} == load_command_line_node_params([])
assert {} == load_command_line_node_params(['a', 'b', 'c'])
assert {} == load_command_line_node_params(['a:=b'])
assert {'a': 'b'} == load_command_line_node_params(['_a:=b'])
assert {'a': 'b', 'foo': 'bar'} == load_command_line_node_params(['_a:=b', 'blah', '_foo:=bar', 'baz'])
# test yaml unmarshal
assert {'a': 1} == load_command_line_node_params(['_a:=1'])
try:
load_command_line_node_params(['_a:=b:=c'])
except rospy.exceptions.ROSInitException:
pass
if __name__ == '__main__':
rosunit.unitrun('test_rospy', sys.argv[0], TestRospyClient, coverage_packages=['rospy.client'])

View File

@@ -0,0 +1,239 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function
import os
import sys
import struct
import unittest
import time
import random
import rospy
class TestRospyCore(unittest.TestCase):
def test_parse_rosrpc_uri(self):
from rospy.core import parse_rosrpc_uri
valid = [('rosrpc://localhost:1234/', 'localhost', 1234),
('rosrpc://localhost2:1234', 'localhost2', 1234),
('rosrpc://third:1234/path/bar', 'third', 1234),
('rosrpc://foo.com:1/', 'foo.com', 1),
('rosrpc://foo.com:1/', 'foo.com', 1)]
for t, addr, port in valid:
paddr, pport = rospy.core.parse_rosrpc_uri(t)
self.assertEquals(addr, paddr)
self.assertEquals(port, pport)
# validate that it's a top-level API method
self.assertEquals(rospy.core.parse_rosrpc_uri(t), rospy.parse_rosrpc_uri(t))
invalid = ['rosrpc://:1234/', 'rosrpc://localhost', 'http://localhost:1234/']
for i in invalid:
try:
parse_rosrpc_uri(i)
self.fail("%s was an invalid rosrpc uri"%i)
except: pass
def test_loggers(self):
# trip wire tests
import rospy.core
rospy.core.logdebug('debug')
rospy.core.logwarn('warn')
rospy.core.logout('out')
rospy.core.logerr('err')
rospy.core.logfatal('fatal')
# test that they are exposed via top-level api
import rospy
rospy.logdebug('debug')
rospy.logwarn('warn')
rospy.logout('out')
rospy.logerr('err')
rospy.logfatal('fatal')
def test_add_shutdown_hook(self):
def handle(reason):
pass
# cannot verify functionality, just crashing
rospy.core.add_shutdown_hook(handle)
try:
rospy.core.add_shutdown_hook(1)
self.fail_("add_shutdown_hook is not protected against invalid args")
except TypeError: pass
try:
rospy.core.add_shutdown_hook(1)
self.fail_("add_shutdown_hook is not protected against invalid args")
except TypeError: pass
def test_add_preshutdown_hook(self):
def handle1(reason):
pass
def handle2(reason):
pass
def handle3(reason):
pass
# cannot verify functionality, just coverage as well as ordering
rospy.core.add_shutdown_hook(handle1)
rospy.core.add_shutdown_hook(handle2)
rospy.core.add_preshutdown_hook(handle3)
self.assert_(handle3 in rospy.core._preshutdown_hooks)
self.assert_(handle2 in rospy.core._shutdown_hooks)
self.assert_(handle1 in rospy.core._shutdown_hooks)
try:
rospy.core.add_preshutdown_hook(1)
self.fail_("add_preshutdown_hook is not protected against invalid args")
except TypeError: pass
try:
rospy.core.add_preshutdown_hook(1)
self.fail_("add_preshutdown_hook is not protected against invalid args")
except TypeError: pass
def test_get_ros_root(self):
try:
rospy.core.get_ros_root(env={}, required=True)
except:
pass
self.assertEquals(None, rospy.core.get_ros_root(env={}, required=False))
rr = "%s"%time.time()
self.assertEquals(rr, rospy.core.get_ros_root(env={'ROS_ROOT': rr}, required=False))
self.assertEquals(rr, rospy.core.get_ros_root(env={'ROS_ROOT': rr}, required=True))
self.assertEquals(os.path.normpath(os.environ['ROS_ROOT']), rospy.core.get_ros_root(required=False))
def test_node_uri(self):
uri = "http://localhost-%s:1234"%random.randint(1, 1000)
self.assertEquals(None, rospy.core.get_node_uri())
rospy.core.set_node_uri(uri)
self.assertEquals(uri, rospy.core.get_node_uri())
def test_initialized(self):
self.failIf(rospy.core.is_initialized())
rospy.core.set_initialized(True)
self.assert_(rospy.core.is_initialized())
def test_shutdown_hook_exception(self):
rospy.core._shutdown_flag = False
del rospy.core._shutdown_hooks[:]
# add a shutdown hook that throws an exception,
# signal_shutdown should be robust to it
rospy.core.add_shutdown_hook(shutdown_hook_exception)
rospy.core.signal_shutdown('test_exception')
rospy.core._shutdown_flag = False
del rospy.core._shutdown_hooks[:]
def test_shutdown(self):
rospy.core._shutdown_flag = False
del rospy.core._shutdown_hooks[:]
global called, called2
called = called2 = None
self.failIf(rospy.core.is_shutdown())
rospy.core.add_shutdown_hook(shutdown_hook1)
reason = "reason %s"%time.time()
rospy.core.signal_shutdown(reason)
self.assertEquals(reason, called)
self.assert_(rospy.core.is_shutdown())
# verify that shutdown hook is called immediately on add if already shutdown
rospy.core.add_shutdown_hook(shutdown_hook2)
self.assert_(called2 is not None)
rospy.core._shutdown_flag = False
#TODO: move to teset_rospy_names
def test_valid_name(self):
# not forcing rospy to be pedantic -- yet, just try and do sanity checks
tests = ['/', 'srv', '/service', '/service1', 'serv/subserv']
caller_id = '/me'
for t in tests:
self.assert_(rospy.core.valid_name('p')(t, caller_id))
failures = ['ftp://foo', '', None, 1, True, 'http:', ' spaced ', ' ']
for f in failures:
try:
rospy.core.valid_name('p')(f, caller_id)
self.fail(f)
except rospy.core.ParameterInvalid:
pass
def test_is_topic(self):
# not forcing rospy to be pedantic -- yet, just try and do sanity checks
caller_id = '/me'
tests = [
('topic', '/node', '/topic'),
('topic', '/ns/node', '/ns/topic'),
('/topic', '/node', '/topic'),
('~topic', '/node', '/node/topic'),
('/topic1', '/node', '/topic1'),
('top/sub', '/node', '/top/sub'),
('top/sub', '/ns/node', '/ns/top/sub'),
]
for t, caller_id, v in tests:
self.assertEquals(v, rospy.core.is_topic('p')(t, caller_id))
failures = ['/', 'ftp://foo', '', None, 1, True, 'http:', ' spaced ', ' ']
for f in failures:
try:
rospy.core.is_topic('p')(f, caller_id)
self.fail(f)
except rospy.core.ParameterInvalid:
pass
def test_configure_logging(self):
# can't test actual functionality
try:
rospy.core.configure_logging("/")
self.fail("configure_logging should not accept a the root namespace as the node_name param")
except: pass
rospy.core.configure_logging("/node/name")
def test_xmlrpcapi(self):
# have to use 'is' so we don't accidentally invoke XMLRPC
self.assert_(rospy.core.xmlrpcapi(None) is None)
self.assert_(rospy.core.xmlrpcapi('localhost:1234') is None)
self.assert_(rospy.core.xmlrpcapi('http://') is None)
api = rospy.core.xmlrpcapi('http://localhost:1234')
self.assert_(api is not None)
try:
from xmlrpc.client import ServerProxy
except ImportError:
from xmlrpclib import ServerProxy
self.assert_(isinstance(api, ServerProxy))
called = None
called2 = None
def shutdown_hook1(reason):
global called
print("HOOK", reason)
called = reason
def shutdown_hook2(reason):
global called2
print("HOOK2", reason)
called2 = reason
def shutdown_hook_exception(reason):
raise Exception("gotcha")

View File

@@ -0,0 +1,77 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
class TestRospyExceptions(unittest.TestCase):
def test_exceptions(self):
# not really testing anything here other than typos
from rospy.exceptions import ROSException, ROSSerializationException, ROSInternalException, ROSInitException, \
TransportException, TransportTerminated, TransportInitError
for e in [ROSException, ROSInitException, ROSSerializationException]:
exc = e('foo')
self.assert_(isinstance(exc, ROSException))
for e in [ROSInternalException,
TransportException, TransportTerminated, TransportInitError]:
exc = e('foo')
self.assert_(isinstance(exc, ROSInternalException))
def test_ROSInterruptException(self):
from rospy.exceptions import ROSInterruptException, ROSException
try:
raise ROSInterruptException("test")
except ROSException:
pass
try:
raise ROSInterruptException("test")
except KeyboardInterrupt:
pass
def test_ROSTimeMovedBackwardsException(self):
from rospy.exceptions import ROSTimeMovedBackwardsException, ROSInterruptException
try:
raise ROSTimeMovedBackwardsException(1.0)
except ROSInterruptException as e:
# ensure the message is not changed, because old code may check it
self.assertEqual("ROS time moved backwards", e.message)
try:
time = 1.0
raise ROSTimeMovedBackwardsException(time)
except ROSTimeMovedBackwardsException as e:
self.assertEqual(time, e.time)

View File

@@ -0,0 +1,275 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import time
import random
import genpy
class TestRospyMsg(unittest.TestCase):
def test_args_kwds_to_message(self):
import rospy
from rospy.msg import args_kwds_to_message
from test_rospy.msg import Val, Empty
v = Val('hello world-1')
d = args_kwds_to_message(Val, (v,), None)
self.assert_(d == v)
d = args_kwds_to_message(Val, ('hello world-2',), None)
self.assertEquals(d.val, 'hello world-2')
d = args_kwds_to_message(Val, (), {'val':'hello world-3'})
self.assertEquals(d.val, 'hello world-3')
# error cases
try:
args_kwds_to_message(Val, 'hi', val='hello world-3')
self.fail("should not allow args and kwds")
except TypeError: pass
try:
args_kwds_to_message(Empty, (Val('hola'),), None)
self.fail("should raise TypeError when publishing Val msg to Empty topic")
except TypeError: pass
def test_serialize_message(self):
import rospy.msg
import rospy.rostime
# have to fake-init rostime so that Header can be stamped
rospy.rostime.set_rostime_initialized(True)
buff = StringIO()
seq = random.randint(1, 1000)
#serialize_message(seq, msg)
from test_rospy.msg import Val
#serialize a simple 'Val' with a string in it
teststr = 'foostr-%s'%time.time()
val = Val(teststr)
fmt = "<II%ss"%len(teststr)
size = struct.calcsize(fmt) - 4
valid = struct.pack(fmt, size, len(teststr), teststr)
rospy.msg.serialize_message(buff, seq, val)
self.assertEquals(valid, buff.getvalue())
#test repeated serialization
rospy.msg.serialize_message(buff, seq, val)
rospy.msg.serialize_message(buff, seq, val)
self.assertEquals(valid*3, buff.getvalue())
# - once more just to make sure that the buffer position is
# being preserved properly
buff.seek(0)
rospy.msg.serialize_message(buff, seq, val)
self.assertEquals(valid*3, buff.getvalue())
rospy.msg.serialize_message(buff, seq, val)
self.assertEquals(valid*3, buff.getvalue())
rospy.msg.serialize_message(buff, seq, val)
self.assertEquals(valid*3, buff.getvalue())
#test sequence parameter
buff.truncate(0)
from test_rospy.msg import HeaderVal
t = rospy.Time.now()
t.secs = t.secs - 1 # move it back in time
h = rospy.Header(None, rospy.Time.now(), teststr)
h.stamp = t
val = HeaderVal(h, teststr)
seq += 1
rospy.msg.serialize_message(buff, seq, val)
self.assertEquals(val.header, h)
self.assertEquals(seq, h.seq)
#should not have been changed
self.assertEquals(t, h.stamp)
self.assertEquals(teststr, h.frame_id)
#test frame_id setting
h.frame_id = None
rospy.msg.serialize_message(buff, seq, val)
self.assertEquals(val.header, h)
self.assertEquals('0', h.frame_id)
def test_deserialize_messages(self):
import rospy.msg
from test_rospy.msg import Val
num_tests = 10
teststrs = ['foostr-%s'%random.randint(0, 10000) for i in range(0, num_tests)]
valids = []
for t in teststrs:
fmt = "<II%ss"%len(t)
size = struct.calcsize(fmt) - 4
valids.append(struct.pack(fmt, size, len(t), t))
data_class = Val
def validate_vals(vals, teststrs=teststrs):
for i, v in zip(range(0, len(vals)), vals):
self.assert_(isinstance(v, Val))
self.assertEquals(teststrs[i], v.val)
b = StringIO()
msg_queue = []
#test with null buff
try:
rospy.msg.deserialize_messages(None, msg_queue, data_class)
except genpy.DeserializationError: pass
#test will null msg_queue
try:
rospy.msg.deserialize_messages(b, None, data_class)
except genpy.DeserializationError: pass
#test with empty buff
rospy.msg.deserialize_messages(b, msg_queue, data_class)
self.assertEquals(0, len(msg_queue))
self.assertEquals(0, b.tell())
#deserialize a simple value
b.truncate(0)
b.write(valids[0])
rospy.msg.deserialize_messages(b, msg_queue, data_class)
self.assertEquals(1, len(msg_queue))
validate_vals(msg_queue)
# - buffer should be reset
self.assertEquals(0, b.tell())
del msg_queue[:]
#verify deserialize does not read past b.tell()
b.truncate(0)
b.write(valids[0])
b.write(valids[1])
b.seek(len(valids[0]))
rospy.msg.deserialize_messages(b, msg_queue, data_class)
self.assertEquals(1, len(msg_queue))
validate_vals(msg_queue)
# - buffer should be reset
self.assertEquals(0, b.tell())
del msg_queue[:]
#deserialize an incomplete message
b.truncate(0)
b.write(valids[0][:-1])
rospy.msg.deserialize_messages(b, msg_queue, data_class)
self.failIf(msg_queue, "deserialize of an incomplete buffer returned %s"%msg_queue)
del msg_queue[:]
#deserialize with extra data leftover
b.truncate(0)
b.write(valids[0]+'leftovers')
rospy.msg.deserialize_messages(b, msg_queue, data_class)
self.assertEquals(1, len(msg_queue))
validate_vals(msg_queue)
# - leftovers should be pushed to the front of the buffer
self.assertEquals('leftovers', b.getvalue())
del msg_queue[:]
#deserialize multiple values
b.truncate(0)
for v in valids:
b.write(v)
rospy.msg.deserialize_messages(b, msg_queue, data_class)
self.assertEquals(len(valids), len(msg_queue))
validate_vals(msg_queue)
# - buffer should be reset
self.assertEquals(0, b.tell())
del msg_queue[:]
#deserialize multiple values with max_msgs
max_msgs = 5
b.truncate(0)
for v in valids:
b.write(v)
rospy.msg.deserialize_messages(b, msg_queue, data_class, max_msgs=max_msgs)
self.assertEquals(max_msgs, len(msg_queue))
validate_vals(msg_queue)
# - buffer should be have remaining msgs
b2 = StringIO()
for v in valids[max_msgs:]:
b2.write(v)
self.assertEquals(b.getvalue(), b2.getvalue())
#deserialize rest and verify that msg_queue is appended to
rospy.msg.deserialize_messages(b, msg_queue, data_class)
self.assertEquals(len(valids), len(msg_queue))
validate_vals(msg_queue)
del msg_queue[:]
#deserialize multiple values with queue_size
queue_size = 5
b.truncate(0)
for v in valids:
b.write(v)
# fill queue with junk
msg_queue = [1, 2, 3, 4, 5, 6, 7, 9, 10, 11]
rospy.msg.deserialize_messages(b, msg_queue, data_class, queue_size=queue_size)
self.assertEquals(queue_size, len(msg_queue))
# - msg_queue should have the most recent values only
validate_vals(msg_queue, teststrs[-queue_size:])
# - buffer should be reset
self.assertEquals(0, b.tell())
#deserialize multiple values with max_msgs and queue_size
queue_size = 5
max_msgs = 5
b.truncate(0)
for v in valids:
b.write(v)
# fill queue with junk
msg_queue = [1, 2, 3, 4, 5, 6, 7, 9, 10, 11]
rospy.msg.deserialize_messages(b, msg_queue, data_class, max_msgs=max_msgs, queue_size=queue_size)
self.assertEquals(queue_size, len(msg_queue))
# - msg_queue should have the oldest messages
validate_vals(msg_queue)
# - buffer should be have remaining msgs
b2 = StringIO()
for v in valids[max_msgs:]:
b2.write(v)
self.assertEquals(b.getvalue(), b2.getvalue())

View File

@@ -0,0 +1,285 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
# test rospy.names package
class TestRospyNames(unittest.TestCase):
def test_scoped_name(self):
from rospy.exceptions import ROSException
from rospy.names import scoped_name
tests = [
['/', '/name', 'name'],
['/', '/ns/name', 'ns/name'],
['/ns', '/ns/name', 'ns/name'],
['/ns/node', '/ns/name', 'name'],
['/ns/', '/ns/name', 'ns/name'],
['/ns/ns2/', '/ns/name', 'name'],
]
for caller_id, name, v in tests:
val = scoped_name(caller_id, name)
self.assertEquals(v, val, "failed on [%s] [%s]: %s"%(caller_id, name, val))
fail = [
['name', '/name'],
['~name', '/name'],
]
for caller_id, name in fail:
try:
scoped_name(caller_id, name)
self.fail("should have failed on %s, %s"%(caller_id, name))
except ROSException: pass
def test_mappings(self):
import roslib.names
import rospy.names
from rospy.names import get_mappings, get_resolved_mappings, initialize_mappings
# get_mappings is initialized statically, so can't test anything other than it is empty
self.assertEquals({}, get_mappings())
# resolved mappings should be empty with no initialization
self.assertEquals({}, get_resolved_mappings())
# now, initialize mappings, shouldn't matter as there are no mappings
initialize_mappings('foo')
# should be empty now
self.assertEquals({}, get_resolved_mappings())
# manipulate mappings to test
rospy.names._mappings = roslib.names.load_mappings(['__name:=newname', '__log:=blah', '_param:=value', 'foo:=bar','/baz:=a/b', '~car:=c/d/e'])
# - param mapping should be removed
self.assertEquals({'__name': 'newname', '__log': 'blah',
'foo': 'bar', '/baz': 'a/b', '~car': 'c/d/e'}, get_mappings())
# - should be unaltered
self.assertEquals({}, get_resolved_mappings())
initialize_mappings('/name')
# should be unchanged
self.assertEquals({'__name': 'newname', '__log': 'blah',
'foo': 'bar', '/baz': 'a/b', '~car': 'c/d/e'}, get_mappings())
# should be remapped
self.assertEquals({'__name': 'newname', '__log': 'blah',
'/foo': '/bar', '/baz': '/a/b', '/name/car':'/c/d/e'},
get_resolved_mappings())
# try with namespaced node
initialize_mappings('/ns/name')
# should be remapped
self.assertEquals({'__name': 'newname', '__log': 'blah',
'/ns/foo': '/ns/bar', '/baz': '/ns/a/b', '/ns/name/car':'/ns/c/d/e'},
get_resolved_mappings())
def test_canonicalize_name(self):
from rospy.names import canonicalize_name
tests = [
('', ''),
('/', '/'),
('foo', 'foo'),
('/foo', '/foo'),
('/foo/', '/foo'),
('/foo/bar', '/foo/bar'),
('/foo/bar/', '/foo/bar'),
('/foo/bar//', '/foo/bar'),
('/foo//bar', '/foo/bar'),
('//foo/bar', '/foo/bar'),
('foo/bar', 'foo/bar'),
('foo//bar', 'foo/bar'),
('foo/bar/', 'foo/bar'),
('/foo/bar', '/foo/bar'),
]
for t, v in tests:
self.assertEquals(v, canonicalize_name(t))
def test_ANYTYPE(self):
from rospy.names import TOPIC_ANYTYPE, SERVICE_ANYTYPE
self.assertEquals("*", TOPIC_ANYTYPE)
self.assertEquals("*", SERVICE_ANYTYPE)
def test_resolve_name(self):
from rospy.names import resolve_name
# TODO: test with remappings
tests = [
('', '/', '/'),
('', None, '/'), #node_name defaults to /
('', '/node', '/'),
('', '/ns1/node', '/ns1/'),
('foo', '', '/foo'),
('foo', None, '/foo'),
('foo/', '', '/foo'),
('/foo', '', '/foo'),
('/foo/', '', '/foo'),
('/foo', '/', '/foo'),
('/foo', None, '/foo'),
('/foo/', '/', '/foo'),
('/foo', '/bar', '/foo'),
('/foo/', '/bar', '/foo'),
('foo', '/ns1/ns2', '/ns1/foo'),
('foo', '/ns1/ns2/', '/ns1/foo'),
('foo', '/ns1/ns2/ns3/', '/ns1/ns2/foo'),
('foo/', '/ns1/ns2', '/ns1/foo'),
('/foo', '/ns1/ns2', '/foo'),
('foo/bar', '/ns1/ns2', '/ns1/foo/bar'),
('foo//bar', '/ns1/ns2', '/ns1/foo/bar'),
('foo/bar', '/ns1/ns2/ns3', '/ns1/ns2/foo/bar'),
('foo//bar//', '/ns1/ns2/ns3', '/ns1/ns2/foo/bar'),
('~foo', '/', '/foo'),
('~foo', '/node', '/node/foo'),
('~foo', '/ns1/ns2', '/ns1/ns2/foo'),
('~foo/', '/ns1/ns2', '/ns1/ns2/foo'),
('~foo/bar', '/ns1/ns2', '/ns1/ns2/foo/bar'),
]
for name, node_name, v in tests:
self.assertEquals(v, resolve_name(name, node_name))
def test_valid_name(self):
# test with resolution
from rospy.names import valid_name_validator_resolved, valid_name, ParameterInvalid
validator = valid_name('param_name', True)
tests = [
('name', '/node', '/name'),
('/name', '/node', '/name'),
('~name', '/node', '/node/name'),
# test unicode
(u'~name', '/node', u'/node/name'),
]
for name, caller_id, v in tests:
self.assertEquals(v, valid_name_validator_resolved('p', name, caller_id), "failed on %s %s"%(name, caller_id))
self.assertEquals(v, validator(name, caller_id))
# kwc: valid_name is currently very soft in the failures it
# checks as it is targetted at catching parameter
# misalignment. I would like to make it more strict in the
# future.
invalid = [
(1, '/node'),
(None, '/node'),
('localhost:123', '/node'),
('Bob Barker', '/node'),
# unicode
(u'Bob Barker', '/node'),
]
for name, caller_id in invalid:
try:
valid_name_validator_resolved('p', name, caller_id)
self.fail("valid_name_validator_unresolved should have failed on : [%s], [%s]"%(name, caller_id))
except ParameterInvalid: pass
try:
validator(name, caller_id)
self.fail("valid_name_validator_unresolved should have failed on : [%s], [%s]"%(name, caller_id))
except ParameterInvalid: pass
from rospy.names import valid_name_validator_unresolved
validator = valid_name('param_name', False)
tests = [
('name', '/node', 'name'),
('/name', '/node', '/name'),
('~name', '/node', '~name'),
# unicode
(u'~name', '/node', u'~name'),
]
for name, caller_id, v in tests:
self.assertEquals(v, valid_name_validator_unresolved('p', name, caller_id), "failed on [%s] [%s]"%(name, caller_id))
self.assertEquals(v, validator(name, caller_id))
for name, caller_id in invalid:
try:
valid_name_validator_unresolved('p', name, caller_id)
self.fail("valid_name_validator_unresolved should have failed on : [%s], [%s]"%(name, caller_id))
except ParameterInvalid: pass
try:
validator(name, caller_id)
self.fail("valid_name_validator_unresolved should have failed on : [%s], [%s]"%(name, caller_id))
except ParameterInvalid: pass
def test_global_name(self):
from rospy.names import global_name, ParameterInvalid
validator = global_name('param_name')
tests = [
('/', '/node', '/'),
('/name', '/node', '/name'),
# unicode
(u'/name', '/node', u'/name'),
]
for name, caller_id, v in tests:
self.assertEquals(v, validator(name, caller_id))
invalid = [
(1, '/node'),
(None, '/node'),
('name', '/node'),
('~name', '/node'),
]
for name, caller_id in invalid:
try:
validator(name, caller_id)
self.fail("global_name should have failed on : [%s], [%s]"%(name, caller_id))
except ParameterInvalid: pass
def test_caller_id(self):
from rospy.names import get_caller_id, get_name, _set_caller_id, get_namespace
# test get_name, get_caller_id, and _set_caller_id
try:
self.assertEquals('/unnamed', get_name())
self.assertEquals('/', get_namespace())
_set_caller_id('/foo')
self.assertEquals('/foo', get_name())
self.assertEquals('/', get_namespace())
_set_caller_id('/foo/bar')
self.assertEquals('/foo/bar', get_name())
self.assertEquals('/foo/', get_namespace())
finally:
_set_caller_id('/unnamed')
# older get_caller_id usage
try:
self.assertEquals('/unnamed', get_caller_id())
self.assertEquals('/', get_namespace())
_set_caller_id('/foo')
self.assertEquals('/foo', get_caller_id())
self.assertEquals('/', get_namespace())
_set_caller_id('/foo/bar')
self.assertEquals('/foo/bar', get_caller_id())
self.assertEquals('/foo/', get_namespace())
finally:
_set_caller_id('/unnamed')

View File

@@ -0,0 +1,89 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import struct
import unittest
import time
try:
import numpy
disable = False
except ImportError:
print("cannot import numpy, test is disabled")
disable = True
# this is partially a teste of the rospy/Tutorials/numpy
from test_rospy.msg import Floats
# test rospy.names package
class TestRospyNumpy(unittest.TestCase):
def test_floats(self):
if disable:
return
vals = [1.0, 2.1, 3.2, 4.3, 5.4, 6.5]
b = StringIO()
f = Floats(numpy.array([1.0, 2.1, 3.2, 4.3, 5.4, 6.5], dtype=numpy.float32))
f.serialize(b)
# deserialize twice, once with numpy wrappers, once without
f2 = Floats()
self.assert_(type(f2.data) == list)
f2.deserialize(b.getvalue())
for x, y in zip(f2.data, vals):
self.assertAlmostEquals(x, y, 2)
from rospy.numpy_msg import numpy_msg
f3 = numpy_msg(Floats)()
if 0:
# future
self.assert_(isinstance(f3.data, numpy.ndarray), type(f3.data))
f3.deserialize(b.getvalue())
self.assert_(isinstance(f3.data, numpy.ndarray), type(f3.data))
v = numpy.equal(f3.data, numpy.array([1.0, 2.1, 3.2, 4.3, 5.4, 6.5], dtype=numpy.float32))
self.assert_(v.all())
def test_class_identity(self):
from rospy.numpy_msg import numpy_msg
self.assert_(isinstance(numpy_msg(Floats)(), numpy_msg(Floats)))
FloatsNP = numpy_msg(Floats)
FloatsNP2 = numpy_msg(Floats)
self.assert_(FloatsNP is FloatsNP2)

View File

@@ -0,0 +1,75 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
import random
import datetime
from rosgraph.names import make_global_ns, ns_join
## Unit tests for rospy.paramserver module
class TestRospyParamServer(unittest.TestCase):
def test_param_server_cache(self):
from rospy.impl.paramserver import get_param_server_cache
ps = get_param_server_cache()
self.assert_(ps is not None)
try:
ps.get('foo')
self.fail("get should fail on non-existent key")
except KeyError:
pass
for i in range(0, 10):
k = 'key-%s%s'%(i, random.randint(0, 1000))
v = 'value-%s'%random.randint(0, 1000)
try:
ps.update(k, v)
self.fail("update should fail on non-existent key "+k)
except KeyError:
pass
ps.set(k, v)
self.assertEquals(v, ps.get(k))
v = 'value-%s'%random.randint(0, 1000)
ps.update(k, v)
self.assertEquals(v, ps.get(k))
ps.delete(k)
try:
ps.get(k)
self.fail('get should fail on deleted key')
except KeyError: pass

View File

@@ -0,0 +1,255 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2009, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
class TestRospyRegistration(unittest.TestCase):
def test_get_set_topic_manager(self):
from rospy.impl.registration import get_topic_manager, set_topic_manager
# rospy initialization sets this, but it is out of scope of
# rospy.impl.registrations to test its value
orig = get_topic_manager()
try:
self.assert_(orig is not None)
class TopicManager(object): pass
x = TopicManager()
# currently untyped
set_topic_manager(x)
self.assertEquals(x, get_topic_manager())
set_topic_manager(None)
self.assert_(get_topic_manager() is None)
finally:
set_topic_manager(orig)
def test_get_set_service_manager(self):
from rospy.impl.registration import get_service_manager, set_service_manager
# rospy initialization sets this, but it is out of scope of
# rospy.impl.registrations to test its value
try:
orig = get_service_manager()
self.assert_(orig is not None)
class ServiceManager(object): pass
x = ServiceManager()
# currently untyped
set_service_manager(x)
self.assertEquals(x, get_service_manager())
set_service_manager(None)
self.assert_(get_service_manager() is None)
finally:
set_service_manager(orig)
def test_Registration(self):
# nothing to test here really
from rospy.impl.registration import Registration
self.assertEquals('pub', Registration.PUB)
self.assertEquals('sub', Registration.SUB)
self.assertEquals('srv', Registration.SRV)
r = Registration()
self.assertEquals('pub', r.PUB)
self.assertEquals('sub', r.SUB)
self.assertEquals('srv', r.SRV)
def test_RegistrationListener(self):
from rospy.impl.registration import RegistrationListener
#RegistrationListener is just an API, nothing to test here
l = RegistrationListener()
l.reg_added('name', 'data_type', 'reg_type')
l.reg_removed('name', 'data_type', 'reg_type')
def test_RegistrationListeners(self):
from rospy.impl.registration import RegistrationListeners, RegistrationListener
class Mock(RegistrationListener):
def __init__(self):
self.args = []
def reg_added(self, name, data_type_or_uri, reg_type):
self.args = ['added', name, data_type_or_uri, reg_type]
def reg_removed(self, name, data_type_or_uri, reg_type):
self.args = ['removed', name, data_type_or_uri, reg_type]
class BadMock(RegistrationListener):
def reg_added(self, name, data_type_or_uri, reg_type):
raise Exception("haha!")
def reg_removed(self, name, data_type_or_uri, reg_type):
raise Exception("haha!")
r = RegistrationListeners()
self.assertEquals([], r.listeners)
try:
r.lock.acquire()
finally:
r.lock.release()
r.notify_added('n1', 'dtype1', 'rtype1')
r.notify_removed('n1', 'dtype1', 'rtype1')
l1 = Mock()
l2 = Mock()
r.add_listener(l1)
self.assertEquals([l1], r.listeners)
self.assertEquals([], l1.args)
r.notify_added('n2', 'dtype2', 'rtype2')
self.assertEquals(['added', 'n2', 'dtype2', 'rtype2'], l1.args)
r.notify_removed('n2', 'dtype2', 'rtype2')
self.assertEquals(['removed', 'n2', 'dtype2', 'rtype2'], l1.args)
r.add_listener(l2)
self.assert_(l2 in r.listeners)
self.assert_(l1 in r.listeners)
self.assertEquals(2, len(r.listeners))
self.assertEquals([], l2.args)
r.notify_added('n3', 'dtype3', 'rtype3')
self.assertEquals(['added', 'n3', 'dtype3', 'rtype3'], l2.args)
self.assertEquals(['added', 'n3', 'dtype3', 'rtype3'], l1.args)
r.notify_removed('n3', 'dtype3', 'rtype3')
self.assertEquals(['removed', 'n3', 'dtype3', 'rtype3'], l2.args)
self.assertEquals(['removed', 'n3', 'dtype3', 'rtype3'], l1.args)
# l3 raises exceptions, make sure they don't break anything
l3 = BadMock()
r.add_listener(l3)
self.assert_(l3 in r.listeners)
self.assert_(l2 in r.listeners)
self.assert_(l1 in r.listeners)
self.assertEquals(3, len(r.listeners))
r.notify_added('n4', 'dtype4', 'rtype4')
self.assertEquals(['added', 'n4', 'dtype4', 'rtype4'], l2.args)
self.assertEquals(['added', 'n4', 'dtype4', 'rtype4'], l1.args)
r.notify_removed('n4', 'dtype4', 'rtype4')
self.assertEquals(['removed', 'n4', 'dtype4', 'rtype4'], l2.args)
self.assertEquals(['removed', 'n4', 'dtype4', 'rtype4'], l1.args)
def test_get_registration_listeners(self):
from rospy.impl.registration import RegistrationListeners, get_registration_listeners
r = get_registration_listeners()
self.assert_(isinstance(r, RegistrationListeners))
def test_RegManager(self):
from rospy.impl.registration import RegManager
class MockHandler(object):
def __init__(self):
self.done = False
self.args = []
def _connect_topic(self, topic, uri):
self.args.append(['_connect_topic', topic, uri])
# trip to done on connect topic so we can exit loop
self.done = True
return 1, 'msg', 1
# bad return value for _connect_topic
class BadHandler(object):
def __init__(self):
self.done = False
def _connect_topic(self, topic, uri):
self.done = True
return None
# bad code for _connect_topic
class BadHandler2(object):
def __init__(self):
self.done = False
def _connect_topic(self, topic, uri):
self.done = True
return -1, "failed", 1
handler = MockHandler()
m = RegManager(handler)
self.assertEquals(handler, m.handler)
self.assert_(m.logger is not None)
self.assertEquals(m.master_uri, None)
self.assertEquals(m.uri, None)
self.assertEquals([], m.updates)
try:
m.cond.acquire()
finally:
m.cond.release()
# call twice with topic 2 to test filtering logic
m.publisher_update('topic1', ['http://uri:1', 'http://uri:1b'])
m.publisher_update('topic2', ['http://old:2', 'http://old:2b'])
m.publisher_update('topic1b', ['http://foo:1', 'http://foo:1b'])
m.publisher_update('topic2', ['http://uri:2', 'http://uri:2b'])
self.assertEquals([('topic1', ['http://uri:1', 'http://uri:1b']),
('topic2', ['http://old:2', 'http://old:2b']),
('topic1b', ['http://foo:1', 'http://foo:1b']),
('topic2', ['http://uri:2', 'http://uri:2b'])], m.updates)
# disabling these tests as they are just too dangerous now that registrations multithreads updates
if 0:
# this should only go through once as MockHandler trips to done
m.run()
# have to give time for threads to spin up and call handler
timeout_t = 10. + time.time()
while time.time() < timeout_t and len(m.updates) > 2:
time.sleep(0.1)
m.handler = BadHandler()
# this should only go through once as BadHandler trips to done. this tests the
# exception branch
m.run()
# this will cause an error to be logged in _connect_topic_thread
# - reset data in m.updates
m.updates= [('topic1', ['http://uri:1', 'http://uri:1b']),
('topic1b', ['http://foo:1', 'http://foo:1b'])]
m.handler = BadHandler2()
m.run()
# m.start should return immediately as m.master_uri is not set
self.assertEquals(m.master_uri, None)
m.start(None, None)
# test that it returns if URIs are equal
m.start('http://localhost:1234', 'http://localhost:1234')
# - test with is_shutdown overriden so we don't enter loop
def foo():
return True
sys.modules['rospy.impl.registration'].__dict__['is_shutdown'] = foo
m.start('http://localhost:1234', 'http://localhost:4567')
handler.done = True
# handler done is true, so this should not run
m.run()
# no master uri, so these should just return
m.master_uri = None
m.reg_added('n1', 'type1', 'rtype1')
m.reg_removed('n1', 'type1', 'rtype1')
m.cleanup('reason')

View File

@@ -0,0 +1,389 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import time
import random
import rospy.rostime
try:
import cPickle as pickle
except ImportError:
import pickle
# currently tests rospy.rostime, rospy.simtime, and some parts of rospy.client
class TestRospyTime(unittest.TestCase):
def setUp(self):
rospy.rostime.set_rostime_initialized(True)
def test_import_simtime(self):
# trip wire test, make sure the module is loading
import rospy.impl.simtime
# can't actually do unit tests of simtime, requires rosunit
def test_switch_to_wallclock(self):
rospy.rostime.switch_to_wallclock()
self.assertAlmostEqual(time.time(), rospy.get_time(), 1)
def test_Time_get_setstate(self):
# use deepcopy to test getstate/setstate
import copy, random
a = rospy.Time(random.randint(0, 10000), random.randint(0, 10000))
b = copy.deepcopy(a)
self.assertEquals(a.secs, b.secs)
self.assertEquals(a.nsecs, b.nsecs)
buff = StringIO()
pickle.dump(a, buff)
buff.seek(0)
c = pickle.load(buff)
self.assertEquals(a.secs, c.secs)
self.assertEquals(a.nsecs, c.nsecs)
def test_Duration_get_setstate(self):
# use deepcopy to test getstate/setstate
import copy, random
a = rospy.Duration(random.randint(0, 10000), random.randint(0, 10000))
b = copy.deepcopy(a)
self.assertEquals(a.secs, b.secs)
self.assertEquals(a.nsecs, b.nsecs)
buff = StringIO()
pickle.dump(a, buff)
buff.seek(0)
c = pickle.load(buff)
self.assertEquals(a.secs, c.secs)
self.assertEquals(a.nsecs, c.nsecs)
def test_Time(self):
# This is a copy of test_roslib_rostime
from rospy import Time, Duration
# #1600 Duration > Time should fail
failed = False
try:
v = Duration.from_sec(0.1) > Time.from_sec(0.5)
failed = True
except: pass
self.failIf(failed, "should have failed to compare")
try:
v = Time.from_sec(0.4) > Duration.from_sec(0.1)
failed = True
except: pass
self.failIf(failed, "should have failed to compare")
try: # neg time fails
Time(-1)
failed = True
except: pass
self.failIf(failed, "negative time not allowed")
try:
Time(1, -1000000001)
failed = True
except: pass
self.failIf(failed, "negative time not allowed")
# test Time.now() is within 10 seconds of actual time (really generous)
import time
t = time.time()
v = Time.from_sec(t)
self.assertEquals(v.to_sec(), t)
# test from_sec()
self.assertEquals(Time.from_sec(0), Time())
self.assertEquals(Time.from_sec(1.), Time(1))
self.assertEquals(Time.from_sec(v.to_sec()), v)
self.assertEquals(v.from_sec(v.to_sec()), v)
# test to_time()
self.assertEquals(v.to_sec(), v.to_time())
# test addition
# - time + time fails
try:
v = Time(1,0) + Time(1, 0)
failed = True
except: pass
self.failIf(failed, "Time + Time must fail")
# - time + duration
v = Time(1,0) + Duration(1, 0)
self.assertEquals(Time(2, 0), v)
v = Duration(1, 0) + Time(1,0)
self.assertEquals(Time(2, 0), v)
v = Time(1,1) + Duration(1, 1)
self.assertEquals(Time(2, 2), v)
v = Duration(1, 1) + Time(1,1)
self.assertEquals(Time(2, 2), v)
v = Time(1) + Duration(0, 1000000000)
self.assertEquals(Time(2), v)
v = Duration(1) + Time(0, 1000000000)
self.assertEquals(Time(2), v)
v = Time(100, 100) + Duration(300)
self.assertEquals(Time(400, 100), v)
v = Duration(300) + Time(100, 100)
self.assertEquals(Time(400, 100), v)
v = Time(100, 100) + Duration(300, 300)
self.assertEquals(Time(400, 400), v)
v = Duration(300, 300) + Time(100, 100)
self.assertEquals(Time(400, 400), v)
v = Time(100, 100) + Duration(300, -101)
self.assertEquals(Time(399, 999999999), v)
v = Duration(300, -101) + Time(100, 100)
self.assertEquals(Time(399, 999999999), v)
# test subtraction
try:
v = Time(1,0) - 1
failed = True
except: pass
self.failIf(failed, "Time - non Duration must fail")
class Foob(object): pass
try:
v = Time(1,0) - Foob()
failed = True
except: pass
self.failIf(failed, "Time - non TVal must fail")
# - Time - Duration
v = Time(1,0) - Duration(1, 0)
self.assertEquals(Time(), v)
v = Time(1,1) - Duration(-1, -1)
self.assertEquals(Time(2, 2), v)
v = Time(1) - Duration(0, 1000000000)
self.assertEquals(Time(), v)
v = Time(2) - Duration(0, 1000000000)
self.assertEquals(Time(1), v)
v = Time(400, 100) - Duration(300)
self.assertEquals(Time(100, 100), v)
v = Time(100, 100) - Duration(0, 101)
self.assertEquals(Time(99, 999999999), v)
# - Time - Time = Duration
v = Time(100, 100) - Time(100, 100)
self.assertEquals(Duration(), v)
v = Time(100, 100) - Time(100)
self.assertEquals(Duration(0,100), v)
v = Time(100) - Time(200)
self.assertEquals(Duration(-100), v)
def test_Duration(self):
Duration = rospy.Duration
# test from_sec
v = Duration(1000)
self.assertEquals(v, Duration.from_sec(v.to_sec()))
self.assertEquals(v, v.from_sec(v.to_sec()))
v = Duration(0,1000)
self.assertEquals(v, Duration.from_sec(v.to_sec()))
self.assertEquals(v, v.from_sec(v.to_sec()))
# test neg
v = -Duration(1, -1)
self.assertEquals(-1, v.secs)
self.assertEquals(1, v.nsecs)
v = -Duration(-1, -1)
self.assertEquals(1, v.secs)
self.assertEquals(1, v.nsecs)
v = -Duration(-1, 1)
self.assertEquals(0, v.secs)
self.assertEquals(999999999, v.nsecs)
# test addition
failed = False
try:
v = Duration(1,0) + Time(1, 0)
failed = True
except: pass
self.failIf(failed, "Duration + Time must fail")
try:
v = Duration(1,0) + 1
failed = True
except: pass
self.failIf(failed, "Duration + int must fail")
v = Duration(1,0) + Duration(1, 0)
self.assertEquals(2, v.secs)
self.assertEquals(0, v.nsecs)
self.assertEquals(Duration(2, 0), v)
v = Duration(-1,-1) + Duration(1, 1)
self.assertEquals(0, v.secs)
self.assertEquals(0, v.nsecs)
self.assertEquals(Duration(), v)
v = Duration(1) + Duration(0, 1000000000)
self.assertEquals(2, v.secs)
self.assertEquals(0, v.nsecs)
self.assertEquals(Duration(2), v)
v = Duration(100, 100) + Duration(300)
self.assertEquals(Duration(400, 100), v)
v = Duration(100, 100) + Duration(300, 300)
self.assertEquals(Duration(400, 400), v)
v = Duration(100, 100) + Duration(300, -101)
self.assertEquals(Duration(399, 999999999), v)
# test subtraction
try:
v = Duration(1,0) - 1
failed = True
except: pass
self.failIf(failed, "Duration - non duration must fail")
try:
v = Duration(1, 0) - Time(1,0)
failed = True
except: pass
self.failIf(failed, "Duration - Time must fail")
v = Duration(1,0) - Duration(1, 0)
self.assertEquals(Duration(), v)
v = Duration(-1,-1) - Duration(1, 1)
self.assertEquals(Duration(-3, 999999998), v)
v = Duration(1) - Duration(0, 1000000000)
self.assertEquals(Duration(), v)
v = Duration(2) - Duration(0, 1000000000)
self.assertEquals(Duration(1), v)
v = Duration(100, 100) - Duration(300)
self.assertEquals(Duration(-200, 100), v)
v = Duration(100, 100) - Duration(300, 101)
self.assertEquals(Duration(-201, 999999999), v)
# test abs
self.assertEquals(abs(Duration()), Duration())
self.assertEquals(abs(Duration(1)), Duration(1))
self.assertEquals(abs(Duration(-1)), Duration(1))
self.assertEquals(abs(Duration(0,-1)), Duration(0,1))
self.assertEquals(abs(Duration(-1,-1)), Duration(1,1))
def test_set_rostime(self):
from rospy.rostime import _set_rostime
from rospy import Time
self.assertAlmostEqual(time.time(), rospy.get_time(), 1)
for t in [Time.from_sec(1.0), Time.from_sec(4.0)]:
_set_rostime(t)
self.assertEquals(t, rospy.get_rostime())
self.assertEquals(t.to_time(), rospy.get_time())
def test_get_rostime(self):
rospy.rostime.switch_to_wallclock()
self.assertAlmostEqual(time.time(), rospy.get_time(), 1)
self.assertAlmostEqual(time.time(), rospy.get_rostime().to_time(), 1)
#rest of get_rostime implicitly tested by update_rostime tests
def test_sleep(self):
# test wallclock sleep
rospy.rostime.switch_to_wallclock()
rospy.sleep(0.1)
rospy.sleep(rospy.Duration.from_sec(0.1))
from rospy.rostime import _set_rostime
from rospy import Time
t = Time.from_sec(1.0)
_set_rostime(t)
self.assertEquals(t, rospy.get_rostime())
self.assertEquals(t.to_time(), rospy.get_time())
import threading
#start sleeper
self.failIf(test_sleep_done)
sleepthread = threading.Thread(target=sleeper, args=())
sleepthread.setDaemon(True)
sleepthread.start()
time.sleep(1.0) #make sure thread is spun up
self.failIf(test_sleep_done)
t = Time.from_sec(1000000.0)
_set_rostime(t)
time.sleep(0.5) #give sleeper time to wakeup
self.assert_(test_sleep_done, "sleeper did not wake up")
#start duration sleeper
self.failIf(test_duration_sleep_done)
dursleepthread = threading.Thread(target=duration_sleeper, args=())
dursleepthread.setDaemon(True)
dursleepthread.start()
time.sleep(1.0) #make sure thread is spun up
self.failIf(test_duration_sleep_done)
t = Time.from_sec(2000000.0)
_set_rostime(t)
time.sleep(0.5) #give sleeper time to wakeup
self.assert_(test_sleep_done, "sleeper did not wake up")
#start backwards sleeper
self.failIf(test_backwards_sleep_done)
backsleepthread = threading.Thread(target=backwards_sleeper, args=())
backsleepthread.setDaemon(True)
backsleepthread.start()
time.sleep(1.0) #make sure thread is spun up
self.failIf(test_backwards_sleep_done)
t = Time.from_sec(1.0)
_set_rostime(t)
time.sleep(0.5) #give sleeper time to wakeup
self.assert_(test_backwards_sleep_done, "backwards sleeper was not given an exception")
test_duration_sleep_done = False
def duration_sleeper():
global test_duration_sleep_done
rospy.sleep(rospy.Duration(10000.0))
test_duration_sleep_done = True
test_sleep_done = False
def sleeper():
global test_sleep_done
rospy.sleep(10000.0)
test_sleep_done = True
test_backwards_sleep_done = False
def backwards_sleeper():
global test_backwards_sleep_done
try:
rospy.sleep(10000.0)
except rospy.ROSException:
test_backwards_sleep_done = True

View File

@@ -0,0 +1,98 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
import rospy
import rospy.service
class MockServiceClass(object):
_request_class = rospy.AnyMsg
_response_class = rospy.AnyMsg
class TestRospyService(unittest.TestCase):
def test_ServiceException(self):
self.assert_(isinstance(rospy.service.ServiceException(), Exception))
def test_ServiceManager(self):
class MockService(rospy.service._Service):
def __init__(self, name, service_class, uri):
rospy.service._Service.__init__(self, name, service_class)
self.uri = uri
from rospy.service import ServiceManager
sm = ServiceManager()
self.assertEquals({}, sm.map)
try:
sm.lock.acquire()
finally:
sm.lock.release()
self.assertEquals([], sm.get_services())
sm.unregister_all()
self.assertEquals([], sm.get_services())
# test actual registration
mock = MockService('/serv', MockServiceClass, "rosrpc://uri:1")
mock2 = MockService('/serv', MockServiceClass, "rosrpc://uri:2")
sm.register('/serv', mock)
self.assertEquals(mock, sm.get_service('/serv'))
self.assertEquals([('/serv', mock.uri)], sm.get_services())
try:
sm.register('/serv', mock2)
self.fail("duplicate reg should fail")
except rospy.service.ServiceException: pass
sm.unregister_all()
self.assertEquals([], sm.get_services())
# - register two services
sm.register('/serv', mock)
sm.unregister('/serv', mock2)
self.assertEquals(mock, sm.get_service('/serv'))
sm.register('/serv2', mock2)
self.assertEquals(mock, sm.get_service('/serv'))
self.assertEquals(mock2, sm.get_service('/serv2'))
self.assert_(('/serv', mock.uri) in sm.get_services())
self.assert_(('/serv2', mock2.uri) in sm.get_services())
sm.unregister('/serv', mock)
self.assertEquals([('/serv2', mock2.uri)], sm.get_services())
sm.unregister('/serv2', mock2)
self.assertEquals([], sm.get_services())

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
class TestRospyTcpros(unittest.TestCase):
def test_init_tcpros(self):
import rospy.impl.tcpros
rospy.impl.tcpros.init_tcpros()
# nothing to validate here other than make sure no exceptions
def test_syms(self):
import rospy.impl.tcpros
import rospy.impl.transport
self.assertEquals(int, type(rospy.impl.tcpros.DEFAULT_BUFF_SIZE))
self.assert_(isinstance(rospy.impl.tcpros.get_tcpros_handler(), rospy.impl.transport.ProtocolHandler))

View File

@@ -0,0 +1,169 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import rospy
g_fileno = 1
class MockSock:
def __init__(self, buff):
global g_fileno
g_fileno += 1
self.buff = buff
self._fileno = g_fileno
def fileno(self):
return self._fileno
def recv(self, buff_size):
return self.buff[:buff_size]
def close(self):
self.buff = None
def getsockname(self):
return (None, None)
class MockEmptySock:
def __init__(self):
global g_fileno
g_fileno += 1
self._fileno = g_fileno
def fileno(self):
return self._fileno
def recv(self, buff_size):
return ''
def close(self):
self.buff = None
class TestRospyTcprosBase(unittest.TestCase):
def test_constants(self):
self.assertEquals("TCPROS", rospy.impl.tcpros_base.TCPROS)
self.assert_(type(rospy.impl.tcpros_base.DEFAULT_BUFF_SIZE), int)
def test_recv_buff(self):
from rospy.impl.tcpros_base import recv_buff
buff = StringIO()
try:
recv_buff(MockEmptySock(), buff, 1)
self.fail("recv_buff should have raised TransportTerminated")
except rospy.impl.tcpros_base.TransportTerminated:
self.assertEquals('', buff.getvalue())
self.assertEquals(5, recv_buff(MockSock('1234567890'), buff, 5))
self.assertEquals('12345', buff.getvalue())
buff = StringIO()
self.assertEquals(10, recv_buff(MockSock('1234567890'), buff, 100))
self.assertEquals('1234567890', buff.getvalue())
def test_TCPServer(self):
from rospy.impl.tcpros_base import TCPServer
def handler(sock, addr):
pass
s = None
try:
s = TCPServer(handler)
self.assert_(s.port > 0)
addr, port = s.get_full_addr()
self.assert_(type(addr) == str)
self.assertEquals(handler, s.inbound_handler)
self.failIf(s.is_shutdown)
finally:
if s is not None:
s.shutdown()
self.assert_(s.is_shutdown)
def test_TCPROSTransportProtocol(self):
import rospy
import random
from rospy.impl.tcpros_base import TCPROSTransportProtocol
from rospy.impl.transport import BIDIRECTIONAL
p = TCPROSTransportProtocol('Bob', rospy.AnyMsg)
self.assertEquals('Bob', p.resolved_name)
self.assertEquals(rospy.AnyMsg, p.recv_data_class)
self.assertEquals(BIDIRECTIONAL, p.direction)
self.assertEquals({}, p.get_header_fields())
self.assertEquals(rospy.impl.tcpros_base.DEFAULT_BUFF_SIZE, p.buff_size)
v = random.randint(1, 100)
p = TCPROSTransportProtocol('Bob', rospy.AnyMsg, queue_size=v)
self.assertEquals(v, p.queue_size)
v = random.randint(1, 100)
p = TCPROSTransportProtocol('Bob', rospy.AnyMsg, buff_size=v)
self.assertEquals(v, p.buff_size)
def test_TCPROSTransport(self):
import rospy.impl.tcpros_base
from rospy.impl.tcpros_base import TCPROSTransport, TCPROSTransportProtocol
from rospy.impl.transport import OUTBOUND
p = TCPROSTransportProtocol('Bob', rospy.AnyMsg)
p.direction = OUTBOUND
try:
TCPROSTransport(p, '')
self.fail("TCPROSTransport should not accept bad name")
except rospy.impl.tcpros_base.TransportInitError: pass
t = TCPROSTransport(p, 'transport-name')
self.assert_(t.socket is None)
self.assert_(t.md5sum is None)
self.assert_(t.type is None)
self.assertEquals(p, t.protocol)
self.assertEquals('TCPROS', t.transport_type)
self.assertEquals(OUTBOUND, t.direction)
self.assertEquals('unknown', t.endpoint_id)
self.assertEquals(b'', t.read_buff.getvalue())
self.assertEquals(b'', t.write_buff.getvalue())
s = MockSock('12345')
t.set_socket(s, 'new_endpoint_id')
self.assertEquals('new_endpoint_id', t.endpoint_id)
self.assertEquals(s, t.socket)
t.close()
self.assert_(t.socket is None)
self.assert_(t.read_buff is None)
self.assert_(t.write_buff is None)
self.assert_(t.protocol is None)

View File

@@ -0,0 +1,237 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import socket
import struct
import unittest
import time
class FakeSocket(object):
def __init__(self):
self.data = b''
self.sockopt = None
def fileno(self):
# fool select logic by giving it stdout fileno
return 1
def setblocking(self, *args):
pass
def setsockopt(self, *args):
self.sockopt = args
def send(self, d):
self.data = self.data+d
return len(d)
def sendall(self, d):
self.data = self.data+d
def close(self):
pass
def getsockname(self):
return (None, None)
# test rospy API verifies that the rospy module exports the required symbols
class TestRospyTcprosPubsub(unittest.TestCase):
def test_TCPROSSub(self):
import rospy.impl.transport
from rospy.impl.tcpros_pubsub import TCPROSSub
import test_rospy.msg
callerid = 'test_TCPROSSub'
import rospy.names
rospy.names._set_caller_id(callerid)
#name, recv_data_class, queue_size=None, buff_size=DEFAULT_BUFF_SIZE
name = 'name-%s'%time.time()
recv_data_class = test_rospy.msg.Val
s = TCPROSSub(name, recv_data_class)
self.assertEquals(name, s.resolved_name)
self.assertEquals(rospy.impl.transport.INBOUND, s.direction)
self.assertEquals(recv_data_class, s.recv_data_class)
self.assert_(s.buff_size > -1)
self.failIf(s.tcp_nodelay)
self.assertEquals(None, s.queue_size)
fields = s.get_header_fields()
self.assertEquals(name, fields['topic'])
self.assertEquals(recv_data_class._md5sum, fields['md5sum'])
self.assertEquals(recv_data_class._full_text, fields['message_definition'])
self.assertEquals('test_rospy/Val', fields['type'])
self.assert_(callerid, fields['callerid'])
if 'tcp_nodelay' in fields:
self.assertEquals('0', fields['tcp_nodelay'])
v = int(time.time())
s = TCPROSSub(name, recv_data_class, queue_size=v)
self.assertEquals(v, s.queue_size)
s = TCPROSSub(name, recv_data_class, buff_size=v)
self.assertEquals(v, s.buff_size)
s = TCPROSSub(name, recv_data_class, tcp_nodelay=True)
self.assert_(s.tcp_nodelay)
self.assertEquals('1', s.get_header_fields()['tcp_nodelay'])
def test_TCPROSPub(self):
import rospy.impl.transport
from rospy.impl.tcpros_pubsub import TCPROSPub
import test_rospy.msg
callerid = 'test_TCPROSPub'
import rospy.names
rospy.names._set_caller_id(callerid)
#name, pub_data_class
name = 'name-%s'%time.time()
pub_data_class = test_rospy.msg.Val
p = TCPROSPub(name, pub_data_class)
self.assertEquals(name, p.resolved_name)
self.assertEquals(rospy.impl.transport.OUTBOUND, p.direction)
self.assertEquals(pub_data_class, p.pub_data_class)
self.assert_(p.buff_size > -1)
self.failIf(p.is_latch)
fields = p.get_header_fields()
self.assertEquals(name, fields['topic'])
self.assertEquals(pub_data_class._md5sum, fields['md5sum'])
self.assertEquals(pub_data_class._full_text, fields['message_definition'])
self.assertEquals('test_rospy/Val', fields['type'])
self.assert_(callerid, fields['callerid'])
if 'latching' in fields:
self.assertEquals('0', fields['latching'])
p = TCPROSPub(name, pub_data_class, is_latch=True)
self.assert_(p.is_latch)
self.assertEquals('1', p.get_header_fields()['latching'])
# test additional header fields
p = TCPROSPub(name, pub_data_class, headers={'foo': 'bar', 'hoge': 'fuga'})
fields = p.get_header_fields()
self.assertEquals(name, fields['topic'])
self.assertEquals('fuga', fields['hoge'])
self.assertEquals('bar', fields['foo'])
def test_configure_pub_socket(self):
# #1241 regression test to make sure that imports don't get messed up again
from rospy.impl.tcpros_pubsub import _configure_pub_socket
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
_configure_pub_socket(sock, True)
sock.close()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
_configure_pub_socket(sock, False)
sock.close()
def test_TCPROSHandler_topic_connection_handler(self):
import rospy
import rospy.core
# very ugly hack to handle bad design choice in rospy and bad isolation inside of nose
rospy.core._shutdown_flag = False
rospy.core._in_shutdown = False
from rospy.impl.registration import Registration
from rospy.impl.tcpros_pubsub import TCPROSHandler
import test_rospy.msg
handler = TCPROSHandler()
tch = handler.topic_connection_handler
sock = FakeSocket()
client_addr = '127.0.0.1'
data_class = test_rospy.msg.Val
topic_name = '/foo-tch'
headers = { 'topic': topic_name, 'md5sum': data_class._md5sum, 'callerid': '/node'}
# test required logic
for k in headers.keys():
header_copy = headers.copy()
del header_copy[k]
err = tch(sock, client_addr, header_copy)
self.assertNotEquals('', err)
# '/foo-tch' is not registered, so this should error
err = tch(sock, client_addr, headers)
self.assert_(err)
# register '/foo-tch'
tm = rospy.impl.registration.get_topic_manager()
impl = tm.acquire_impl(Registration.PUB, topic_name, data_class)
self.assert_(impl is not None)
# test with mismatched md5sum
header_copy = headers.copy()
header_copy['md5sum'] = 'bad'
md5_err = tch(sock, client_addr, header_copy)
self.assert_("md5sum" in md5_err, md5_err)
# now test with correct params
err = tch(sock, client_addr, headers)
self.failIf(err)
self.assertEquals(None, sock.sockopt)
# test with mismatched type
# - if md5sums match, this should not error
header_copy = headers.copy()
header_copy['type'] = 'bad_type/Bad'
err = tch(sock, client_addr, header_copy)
self.failIf(err)
# - now give mismatched md5sum, this will test different error message
header_copy['md5sum'] = 'bad'
type_md5_err = tch(sock, client_addr, header_copy)
self.assert_("types" in type_md5_err, type_md5_err)
# - these error messages should be different
self.assertNotEquals(md5_err, type_md5_err)
# test tcp_nodelay
# - should be equivalent to above
headers['tcp_nodelay'] = '0'
err = tch(sock, client_addr, headers)
self.failIf(err)
self.assertEquals(None, sock.sockopt)
# - now test actual sock opt
headers['tcp_nodelay'] = '1'
err = tch(sock, client_addr, headers)
self.failIf(err)
self.assertEquals((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1), sock.sockopt)
# test connection headers
impl.headers = {'foo': 'baz', 'hoge': 'fuga'}
headers['tcp_nodelay'] = '0'
err = tch(sock, client_addr, headers)
self.failIf(err)
connection = impl.connections[-1]
fields = connection.protocol.get_header_fields()
self.assertEquals(impl.resolved_name, fields['topic'])
self.assertEquals('fuga', fields['hoge'])
self.assertEquals('baz', fields['foo'])

View File

@@ -0,0 +1,234 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import socket
import struct
import unittest
import time
class FakeSocket(object):
def __init__(self):
self.data = ''
self.sockopt = None
def fileno(self):
# fool select logic by giving it stdout fileno
return 1
def setblocking(self, *args):
pass
def setsockopt(self, *args):
self.sockopt = args
def send(self, d):
self.data = self.data+d
return len(d)
def sendall(self, d):
self.data = self.data+d
def close(self):
pass
# test service implementation
class TestRospyTcprosService(unittest.TestCase):
def test_convert_return_to_response(self):
import rospy
from rospy.impl.tcpros_service import convert_return_to_response
from test_rosmaster.srv import AddTwoIntsResponse
cls = AddTwoIntsResponse
v = cls(3)
# test various ways that a user could reasonable return a
# value for a single-arg message. This is actually our hardest
# case.
self.assertEquals(v, convert_return_to_response(v, cls))
self.assertEquals(v, convert_return_to_response(3, cls))
self.assertEquals(v, convert_return_to_response((3), cls))
self.assertEquals(v, convert_return_to_response([3], cls))
self.assertEquals(v, convert_return_to_response({'sum':3}, cls))
for bad in [[1, 2, 3], {'fake': 1}]:
try:
convert_return_to_response(bad, cls)
self.fail("should have raised: %s"%str(bad))
except rospy.ServiceException:
pass
# test multi-arg services
from test_rospy.srv import MultipleAddTwoIntsResponse
cls = MultipleAddTwoIntsResponse
v = cls(1, 2)
self.assertEquals(v, convert_return_to_response(v, cls))
self.assertEquals(v, convert_return_to_response((1, 2), cls))
self.assertEquals(v, convert_return_to_response([1, 2], cls))
self.assertEquals(v, convert_return_to_response({'ab':1, 'cd': 2}, cls))
for bad in [1, AddTwoIntsResponse(), [1, 2, 3], {'fake': 1}]:
try:
convert_return_to_response(bad, cls)
self.fail("should have raised: %s"%str(bad))
except rospy.ServiceException:
pass
# test response with single, array field
from test_rospy.srv import ListReturnResponse
cls = ListReturnResponse
v = cls([1, 2, 3])
self.assertEquals(v, convert_return_to_response(v, cls))
self.assertEquals(v, convert_return_to_response(((1, 2, 3),), cls))
self.assertEquals(v, convert_return_to_response(([1, 2, 3],), cls))
self.assertEquals(v, convert_return_to_response([[1, 2, 3]], cls))
self.assertEquals(v, convert_return_to_response({'abcd':[1,2,3]}, cls))
for bad in [[1, 2, 3], {'fake': 1}]:
try:
convert_return_to_response(bad, cls)
self.fail("should have raised: %s"%str(bad))
except rospy.ServiceException:
pass
# test with empty response
from test_rospy.srv import EmptySrvResponse
cls = EmptySrvResponse
v = cls()
# - only valid return values are empty list, empty dict and a response instance
self.assertEquals(v, convert_return_to_response(v, cls))
self.assertEquals(v, convert_return_to_response([], cls))
self.assertEquals(v, convert_return_to_response({}, cls))
# #2185: currently empty does not do any checking whatsoever,
# disabling this test as it is not convert()s fault
if 0:
for bad in [1, AddTwoIntsResponse(), [1, 2, 3], {'fake': 1}]:
try:
convert_return_to_response(bad, cls)
self.fail("should have raised: %s"%str(bad))
except rospy.ServiceException:
pass
def test_service_connection_handler(self):
import test_rospy.srv
from rospy.impl.registration import get_service_manager
import rospy.service
sock = FakeSocket()
from rospy.impl.tcpros_service import service_connection_handler
client_addr = '10.0.0.1'
# check error conditions on missing headers
self.assert_("Missing" in service_connection_handler(sock, client_addr, {}))
header = { 'service' : '/service', 'md5sum': '*', 'callerid': '/bob' }
for k in header:
c = header.copy()
del c[k]
msg = service_connection_handler(sock, client_addr, c)
self.assert_("Missing" in msg, str(c) + msg)
self.assert_(k in msg, msg)
# check error condition on invalid service
header['service'] = '/doesnotexist'
msg = service_connection_handler(sock, client_addr, header)
self.assert_('is not a provider' in msg, msg)
# check invalid md5sums
name = '/service'
sm = get_service_manager()
fake_service = \
rospy.service._Service(name, test_rospy.srv.EmptySrv)
sm.register(name, fake_service)
header['service'] = name
header['md5sum'] = 'X'
msg = service_connection_handler(sock, client_addr, header)
self.assert_('md5sums do not match' in msg, msg)
def test_TCPROSServiceClient(self):
import rospy.impl.transport
from rospy.impl.tcpros_service import TCPROSServiceClient
import test_rospy.srv
callerid = 'test_TCPROSServiceClient'
import rospy.names
rospy.names._set_caller_id(callerid)
#name, pub_data_class
name = 'name-%s'%time.time()
srv_data_class = test_rospy.srv.EmptySrv
p = TCPROSServiceClient(name, srv_data_class)
self.assertEquals(name, p.resolved_name)
self.assertEquals(rospy.impl.transport.BIDIRECTIONAL, p.direction)
self.assertEquals(srv_data_class, p.service_class)
self.assert_(p.buff_size > -1)
p = TCPROSServiceClient(name, srv_data_class, buff_size=1)
self.assert_(1, p.buff_size)
fields = p.get_header_fields()
self.assertEquals(name, fields['service'])
self.assertEquals(srv_data_class._md5sum, fields['md5sum'])
# test custom headers
headers = {'sessionid': '123456', 'persistent': '1'}
p = TCPROSServiceClient(name, srv_data_class, headers=headers)
self.assertEquals('123456', p.get_header_fields()['sessionid'])
self.assertEquals('1', p.get_header_fields()['persistent'])
# - make sure builtins are still there
self.assertEquals(name, fields['service'])
self.assertEquals(srv_data_class._md5sum, fields['md5sum'])
def test_TCPService(self):
import rospy.impl.transport
from rospy.impl.tcpros_service import TCPService
import test_rospy.srv
callerid = 'test_TCPService'
import rospy.names
rospy.names._set_caller_id(callerid)
#name, pub_data_class
name = 'name-%s'%time.time()
srv_data_class = test_rospy.srv.EmptySrv
p = TCPService(name, srv_data_class)
self.assertEquals(name, p.resolved_name)
self.assertEquals(rospy.impl.transport.BIDIRECTIONAL, p.direction)
self.assertEquals(srv_data_class, p.service_class)
self.assert_(p.buff_size > -1)
p = TCPService(name, srv_data_class, buff_size=1)
self.assert_(1, p.buff_size)
fields = p.get_header_fields()
self.assertEquals(name, fields['service'])
self.assertEquals(srv_data_class._md5sum, fields['md5sum'])
self.assertEquals(srv_data_class._type, fields['type'])

View File

@@ -0,0 +1,431 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
import test_rospy.msg
def callback1(data): pass
def callback2(data): pass
# for use with publish() tests
import rospy.impl.transport
class ConnectionOverride(rospy.impl.transport.Transport):
def __init__(self, endpoint_id):
super(ConnectionOverride, self).__init__(rospy.impl.transport.OUTBOUND, endpoint_id)
self.endpoint_id = endpoint_id
self.data = ''
def set_cleanup_callback(self, cb): pass
def write_data(self, data):
self.data = self.data + data
# test rospy API verifies that the rospy module exports the required symbols
class TestRospyTopics(unittest.TestCase):
def test_add_connection(self):
from rospy.topics import _TopicImpl
from std_msgs.msg import String
t = _TopicImpl('/foo', String)
c1 = ConnectionOverride('c1')
c1b = ConnectionOverride('c1')
c2 = ConnectionOverride('c2')
c3 = ConnectionOverride('c3')
assert not t.has_connection('c1')
assert t.get_num_connections() == 0
t.add_connection(c1)
assert t.get_num_connections() == 1
assert t.has_connection('c1')
t.add_connection(c1b)
assert t.get_num_connections() == 1
assert t.has_connection('c1')
# should not remove
t.remove_connection(c1)
assert t.has_connection('c1')
t.remove_connection(c1b)
assert not t.has_connection('c1')
t.close()
assert t.get_num_connections() == 0
t = _TopicImpl('/foo', String)
t.add_connection(c1)
t.add_connection(c2)
t.add_connection(c3)
for x in ['c1', 'c2', 'c3']:
assert t.has_connection(x)
assert t.get_num_connections() == 3
t.close()
assert t.get_num_connections() == 0
def test_Publisher(self):
import rospy
from rospy.impl.registration import get_topic_manager, Registration
from rospy.topics import Publisher, DEFAULT_BUFF_SIZE
# Publisher(self, name, data_class, subscriber_listener=None, tcp_nodelay=False, latch=False, headers=None)
name = 'foo'
rname = rospy.resolve_name('foo')
data_class = test_rospy.msg.Val
# test invalid params
for n in [None, '', 1]:
try:
Publisher(n, data_class)
self.fail("should not allow invalid name")
except ValueError: pass
for d in [None, 1, TestRospyTopics]:
try:
Publisher(name, d)
self.fail("should now allow invalid data_class")
except ValueError: pass
try:
Publisher(name, None)
self.fail("None should not be allowed for data_class")
except ValueError: pass
# round 1: test basic params
pub = Publisher(name, data_class)
self.assertEquals(rname, pub.resolved_name)
# - pub.name is left in for backwards compatiblity, but resolved_name is preferred
self.assertEquals(rname, pub.name)
self.assertEquals(data_class, pub.data_class)
self.assertEquals('test_rospy/Val', pub.type)
self.assertEquals(data_class._md5sum, pub.md5sum)
self.assertEquals(Registration.PUB, pub.reg_type)
# verify impl as well
impl = get_topic_manager().get_impl(Registration.PUB, rname)
self.assert_(impl == pub.impl)
self.assertEquals(rname, impl.resolved_name)
self.assertEquals(data_class, impl.data_class)
self.failIf(impl.is_latch)
self.assertEquals(None, impl.latch)
self.assertEquals(0, impl.seq)
self.assertEquals(1, impl.ref_count)
self.assertEquals(b'', impl.buff.getvalue())
self.failIf(impl.closed)
self.failIf(impl.has_connections())
# check publish() fall-through
from test_rospy.msg import Val
impl.publish(Val('hello world-1'))
# check stats
self.assertEquals(0, impl.message_data_sent)
# check acquire/release don't bomb
impl.acquire()
impl.release()
# do a single publish with connection override. The connection
# override is a major cheat as the object isn't even an actual
# connection. I will need to add more integrated tests later
co1 = ConnectionOverride('co1')
self.failIf(impl.has_connection('co1'))
impl.add_connection(co1)
self.assert_(impl.has_connection('co1'))
self.assert_(impl.has_connections())
impl.publish(Val('hello world-1'), connection_override=co1)
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
buff = StringIO()
Val('hello world-1').serialize(buff)
# - check equals, but strip length field first
self.assertEquals(co1.data[4:], buff.getvalue())
self.assertEquals(None, impl.latch)
# Now enable latch
pub = Publisher(name, data_class, latch=True)
impl = get_topic_manager().get_impl(Registration.PUB, rname)
# have to verify latching in pub impl
self.assert_(impl == pub.impl)
self.assertEquals(True, impl.is_latch)
self.assertEquals(None, impl.latch)
self.assertEquals(2, impl.ref_count)
co2 = ConnectionOverride('co2')
self.failIf(impl.has_connection('co2'))
impl.add_connection(co2)
for n in ['co1', 'co2']:
self.assert_(impl.has_connection(n))
self.assert_(impl.has_connections())
v = Val('hello world-2')
impl.publish(v, connection_override=co2)
self.assert_(v == impl.latch)
buff = StringIO()
Val('hello world-2').serialize(buff)
# - strip length and check value
self.assertEquals(co2.data[4:], buff.getvalue())
# test that latched value is sent to connections on connect
co3 = ConnectionOverride('co3')
self.failIf(impl.has_connection('co3'))
impl.add_connection(co3)
for n in ['co1', 'co2', 'co3']:
self.assert_(impl.has_connection(n))
self.assert_(impl.has_connections())
self.assertEquals(co3.data[4:], buff.getvalue())
# TODO: tcp_nodelay
# TODO: suscribe listener
self.assert_(impl.has_connection('co1'))
impl.remove_connection(co1)
self.failIf(impl.has_connection('co1'))
self.assert_(impl.has_connections())
self.assert_(impl.has_connection('co3'))
impl.remove_connection(co3)
self.failIf(impl.has_connection('co3'))
self.assert_(impl.has_connections())
self.assert_(impl.has_connection('co2'))
impl.remove_connection(co2)
self.failIf(impl.has_connection('co2'))
self.failIf(impl.has_connections())
# test publish() latch on a new Publisher object (this was encountered in testing, so I want a test case for it)
pub = Publisher('bar', data_class, latch=True)
v = Val('no connection test')
pub.impl.publish(v)
self.assert_(v == pub.impl.latch)
# test connection header
h = {'foo': 'bar', 'fuga': 'hoge'}
pub = Publisher('header_test', data_class, headers=h)
self.assertEquals(h, pub.impl.headers)
def test_Subscriber_unregister(self):
# regression test for #3029 (unregistering a Subcriber with no
# callback) plus other unregistration tests
import rospy
from rospy.impl.registration import get_topic_manager, Registration
from rospy.topics import Subscriber, DEFAULT_BUFF_SIZE
#Subscriber: name, data_class, callback=None, callback_args=None,
#queue_size=None, buff_size=DEFAULT_BUFF_SIZE, tcp_nodelay=False):
name = 'unregistertest'
rname = rospy.resolve_name(name)
data_class = test_rospy.msg.Val
sub = Subscriber(name, data_class)
self.assertEquals(None, sub.callback)
# verify impl (test_Subscriber handles more verification, we
# just care about callbacks and ref_count state here)
impl = get_topic_manager().get_impl(Registration.SUB, rname)
self.assert_(impl == sub.impl)
self.assertEquals(1, impl.ref_count)
self.assertEquals([], impl.callbacks)
# unregister should release the underlying impl
sub.unregister()
self.assertEquals(None, get_topic_manager().get_impl(Registration.SUB, rname))
# create two subs
sub2 = Subscriber(name, data_class)
sub3 = Subscriber(name, data_class)
impl = get_topic_manager().get_impl(Registration.SUB, rname)
# - test that they share the same impl
self.assert_(impl == sub2.impl)
self.assert_(impl == sub3.impl)
# - test basic impl state
self.assertEquals([], impl.callbacks)
self.assertEquals(2, impl.ref_count)
sub2.unregister()
self.assertEquals(1, impl.ref_count)
# - make sure double unregister is safe
sub2.unregister()
self.assertEquals(1, impl.ref_count)
# - clean it up
sub3.unregister()
self.assertEquals(0, impl.ref_count)
self.assertEquals(None, get_topic_manager().get_impl(Registration.SUB, rname))
# CALLBACKS
cb_args5 = 5
cb_args6 = 6
cb_args7 = 7
sub4 = Subscriber(name, data_class, callback1)
# - use should be allowed to subcribe using the same callback
# and it shouldn't interfere on unregister
sub5 = Subscriber(name, data_class, callback2, cb_args5)
sub6 = Subscriber(name, data_class, callback2, cb_args6)
sub7 = Subscriber(name, data_class, callback2, cb_args7)
impl = get_topic_manager().get_impl(Registration.SUB, rname)
self.assertEquals(4, impl.ref_count)
self.assertEquals([(callback1, None), (callback2, cb_args5), (callback2, cb_args6), (callback2, cb_args7)], impl.callbacks)
# unregister sub6 first to as it is most likely to confuse any callback-finding logic
sub6.unregister()
self.assertEquals([(callback1, None), (callback2, cb_args5), (callback2, cb_args7)], impl.callbacks)
self.assertEquals(3, impl.ref_count)
sub5.unregister()
self.assertEquals([(callback1, None), (callback2, cb_args7)], impl.callbacks)
self.assertEquals(2, impl.ref_count)
sub4.unregister()
self.assertEquals([(callback2, cb_args7)], impl.callbacks)
self.assertEquals(1, impl.ref_count)
sub7.unregister()
self.assertEquals([], impl.callbacks)
self.assertEquals(0, impl.ref_count)
self.assertEquals(None, get_topic_manager().get_impl(Registration.SUB, rname))
# one final condition: two identical subscribers
sub8 = Subscriber(name, data_class, callback1, 'hello')
sub9 = Subscriber(name, data_class, callback1, 'hello')
impl = get_topic_manager().get_impl(Registration.SUB, rname)
self.assertEquals([(callback1, 'hello'), (callback1, 'hello')], impl.callbacks)
self.assertEquals(2, impl.ref_count)
sub8.unregister()
self.assertEquals([(callback1, 'hello')], impl.callbacks)
self.assertEquals(1, impl.ref_count)
sub9.unregister()
self.assertEquals([], impl.callbacks)
self.assertEquals(0, impl.ref_count)
def test_Subscriber(self):
#TODO: test callback args
#TODO: negative buff_size
#TODO: negative queue_size
import rospy
from rospy.impl.registration import get_topic_manager, Registration
from rospy.topics import Subscriber, DEFAULT_BUFF_SIZE
#Subscriber: name, data_class, callback=None, callback_args=None,
#queue_size=None, buff_size=DEFAULT_BUFF_SIZE, tcp_nodelay=False):
name = 'foo'
rname = rospy.resolve_name('foo')
data_class = test_rospy.msg.Val
# test invalid params
for n in [None, '', 1]:
try:
Subscriber(n, data_class)
self.fail("should not allow invalid name")
except ValueError: pass
for d in [None, 1, TestRospyTopics]:
try:
Subscriber(name, d)
self.fail("should now allow invalid data_class")
except ValueError: pass
try:
Subscriber(name, None)
self.fail("None should not be allowed for data_class")
except ValueError: pass
sub = Subscriber(name, data_class)
self.assertEquals(rname, sub.resolved_name)
self.assertEquals(data_class, sub.data_class)
self.assertEquals('test_rospy/Val', sub.type)
self.assertEquals(data_class._md5sum, sub.md5sum)
self.assertEquals(Registration.SUB, sub.reg_type)
# verify impl as well
impl = get_topic_manager().get_impl(Registration.SUB, rname)
self.assert_(impl == sub.impl)
self.assertEquals([], impl.callbacks)
self.assertEquals(rname, impl.resolved_name)
self.assertEquals(data_class, impl.data_class)
self.assertEquals(None, impl.queue_size)
self.assertEquals(DEFAULT_BUFF_SIZE, impl.buff_size)
self.failIf(impl.tcp_nodelay)
self.assertEquals(1, impl.ref_count)
self.failIf(impl.closed)
# round 2, now start setting options and make sure underlying impl is reconfigured
name = 'foo'
data_class = test_rospy.msg.Val
queue_size = 1
buff_size = 1
sub = Subscriber(name, data_class, callback=callback1,
queue_size=queue_size, buff_size=buff_size, tcp_nodelay=True)
self.assertEquals(rname, sub.resolved_name)
# - sub.name is a backwards-compat field as it is public API
self.assertEquals(rname, sub.name)
self.assertEquals(data_class, sub.data_class)
# verify impl
impl2 = get_topic_manager().get_impl(Registration.SUB, rname)
self.assert_(impl == impl2) # should be same instance
self.assertEquals([(callback1, None)], impl.callbacks)
self.assertEquals(rname, impl.resolved_name)
self.assertEquals(data_class, impl.data_class)
self.assertEquals(queue_size, impl.queue_size)
self.assertEquals(buff_size, impl.buff_size)
self.assert_(impl.tcp_nodelay)
self.assertEquals(2, impl.ref_count)
self.failIf(impl.closed)
# round 3, make sure that options continue to reconfigure
# underlying impl also test that tcp_nodelay is sticky. this
# is technically undefined, but this is how rospy chose to
# implement.
name = 'foo'
data_class = test_rospy.msg.Val
queue_size = 2
buff_size = 2
sub = Subscriber(name, data_class, callback=callback2,
queue_size=queue_size, buff_size=buff_size, tcp_nodelay=False)
# verify impl
impl2 = get_topic_manager().get_impl(Registration.SUB, rname)
self.assert_(impl == impl2) # should be same instance
self.assertEquals(set([(callback1, None), (callback2, None)]), set(impl.callbacks))
self.assertEquals(queue_size, impl.queue_size)
self.assertEquals(buff_size, impl.buff_size)
self.assert_(impl.tcp_nodelay)
self.assertEquals(3, impl.ref_count)
self.failIf(impl.closed)
def test_Poller(self):
# no real test as this goes down to kqueue/select, just make sure that it behaves
from rospy.topics import Poller
p = Poller()
p.add_fd(1)
for x in p.error_iter():
pass
p.remove_fd(1)
for x in p.error_iter():
pass

View File

@@ -0,0 +1,135 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
class TestRospyTransport(unittest.TestCase):
def test_Transport(self):
from rospy.impl.transport import Transport, INBOUND, OUTBOUND, BIDIRECTIONAL
ids = []
for d in [INBOUND, OUTBOUND, BIDIRECTIONAL]:
t = Transport(d)
self.assertEquals(d, t.direction)
self.assertEquals("UNKNOWN", t.transport_type)
self.failIf(t.done)
self.assertEquals(None, t.cleanup_cb)
self.assertEquals('', t.endpoint_id)
self.assertEquals('unnamed', t.name)
self.assertEquals(0, t.stat_bytes)
self.assertEquals(0, t.stat_num_msg)
self.failIf(t.id in ids)
ids.append(t.id)
t = Transport(d, 'a name')
self.assertEquals(d, t.direction)
self.assertEquals('a name', t.name)
# test cleanup with and without a callback
t = Transport(INBOUND)
t.close()
self.assert_(t.done)
t = Transport(INBOUND)
self.cleanup_obj = None
def cleanup(obj):
self.cleanup_obj = obj
t.set_cleanup_callback(cleanup)
self.assertEquals(t.cleanup_cb, cleanup)
t.close()
self.assert_(t.done)
self.assertEquals(self.cleanup_obj, t)
t = Transport(OUTBOUND)
import traceback
try:
t.send_message('msg', 1)
self.fail("send_message() should be abstract")
except: pass
try:
t.write_data('data')
self.fail("write_data() should be abstract")
except: pass
t = Transport(INBOUND)
try:
t.receive_once()
self.fail("receive_once() should be abstract")
except: pass
t = Transport(INBOUND)
try:
t.receive_loop()
self.fail("receive_loop() should be abstract")
except: pass
def test_DeadTransport(self):
from rospy.impl.transport import Transport, DeadTransport, INBOUND, OUTBOUND, BIDIRECTIONAL
t = Transport(INBOUND, 'foo')
t.stat_bytes = 1234
t.stat_num_msg = 5678
dead = DeadTransport(t)
self.assertEquals(INBOUND, dead.direction)
self.assertEquals('foo', dead.name)
self.assertEquals(1234, dead.stat_bytes)
self.assertEquals(5678, dead.stat_num_msg)
self.assertEquals(True, dead.done)
self.assertEquals('', dead.endpoint_id)
t = Transport(OUTBOUND, 'bar')
t.endpoint_id = 'blah blah'
t.close()
dead = DeadTransport(t)
self.assertEquals(OUTBOUND, dead.direction)
self.assertEquals('bar', dead.name)
self.assertEquals(True, dead.done)
self.assertEquals(t.endpoint_id, dead.endpoint_id)
def test_ProtocolHandler(self):
# tripwire tests
from rospy.impl.transport import ProtocolHandler
h = ProtocolHandler()
self.failIf(h.supports('TCPROS'))
self.assertEquals([], h.get_supported())
try:
h.create_connection("/topic", 'http://localhost:1234', ['TCPROS'])
self.fail("create_connection should raise an exception")
except: pass
try:
h.init_publisher("/topic", 'TCPROS')
self.fail("init_publisher raise an exception")
except: pass
h.shutdown()

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import os
import sys
import struct
import unittest
import time
class TestRospyValidators(unittest.TestCase):
def test_ParameterInvalid(self):
# not really testing anything here other than typos
from rospy.impl.validators import ParameterInvalid
self.assert_(isinstance(ParameterInvalid('param'), Exception))
def test_validators(self):
from rospy.impl.validators import ParameterInvalid
from rospy.impl.validators import non_empty
contextes = ['', '/', '/foo']
for context in contextes:
valid = ['foo', 1, [1]]
for v in valid:
non_empty('param-name')(v, context)
invalid = ['', 0, []]
for i in invalid:
try:
non_empty('param-name-foo')(i, context)
except ParameterInvalid as e:
self.assert_('param-name-foo' in str(e))