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,178 @@
#!/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 signal
import sys
import time
import unittest
import rospy
import rostest
import std_msgs.msg
from subprocess import Popen, PIPE, check_call, call
def run_for(cmd, secs):
popen = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
timeout_t = time.time() + secs
while time.time() < timeout_t:
time.sleep(0.1)
os.kill(popen.pid, signal.SIGKILL)
class TestRostopicOnline(unittest.TestCase):
def setUp(self):
self.vals = set()
self.msgs = {}
def callback(self, msg, val):
self.vals.add(val)
self.msgs[val] = msg
def test_rostopic(self):
topics = ['/chatter', '/foo/chatter', '/bar/chatter']
# wait for network to initialize
rospy.init_node('test')
for i, t in enumerate(topics):
rospy.Subscriber(t, std_msgs.msg.String, self.callback, i)
all = set(range(0, len(topics)))
timeout_t = time.time() + 10.
while time.time() < timeout_t and self.vals != all:
time.sleep(0.1)
# network is initialized
cmd = 'rostopic'
names = ['/chatter', 'foo/chatter']
# list
# - we aren't matching against the core services as those can make the test suites brittle
output = Popen([cmd, 'list'], stdout=PIPE).communicate()[0]
output = output.decode()
l = set(output.split())
for t in topics:
self.assert_(t in l)
for name in names:
# type
output = Popen([cmd, 'type', name], stdout=PIPE).communicate()[0]
output = output.decode()
self.assertEquals('std_msgs/String', output.strip())
# check type of topic field
output = Popen([cmd, 'type', name + '/data'], stdout=PIPE).communicate()[0]
output = output.decode()
self.assertEquals('std_msgs/String data string', output.strip())
# find
output = Popen([cmd, 'find', 'std_msgs/String'], stdout=PIPE).communicate()[0]
output = output.decode()
values = [n.strip() for n in output.split('\n') if n.strip()]
self.assertEquals(set(values), set(topics))
#echo
# test with -c option to get command to terminate
count = 3
output = Popen([cmd, 'echo', name, '-n', str(count)], stdout=PIPE).communicate()[0]
output = output.decode()
values = [n.strip() for n in output.split('\n') if n.strip()]
values = [n for n in values if n != '---']
self.assertEquals(count, len(values), "wrong number of echos in output:\n"+str(values))
for n in values:
self.assert_('data: "hello world ' in n, n)
if 0:
#bw
stdout, stderr = run_for([cmd, 'bw', name], 3.)
self.assert_('average:' in stdout, "OUTPUT: %s\n%s"%(stdout,stderr))
# hz
stdout, stderr = run_for([cmd, 'hz', name], 2.)
self.assert_('average rate:' in stdout)
# delay
stdout, stderr = run_for([cmd, 'delay', name], 2.)
self.assert_('average rate:' in stdout)
# pub
# - pub wait until ctrl-C, so we have to wait then kill it
if 1:
s = 'hello'
t = '/pub/chatter'
key = len(topics)
rospy.Subscriber(t, std_msgs.msg.String, self.callback, key)
#TODO: correct popen call
args = [cmd, 'pub', t, 'std_msgs/String', s]
popen = Popen(args, stdout=PIPE, stderr=PIPE, close_fds=True)
# - give rostopic pub 5 seconds to send us a message
all = set(range(0, key+1))
timeout_t = time.time() + 5.
while time.time() < timeout_t and self.vals != all:
time.sleep(0.1)
# - check published value
msg = self.msgs[key]
self.assertEquals(s, msg.data)
os.kill(popen.pid, signal.SIGKILL)
# test with dictionary
t = '/pub2/chatter'
key = len(topics)+1
rospy.Subscriber(t, std_msgs.msg.String, self.callback, key)
args = [cmd, 'pub', t, 'std_msgs/String', "{data: %s}"%s]
popen = Popen(args, stdout=PIPE, stderr=PIPE, close_fds=True)
# - give rostopic pub 5 seconds to send us a message
all = set(range(0, key+2))
timeout_t = time.time() + 5.
while time.time() < timeout_t and self.vals != all:
time.sleep(0.1)
# - check published value
try:
msg = self.msgs[key]
except KeyError:
self.fail("no message received on "+str(key))
self.assertEquals(s, msg.data)
os.kill(popen.pid, signal.SIGKILL)
PKG = 'test_rostopic'
NAME = 'test_rostopic_command_line_online'
if __name__ == '__main__':
rostest.run(PKG, NAME, TestRostopicOnline, sys.argv)

View File

@@ -0,0 +1,10 @@
<launch>
<node name="talker" pkg="rospy" type="talker.py" />
<group ns="foo">
<node name="talker" pkg="rospy" type="talker.py" />
</group>
<group ns="bar">
<node name="talker" pkg="rospy" type="talker.py" />
</group>
<test test-name="rostopic_command_line_online" pkg="rostopic" type="check_rostopic_command_line_online.py" />
</launch>

View File

@@ -0,0 +1,10 @@
<launch>
<node name="talker" pkg="rospy" type="talker.py" />
<group ns="foo">
<node name="talker" pkg="rospy" type="talker.py" />
</group>
<group ns="bar">
<node name="talker" pkg="rospy" type="talker.py" />
</group>
<test test-name="rostopic_unit" pkg="rostopic" type="test_rostopic.py" />
</launch>

View File

@@ -0,0 +1,355 @@
#!/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 unittest
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import time
import rostest
import rospy
import std_msgs.msg
from subprocess import Popen, PIPE, check_call, call
from contextlib import contextmanager
@contextmanager
def fakestdout():
realstdout = sys.stdout
fakestdout = StringIO()
sys.stdout = fakestdout
yield fakestdout
sys.stdout = realstdout
def todict(s):
d = {}
for l in s.split('\n'):
key, p, val = l.partition(':')
if p:
d[key] = val.strip()
return d
class TestRostopic(unittest.TestCase):
def __init__(self, *args):
unittest.TestCase.__init__(self, *args)
self.vals = set()
# wait for network to initialize
rospy.init_node('test')
topics = ['/chatter', '/foo/chatter', '/bar/chatter']
subs = [rospy.Subscriber(t, std_msgs.msg.String, self.callback, i) for i, t in enumerate(topics)]
all = set(range(0, len(topics)))
timeout_t = time.time() + 10.
while time.time() < timeout_t and self.vals != all and not rospy.is_shutdown():
time.sleep(0.1)
[s.unregister() for s in subs]
if rospy.is_shutdown():
self.fail("shutdown")
def test_offline(self):
import rostopic
orig_uri = os.environ['ROS_MASTER_URI']
os.environ['ROS_MASTER_URI'] = 'http://fake_host:12356'
try:
c = 'rostopic'
try:
rostopic._rostopic_cmd_list([c, 'list'])
self.fail("should have raised ROSTopicIOException")
except rostopic.ROSTopicIOException: pass
try:
rostopic._rostopic_cmd_info([c, 'info', '/chatter'])
self.fail("should have raised ROSTopicIOException")
except rostopic.ROSTopicIOException: pass
try:
rostopic._rostopic_cmd_type([c, 'type', '/chatter'])
self.fail("should have raised ROSTopicIOException")
except rostopic.ROSTopicIOException: pass
try:
rostopic._rostopic_cmd_find([c, 'find', 'std_msgs/String'])
self.fail("should have raised ROSTopicIOException")
except rostopic.ROSTopicIOException: pass
finally:
os.environ['ROS_MASTER_URI'] = orig_uri
def test_cmd_type(self):
import rostopic
cmd = 'rostopic'
s = '/rosout_agg'
t = 'rosgraph_msgs/Log'
try:
rostopic.rostopicmain([cmd, 'type', 'fake'])
self.fail("should have exited")
except SystemExit as e:
self.assertNotEquals(0, e.code)
for s in ['/chatter', 'chatter', 'foo/chatter', '/bar/chatter']:
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'type', s])
v = b.getvalue().strip()
self.assertEquals('std_msgs/String', v)
# check type of topic field
rostopic.rostopicmain([cmd, 'type', s + '/data'])
v = b.getvalue().strip()
self.assertEquals('std_msgs/String data string', v)
def test_main(self):
import rostopic
c = 'rostopic'
try:
rostopic.rostopicmain([c])
self.fail("should have exited with error")
except SystemExit as e:
self.assertNotEquals(0, e.code)
try:
rostopic.rostopicmain([c, 'foo'])
self.fail("should have exited with error")
except SystemExit as e:
self.assertNotEquals(0, e.code)
def test_cmd_pub(self):
import rostopic
cmd = 'rostopic'
# we can't actually test functional behavior because rostopic
# needs control over a node, though we can probably change the
# source code to just check for the existing node.
invalid = [['-r', '--once', '/foo', 'std_msgs/String', 'hello'],
['-r', 'a', '/foo', 'std_msgs/String', 'hello'],
['-r', '--', '-1', '/foo', 'std_msgs/String', 'hello'],
[],
['/foo'],
['/foo', 'std_msgs/String', 'a: b: !!c: d: e'],
]
for i in invalid:
try:
rostopic.rostopicmain([cmd, 'pub'] + i)
self.fail("should have exited with error"+str(i))
except SystemExit as e:
self.assert_(e.code != 0)
def test_full_usage(self):
import rostopic
try:
rostopic._fullusage()
self.fail("should have caused system exit")
except SystemExit: pass
def test_get_topic_type(self):
import rostopic
self.assertEquals((None, None, None), rostopic.get_topic_type('/fake', blocking=False))
t, n, f = rostopic.get_topic_type('/rosout', blocking=False)
self.assertEquals('rosgraph_msgs/Log', t)
self.assertEquals('/rosout', n)
self.assert_(f is None)
t, n, f = rostopic.get_topic_type('/rosout/name', blocking=False)
self.assertEquals('rosgraph_msgs/Log', t)
self.assertEquals('/rosout', n)
self.failIf(f is None)
from rosgraph_msgs.msg import Log
self.assertEquals("bob", f(Log(name="bob")))
def test_get_topic_class(self):
import rostopic
self.assertEquals((None, None, None), rostopic.get_topic_class('/fake'))
from rosgraph_msgs.msg import Log
c, n, f = rostopic.get_topic_class('/rosout')
self.assertEquals(Log, c)
self.assertEquals('/rosout', n)
self.assert_(f is None)
c, n, f = rostopic.get_topic_class('/rosout/name')
self.assertEquals(c, Log)
self.assertEquals('/rosout', n)
self.failIf(f is None)
self.assertEquals("bob", f(Log(name="bob")))
def test_cmd_info(self):
import rostopic
cmd = 'rostopic'
try:
rostopic.rostopicmain([cmd, 'info'])
self.fail("should have exited with error")
except SystemExit: pass
try:
rostopic.rostopicmain([cmd, 'info', '/fake_topic'])
self.fail("should have exited with error")
except SystemExit: pass
try:
rostopic.rostopicmain([cmd, 'info', '/chatter', '/bar/chatter'])
self.fail("should have exited with error")
except SystemExit: pass
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'info', 'rosout'])
v = b.getvalue()
for s in ["Publishers:", "Subscribers", "Type: rosgraph_msgs/Log", " * /rosout"]:
self.assert_(s in v, "failed on %s: %s"%(s, v))
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'info', '/chatter'])
v = b.getvalue()
for s in ["Publishers:", "Subscribers", "Type: std_msgs/String", " * /talker"]:
self.assert_(s in v, "failed on %s: %s"%(s, v))
def test_cmd_find(self):
import rostopic
cmd = 'rostopic'
try:
rostopic.rostopicmain([cmd, 'find'])
self.fail("arg parsing should have failed")
except SystemExit: pass
try:
rostopic.rostopicmain([cmd, 'find', 'std_msgs/String', 'std_msgs/Int32'])
self.fail("arg parsing should have failed")
except SystemExit: pass
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'find', 'std_msgs/String'])
d = [x for x in b.getvalue().split('\n') if x.strip()]
v = ['/foo/chatter', '/bar/chatter', '/chatter']
self.assertEquals(set(v), set(d))
def callback(self, msg, val):
self.vals.add(val)
def test_cmd_list(self):
import rostopic
cmd = 'rostopic'
s = '/add_two_ints'
# test failures
for invalid in [['-ps'], ['-b' 'file.bag', '-s'], ['-b' 'file.bag', '-p']]:
try:
rostopic.rostopicmain([cmd, 'list'] + invalid)
self.fail("should have failed")
except SystemExit: pass
# test main entry
rostopic.rostopicmain([cmd, 'list'])
# test directly
topics = ['/chatter', '/foo/chatter', '/bar/chatter', '/rosout', '/rosout_agg']
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'list'])
v = [x.strip() for x in b.getvalue().split('\n') if x.strip()]
self.failIf(set(topics)-set(v))
# publishers-only
topics = ['/chatter', '/foo/chatter', '/bar/chatter', '/rosout', '/rosout_agg']
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'list', '-p'])
v = [x.strip() for x in b.getvalue().split('\n') if x.strip()]
self.failIf(set(topics)-set(v))
self.failIf('/clock' in v)
# subscribers-only
topics = ['/rosout']
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'list', '-s'])
v = [x.strip() for x in b.getvalue().split('\n') if x.strip()]
self.failIf(set(topics)-set(v), "%s vs. %s"%(topics, v))
self.failIf('/chatter' in v)
# turn on verbosity, not checking output as it's not as stable
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'list', '-v'])
v = b.getvalue()
self.assert_("Published topics:" in v)
self.assert_("Subscribed topics:" in v)
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'list', '-vs'])
v = b.getvalue()
self.failIf("Published topics:" in v)
self.assert_("Subscribed topics:" in v)
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'list', '-vp'])
v = b.getvalue()
self.assert_("Published topics:" in v)
self.failIf("Subscribed topics:" in v)
# test with multiple topic names
try:
rostopic.rostopicmain([cmd, 'list', 'rosout', 'rosout_agg'])
self.fail("should have caused parser error")
except SystemExit:
pass
# test with resolved names
for n in topics:
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'list', n])
self.assertEquals(n, b.getvalue().strip())
# test with relative names
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'list', 'rosout'])
self.assertEquals('/rosout', b.getvalue().strip())
# test with namespaces
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'list', '/foo'])
self.assertEquals('/foo/chatter', b.getvalue().strip())
with fakestdout() as b:
rostopic.rostopicmain([cmd, 'list', 'bar'])
self.assertEquals('/bar/chatter', b.getvalue().strip())
NAME = 'test_rostopic'
if __name__ == '__main__':
rostest.unitrun('test_rostopic', NAME, TestRostopic, sys.argv, coverage_packages=['rostopic'])

View File

@@ -0,0 +1,98 @@
#!/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 unittest
import time
from subprocess import Popen, PIPE, check_call, call
class TestRostopicOffline(unittest.TestCase):
def setUp(self):
pass
## test that the rosmsg command works
def test_cmd_help(self):
cmd = 'rostopic'
sub = ['bw', 'echo', 'hz', 'delay', 'info', 'list', 'pub', 'type','find']
output = Popen([cmd], stdout=PIPE).communicate()[0]
self.assert_('Commands' in output)
output = Popen([cmd, '-h'], stdout=PIPE).communicate()[0]
self.assert_('Commands' in output)
# make sure all the commands are in the usage
for c in sub:
cmd_sub = "%s %s"%(cmd, c)
self.assert_(cmd_sub in output, "'%s' is not in help: \n%s"%(cmd_sub, output))
for c in sub:
output = Popen([cmd, c, '-h'], stdout=PIPE, stderr=PIPE).communicate()
self.assert_("usage:" in output[0].lower(), output)
# make sure usage refers to the command
self.assert_("%s %s"%(cmd, c) in output[0], output)
# test no args on commands that require args
for c in ['bw', 'echo', 'hz', 'delay', 'info', 'pub', 'type', 'find']:
output = Popen([cmd, c], stdout=PIPE, stderr=PIPE).communicate()
self.assert_("usage:" in output[0].lower() or "usage:" in output[1].lower(), output)
# make sure usage refers to the command
self.assert_("%s %s"%(cmd, c) in output[1], output)
def test_offline(self):
cmd = 'rostopic'
# point at a different 'master'
env = os.environ.copy()
env['ROS_MASTER_URI'] = 'http://localhost:11312'
kwds = { 'env': env, 'stdout': PIPE, 'stderr': PIPE}
msg = "ERROR: Unable to communicate with master!\n"
output = Popen([cmd, 'bw', 'chatter'], **kwds).communicate()
self.assert_(output[1].endswith(msg))
output = Popen([cmd, 'echo', 'chatter'], **kwds).communicate()
self.assert_(output[1].endswith(msg))
output = Popen([cmd, 'hz', 'chatter'], **kwds).communicate()
self.assert_(output[1].endswith(msg))
output = Popen([cmd, 'delay', 'chatter'], **kwds).communicate()
self.assert_(output[1].endswith(msg))
output = Popen([cmd, 'list'], **kwds).communicate()
self.assert_(output[1].endswith(msg))
output = Popen([cmd, 'pub', 'chatter', 'std_msgs/String', 'hello'], **kwds).communicate()
self.assert_(output[1].endswith(msg))
output = Popen([cmd, 'type', 'chatter'], **kwds).communicate()
self.assert_(output[1].endswith(msg))
output = Popen([cmd, 'type', 'std_msgs/String'], **kwds).communicate()
self.assert_(output[1].endswith(msg))