v01
This commit is contained in:
0
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/__init__.py
vendored
Normal file
0
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/__init__.py
vendored
Normal file
201
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_core.py
vendored
Normal file
201
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_core.py
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
#!/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.
|
||||
|
||||
NAME = 'test_core'
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import rospkg
|
||||
|
||||
_lastmsg = None
|
||||
def printlog_cb(msg):
|
||||
global _lastmsg
|
||||
_lastmsg = msg
|
||||
def printlog_cb_exception(msg):
|
||||
raise Exception(msg)
|
||||
|
||||
## Test roslaunch.core
|
||||
class TestCore(unittest.TestCase):
|
||||
def test_xml_escape(self):
|
||||
from roslaunch.core import _xml_escape
|
||||
self.assertEquals('', _xml_escape(''))
|
||||
self.assertEquals(' ', _xml_escape(' '))
|
||||
self.assertEquals('"', _xml_escape('"'))
|
||||
self.assertEquals('"hello world"', _xml_escape('"hello world"'))
|
||||
self.assertEquals('>', _xml_escape('>'))
|
||||
self.assertEquals('<', _xml_escape('<'))
|
||||
self.assertEquals('&', _xml_escape('&'))
|
||||
self.assertEquals('&amp;', _xml_escape('&'))
|
||||
self.assertEquals('&"><"', _xml_escape('&"><"'))
|
||||
|
||||
|
||||
def test_child_mode(self):
|
||||
from roslaunch.core import is_child_mode, set_child_mode
|
||||
set_child_mode(False)
|
||||
self.failIf(is_child_mode())
|
||||
set_child_mode(True)
|
||||
self.assert_(is_child_mode())
|
||||
set_child_mode(False)
|
||||
self.failIf(is_child_mode())
|
||||
|
||||
def test_printlog(self):
|
||||
from roslaunch.core import add_printlog_handler, add_printerrlog_handler, printlog, printlog_bold, printerrlog
|
||||
add_printlog_handler(printlog_cb)
|
||||
add_printlog_handler(printlog_cb_exception)
|
||||
add_printerrlog_handler(printlog_cb)
|
||||
add_printerrlog_handler(printlog_cb_exception)
|
||||
|
||||
#can't really test functionality, just make sure it doesn't crash
|
||||
global _lastmsg
|
||||
_lastmsg = None
|
||||
printlog('foo')
|
||||
self.assertEquals('foo', _lastmsg)
|
||||
printlog_bold('bar')
|
||||
self.assertEquals('bar', _lastmsg)
|
||||
printerrlog('baz')
|
||||
self.assertEquals('baz', _lastmsg)
|
||||
|
||||
def test_setup_env(self):
|
||||
from roslaunch.core import setup_env, Node, Machine
|
||||
master_uri = 'http://masteruri:1234'
|
||||
|
||||
n = Node('nodepkg','nodetype')
|
||||
m = Machine('name1', '1.2.3.4')
|
||||
d = setup_env(n, m, master_uri)
|
||||
self.assertEquals(d['ROS_MASTER_URI'], master_uri)
|
||||
|
||||
m = Machine('name1', '1.2.3.4')
|
||||
d = setup_env(n, m, master_uri)
|
||||
val = os.environ['ROS_ROOT']
|
||||
self.assertEquals(d['ROS_ROOT'], val)
|
||||
|
||||
# test ROS_NAMESPACE
|
||||
# test stripping
|
||||
n = Node('nodepkg','nodetype', namespace="/ns2/")
|
||||
d = setup_env(n, m, master_uri)
|
||||
self.assertEquals(d['ROS_NAMESPACE'], "/ns2")
|
||||
|
||||
# test node.env_args
|
||||
n = Node('nodepkg','nodetype', env_args=[('NENV1', 'val1'), ('NENV2', 'val2'), ('ROS_ROOT', '/new/root')])
|
||||
d = setup_env(n, m, master_uri)
|
||||
self.assertEquals(d['ROS_ROOT'], "/new/root")
|
||||
self.assertEquals(d['NENV1'], "val1")
|
||||
self.assertEquals(d['NENV2'], "val2")
|
||||
|
||||
|
||||
def test_local_machine(self):
|
||||
try:
|
||||
env_copy = os.environ.copy()
|
||||
|
||||
from roslaunch.core import local_machine
|
||||
lm = local_machine()
|
||||
self.failIf(lm is None)
|
||||
#singleton
|
||||
self.assert_(lm == local_machine())
|
||||
|
||||
self.assertEquals(lm.name, '')
|
||||
self.assertEquals(lm.assignable, True)
|
||||
self.assertEquals(lm.env_loader, None)
|
||||
self.assertEquals(lm.user, None)
|
||||
self.assertEquals(lm.password, None)
|
||||
finally:
|
||||
os.environ = env_copy
|
||||
|
||||
|
||||
def test_Master(self):
|
||||
from roslaunch.core import Master
|
||||
old_env = os.environ.get('ROS_MASTER_URI', None)
|
||||
try:
|
||||
os.environ['ROS_MASTER_URI'] = 'http://foo:789'
|
||||
m = Master()
|
||||
self.assertEquals(m.type, Master.ROSMASTER)
|
||||
self.assertEquals(m.uri, 'http://foo:789')
|
||||
self.assertEquals(m, m)
|
||||
self.assertEquals(m, Master())
|
||||
|
||||
m = Master(Master.ROSMASTER, 'http://foo:1234')
|
||||
self.assertEquals(m.type, Master.ROSMASTER)
|
||||
self.assertEquals(m.uri, 'http://foo:1234')
|
||||
self.assertEquals(m, m)
|
||||
self.assertEquals(m, Master(Master.ROSMASTER, 'http://foo:1234'))
|
||||
|
||||
try:
|
||||
from xmlrpc.client import ServerProxy
|
||||
except ImportError:
|
||||
from xmlrpclib import ServerProxy
|
||||
self.assert_(isinstance(m.get(), ServerProxy))
|
||||
m.uri = 'http://foo:567'
|
||||
self.assertEquals(567, m.get_port())
|
||||
self.failIf(m.is_running())
|
||||
|
||||
finally:
|
||||
if old_env is None:
|
||||
del os.environ['ROS_MASTER_URI']
|
||||
else:
|
||||
os.environ['ROS_MASTER_URI'] = old_env
|
||||
|
||||
def test_Executable(self):
|
||||
from roslaunch.core import Executable, PHASE_SETUP, PHASE_RUN, PHASE_TEARDOWN
|
||||
|
||||
e = Executable('ls', ['-alF'])
|
||||
self.assertEquals('ls', e.command)
|
||||
self.assertEquals(['-alF'], e.args)
|
||||
self.assertEquals(PHASE_RUN, e.phase)
|
||||
self.assertEquals('ls -alF', str(e))
|
||||
self.assertEquals('ls -alF', repr(e))
|
||||
|
||||
e = Executable('ls', ['-alF', 'b*'], PHASE_TEARDOWN)
|
||||
self.assertEquals('ls', e.command)
|
||||
self.assertEquals(['-alF', 'b*'], e.args)
|
||||
self.assertEquals(PHASE_TEARDOWN, e.phase)
|
||||
self.assertEquals('ls -alF b*', str(e))
|
||||
self.assertEquals('ls -alF b*', repr(e))
|
||||
|
||||
def test_RosbinExecutable(self):
|
||||
from roslaunch.core import RosbinExecutable, PHASE_SETUP, PHASE_RUN, PHASE_TEARDOWN
|
||||
|
||||
e = RosbinExecutable('ls', ['-alF'])
|
||||
self.assertEquals('ls', e.command)
|
||||
self.assertEquals(['-alF'], e.args)
|
||||
self.assertEquals(PHASE_RUN, e.phase)
|
||||
self.assertEquals('ros/bin/ls -alF', str(e))
|
||||
self.assertEquals('ros/bin/ls -alF', repr(e))
|
||||
|
||||
e = RosbinExecutable('ls', ['-alF', 'b*'], PHASE_TEARDOWN)
|
||||
self.assertEquals('ls', e.command)
|
||||
self.assertEquals(['-alF', 'b*'], e.args)
|
||||
self.assertEquals(PHASE_TEARDOWN, e.phase)
|
||||
self.assertEquals('ros/bin/ls -alF b*', str(e))
|
||||
self.assertEquals('ros/bin/ls -alF b*', repr(e))
|
||||
280
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_nodeprocess.py
vendored
Normal file
280
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_nodeprocess.py
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
#!/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 rospkg
|
||||
import roslib.packages
|
||||
import logging
|
||||
logging.getLogger('roslaunch').setLevel(logging.CRITICAL)
|
||||
|
||||
## Test roslaunch.nodeprocess
|
||||
class TestNodeprocess(unittest.TestCase):
|
||||
|
||||
def test_create_master_process(self):
|
||||
from roslaunch.core import Node, Machine, Master, RLException
|
||||
from roslaunch.nodeprocess import create_master_process, LocalProcess
|
||||
|
||||
ros_root = '/ros/root'
|
||||
port = 1234
|
||||
type = Master.ROSMASTER
|
||||
run_id = 'foo'
|
||||
|
||||
# test invalid params
|
||||
try:
|
||||
create_master_process(run_id, type, ros_root, -1)
|
||||
self.fail("shoud have thrown RLException")
|
||||
except RLException: pass
|
||||
try:
|
||||
create_master_process(run_id, type, ros_root, 10000000)
|
||||
self.fail("shoud have thrown RLException")
|
||||
except RLException: pass
|
||||
try:
|
||||
create_master_process(run_id, 'foo', ros_root, port)
|
||||
self.fail("shoud have thrown RLException")
|
||||
except RLException: pass
|
||||
|
||||
# test valid params
|
||||
p = create_master_process(run_id, type, ros_root, port)
|
||||
self.assert_(isinstance(p, LocalProcess))
|
||||
self.assertEquals(p.args[0], 'rosmaster')
|
||||
idx = p.args.index('-p')
|
||||
self.failIf(idx < 1)
|
||||
self.assertEquals(p.args[idx+1], str(port))
|
||||
self.assert_('--core' in p.args)
|
||||
|
||||
self.assertEquals(p.package, 'rosmaster')
|
||||
p = create_master_process(run_id, type, ros_root, port)
|
||||
|
||||
# TODO: have to think more as to the correct environment for the master process
|
||||
|
||||
|
||||
def test_create_node_process(self):
|
||||
from roslaunch.core import Node, Machine, RLException
|
||||
from roslaunch.node_args import NodeParamsException
|
||||
from roslaunch.nodeprocess import create_node_process, LocalProcess
|
||||
# have to use real ROS configuration for these tests
|
||||
ros_root = os.environ['ROS_ROOT']
|
||||
rpp = os.environ.get('ROS_PACKAGE_PATH', None)
|
||||
master_uri = 'http://masteruri:1234'
|
||||
m = Machine('name1', ros_root, rpp, '1.2.3.4')
|
||||
|
||||
run_id = 'id'
|
||||
|
||||
# test invalid params
|
||||
n = Node('not_a_real_package','not_a_node')
|
||||
n.machine = m
|
||||
n.name = 'foo'
|
||||
try: # should fail b/c node cannot be found
|
||||
create_node_process(run_id, n, master_uri)
|
||||
self.fail("should have failed")
|
||||
except NodeParamsException:
|
||||
pass
|
||||
|
||||
# have to specify a real node
|
||||
n = Node('rospy','talker.py')
|
||||
n.machine = m
|
||||
try: # should fail b/c n.name is not set
|
||||
create_node_process(run_id, n, master_uri)
|
||||
self.fail("should have failed")
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# have to specify a real node
|
||||
n = Node('rospy','talker.py')
|
||||
|
||||
n.machine = None
|
||||
n.name = 'talker'
|
||||
try: # should fail b/c n.machine is not set
|
||||
create_node_process(run_id, n, master_uri)
|
||||
self.fail("should have failed")
|
||||
except RLException:
|
||||
pass
|
||||
|
||||
# basic integration test
|
||||
n.machine = m
|
||||
p = create_node_process(run_id, n, master_uri)
|
||||
self.assert_(isinstance(p, LocalProcess))
|
||||
|
||||
# repeat some setup_local_process_env tests
|
||||
d = p.env
|
||||
self.assertEquals(d['ROS_MASTER_URI'], master_uri)
|
||||
self.assertEquals(d['ROS_ROOT'], ros_root)
|
||||
self.assertEquals(d['PYTHONPATH'], os.environ['PYTHONPATH'])
|
||||
if rpp:
|
||||
self.assertEquals(d['ROS_PACKAGE_PATH'], rpp)
|
||||
for k in ['ROS_IP', 'ROS_NAMESPACE']:
|
||||
if k in d:
|
||||
self.fail('%s should not be set: %s'%(k,d[k]))
|
||||
|
||||
# test package and name
|
||||
self.assertEquals(p.package, 'rospy')
|
||||
# - no 'correct' full answer here
|
||||
self.assert_(p.name.startswith('talker'), p.name)
|
||||
|
||||
# test log_output
|
||||
n.output = 'log'
|
||||
self.assert_(create_node_process(run_id, n, master_uri).log_output)
|
||||
n.output = 'screen'
|
||||
self.failIf(create_node_process(run_id, n, master_uri).log_output)
|
||||
|
||||
# test respawn
|
||||
n.respawn = True
|
||||
self.assert_(create_node_process(run_id, n, master_uri).respawn)
|
||||
n.respawn = False
|
||||
self.failIf(create_node_process(run_id, n, master_uri).respawn)
|
||||
|
||||
# test cwd
|
||||
n.cwd = None
|
||||
self.assertEquals(create_node_process(run_id, n, master_uri).cwd, None)
|
||||
n.cwd = 'ros-root'
|
||||
self.assertEquals(create_node_process(run_id, n, master_uri).cwd, 'ros-root')
|
||||
n.cwd = 'node'
|
||||
self.assertEquals(create_node_process(run_id, n, master_uri).cwd, 'node')
|
||||
|
||||
# test args
|
||||
|
||||
# - simplest test (no args)
|
||||
n.args = ''
|
||||
p = create_node_process(run_id, n, master_uri)
|
||||
# - the first arg should be the path to the node executable
|
||||
rospack = rospkg.RosPack()
|
||||
cmd = roslib.packages.find_node('rospy', 'talker.py', rospack)[0]
|
||||
self.assertEquals(p.args[0], cmd)
|
||||
|
||||
# - test basic args
|
||||
n.args = "arg1 arg2 arg3"
|
||||
p = create_node_process(run_id, n, master_uri)
|
||||
self.assertEquals(p.args[0], cmd)
|
||||
for a in "arg1 arg2 arg3".split():
|
||||
self.assert_(a in p.args)
|
||||
|
||||
# - test remap args
|
||||
n.remap_args = [('KEY1', 'VAL1'), ('KEY2', 'VAL2')]
|
||||
p = create_node_process(run_id, n, master_uri)
|
||||
self.assert_('KEY1:=VAL1' in p.args)
|
||||
self.assert_('KEY2:=VAL2' in p.args)
|
||||
|
||||
# - test __name
|
||||
n = Node('rospy','talker.py')
|
||||
n.name = 'fooname'
|
||||
n.machine = m
|
||||
self.assert_('__name:=fooname' in create_node_process(run_id, n, master_uri).args)
|
||||
|
||||
# - test substitution args
|
||||
os.environ['SUB_TEST'] = 'subtest'
|
||||
os.environ['SUB_TEST2'] = 'subtest2'
|
||||
n.args = 'foo $(env SUB_TEST) $(env SUB_TEST2)'
|
||||
p = create_node_process(run_id, n, master_uri)
|
||||
self.failIf('SUB_TEST' in p.args)
|
||||
self.assert_('foo' in p.args)
|
||||
self.assert_('subtest' in p.args)
|
||||
self.assert_('subtest2' in p.args)
|
||||
|
||||
def test__cleanup_args(self):
|
||||
# #1595
|
||||
from roslaunch.nodeprocess import _cleanup_remappings
|
||||
args = [
|
||||
'ROS_PACKAGE_PATH=foo',
|
||||
'/home/foo/monitor',
|
||||
'__log:=/home/pr2/21851/ros-0.7.2/log/8d769688-897d-11de-8e93-00238bdfe0ab/monitor-3.log',
|
||||
'__name:=bar',
|
||||
'__log:=/home/pr2/21851/ros-0.7.2/log/8d769688-897d-11de-8e93-00238bdfe0ab/monitor-3.log',
|
||||
'topic:=topic2',
|
||||
'__log:=/home/pr2/21851/ros-0.7.2/log/8d769688-897d-11de-8e93-00238bdfe0ab/monitor-3.log',
|
||||
'__log:=/home/pr2/21851/ros-0.7.2/log/8d769688-897d-11de-8e93-00238bdfe0ab/monitor-3.log',
|
||||
'__log:=/home/pr2/21851/ros-0.7.2/log/8d769688-897d-11de-8e93-00238bdfe0ab/monitor-3.log',
|
||||
'__log:=/home/pr2/21851/ros-0.7.2/log/8d769688-897d-11de-8e93-00238bdfe0ab/monitor-3.log',
|
||||
'__log:=/home/pr2/21851/ros-0.7.2/log/8d769688-897d-11de-8e93-00238bdfe0ab/monitor-3.log']
|
||||
clean_args = [
|
||||
'ROS_PACKAGE_PATH=foo',
|
||||
'/home/foo/monitor',
|
||||
'__name:=bar',
|
||||
'topic:=topic2']
|
||||
|
||||
self.assertEquals([], _cleanup_remappings([], '__log:='))
|
||||
self.assertEquals(clean_args, _cleanup_remappings(args, '__log:='))
|
||||
self.assertEquals(clean_args, _cleanup_remappings(clean_args, '__log:='))
|
||||
self.assertEquals(args, _cleanup_remappings(args, '_foo'))
|
||||
|
||||
def test__next_counter(self):
|
||||
from roslaunch.nodeprocess import _next_counter
|
||||
x = _next_counter()
|
||||
y = _next_counter()
|
||||
self.assert_(x +1 == y)
|
||||
self.assert_(x > 0)
|
||||
|
||||
def test_create_master_process2(self):
|
||||
# accidentally wrote two versions of this, need to merge
|
||||
from roslaunch.core import Master, RLException
|
||||
import rospkg
|
||||
from roslaunch.nodeprocess import create_master_process
|
||||
|
||||
ros_root = rospkg.get_ros_root()
|
||||
|
||||
# test failures
|
||||
failed = False
|
||||
try:
|
||||
create_master_process('runid-unittest', Master.ROSMASTER, rospkg.get_ros_root(), 0)
|
||||
failed = True
|
||||
except RLException: pass
|
||||
self.failIf(failed, "invalid port should have triggered error")
|
||||
|
||||
# test success with ROSMASTER
|
||||
m1 = create_master_process('runid-unittest', Master.ROSMASTER, ros_root, 1234)
|
||||
self.assertEquals('runid-unittest', m1.run_id)
|
||||
self.failIf(m1.started)
|
||||
self.failIf(m1.stopped)
|
||||
self.assertEquals(None, m1.cwd)
|
||||
self.assertEquals('master', m1.name)
|
||||
master_p = 'rosmaster'
|
||||
self.assert_(master_p in m1.args)
|
||||
# - it should have the default environment
|
||||
self.assertEquals(os.environ, m1.env)
|
||||
# - check args
|
||||
self.assert_('--core' in m1.args)
|
||||
# - make sure port arguent is correct
|
||||
idx = m1.args.index('-p')
|
||||
self.assertEquals('1234', m1.args[idx+1])
|
||||
|
||||
# test port argument
|
||||
m2 = create_master_process('runid-unittest', Master.ROSMASTER, ros_root, 1234)
|
||||
self.assertEquals('runid-unittest', m2.run_id)
|
||||
|
||||
# test ros_root argument
|
||||
m3 = create_master_process('runid-unittest', Master.ROSMASTER, ros_root, 1234)
|
||||
self.assertEquals('runid-unittest', m3.run_id)
|
||||
master_p = 'rosmaster'
|
||||
self.assert_(master_p in m3.args)
|
||||
190
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_child.py
vendored
Normal file
190
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_child.py
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
#!/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, sys, unittest
|
||||
import time
|
||||
|
||||
import rosgraph
|
||||
|
||||
import roslaunch.child
|
||||
import roslaunch.server
|
||||
|
||||
## Fake RemoteProcess object
|
||||
class ChildProcessMock(roslaunch.server.ChildROSLaunchProcess):
|
||||
def __init__(self, name, args=[], env={}):
|
||||
super(ChildProcessMock, self).__init__(name, args, env)
|
||||
self.stopped = False
|
||||
def stop(self):
|
||||
self.stopped = True
|
||||
|
||||
## Fake ProcessMonitor object
|
||||
class ProcessMonitorMock(object):
|
||||
def __init__(self):
|
||||
self.core_procs = []
|
||||
self.procs = []
|
||||
self.listeners = []
|
||||
|
||||
def join(self, timeout=0):
|
||||
pass
|
||||
|
||||
def add_process_listener(self, l):
|
||||
self.listeners.append(l)
|
||||
|
||||
def register(self, p):
|
||||
self.procs.append(p)
|
||||
|
||||
def register_core_proc(self, p):
|
||||
self.core_procs.append(p)
|
||||
|
||||
def registrations_complete(self):
|
||||
pass
|
||||
|
||||
def unregister(self, p):
|
||||
self.procs.remove(p)
|
||||
|
||||
def has_process(self, name):
|
||||
return len([p for p in self.procs if p.name == name]) > 0
|
||||
|
||||
def get_process(self, name):
|
||||
val = [p for p in self.procs if p.name == name]
|
||||
if val:
|
||||
return val[0]
|
||||
return None
|
||||
|
||||
def has_main_thread_jobs(self):
|
||||
return False
|
||||
|
||||
def do_main_thread_jobs(self):
|
||||
pass
|
||||
|
||||
def kill_process(self, name):
|
||||
pass
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def get_active_names(self):
|
||||
return [p.name for p in self.procs]
|
||||
|
||||
def get_process_names_with_spawn_count(self):
|
||||
actives = [(p.name, p.spawn_count) for p in self.procs]
|
||||
deads = []
|
||||
return [actives, deads]
|
||||
|
||||
def mainthread_spin_once(self):
|
||||
pass
|
||||
|
||||
def mainthread_spin(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
## Test roslaunch.server
|
||||
class TestRoslaunchChild(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.pmon = ProcessMonitorMock()
|
||||
try:
|
||||
# if there is a core up, we have to use its run id
|
||||
m = rosgraph.Master('/roslaunch')
|
||||
self.run_id = m.getParam('/run_id')
|
||||
except:
|
||||
self.run_id = 'foo-%s'%time.time()
|
||||
|
||||
def test_roslaunchChild(self):
|
||||
# this is mainly a code coverage test to try and make sure that we don't
|
||||
# have any uninitialized references, etc...
|
||||
|
||||
from roslaunch.child import ROSLaunchChild
|
||||
|
||||
name = 'child-%s'%time.time()
|
||||
server_uri = 'http://unroutable:1234'
|
||||
c = ROSLaunchChild(self.run_id, name, server_uri)
|
||||
self.assertEquals(self.run_id, c.run_id)
|
||||
self.assertEquals(name, c.name)
|
||||
self.assertEquals(server_uri, c.server_uri)
|
||||
# - this check tests our assumption about c's process monitor field
|
||||
self.assertEquals(None, c.pm)
|
||||
self.assertEquals(None, c.child_server)
|
||||
|
||||
# should be a noop
|
||||
c.shutdown()
|
||||
|
||||
# create a new child to test _start_pm() and shutdown()
|
||||
c = ROSLaunchChild(self.run_id, name, server_uri)
|
||||
|
||||
# - test _start_pm and shutdown logic
|
||||
c._start_pm()
|
||||
self.assert_(c.pm is not None)
|
||||
c.shutdown()
|
||||
|
||||
# create a new child to test run() with a fake process
|
||||
# monitor. this requires an actual parent server to be running
|
||||
|
||||
import roslaunch.config
|
||||
server = roslaunch.server.ROSLaunchParentNode(roslaunch.config.ROSLaunchConfig(), self.pmon)
|
||||
# - register a fake child with the server so that it accepts registration from ROSLaunchChild
|
||||
server.add_child(name, ChildProcessMock('foo'))
|
||||
try:
|
||||
server.start()
|
||||
self.assert_(server.uri, "server URI did not initialize")
|
||||
|
||||
c = ROSLaunchChild(self.run_id, name, server.uri)
|
||||
c.pm = self.pmon
|
||||
# - run should speed through
|
||||
c.run()
|
||||
finally:
|
||||
server.shutdown('test done')
|
||||
|
||||
# one final test for code completness: raise an exception during run()
|
||||
c = ROSLaunchChild(self.run_id, name, server_uri)
|
||||
def bad():
|
||||
raise Exception('haha')
|
||||
# - violate some encapsulation here just to make sure the exception happens
|
||||
c._start_pm = bad
|
||||
try:
|
||||
# this isn't really a correctness test, this just manually
|
||||
# tests that the exception is logged
|
||||
c.run()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def kill_parent(p, delay=1.0):
|
||||
# delay execution so that whatever pmon method we're calling has time to enter
|
||||
import time
|
||||
time.sleep(delay)
|
||||
print("stopping parent")
|
||||
p.shutdown()
|
||||
|
||||
311
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_core.py
vendored
Normal file
311
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_core.py
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2012, 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 rospkg
|
||||
try:
|
||||
from xmlrpc.client import MultiCall, ServerProxy
|
||||
except ImportError:
|
||||
from xmlrpclib import MultiCall, ServerProxy
|
||||
|
||||
|
||||
import roslaunch.core
|
||||
|
||||
def test_Executable():
|
||||
from roslaunch.core import Executable, PHASE_SETUP
|
||||
e = Executable('cmd', ('arg1', 'arg2'), PHASE_SETUP)
|
||||
assert e.command == 'cmd'
|
||||
assert e.args == ('arg1', 'arg2')
|
||||
assert e.phase == PHASE_SETUP
|
||||
assert 'cmd' in str(e)
|
||||
assert 'arg2' in str(e)
|
||||
assert 'cmd' in repr(e)
|
||||
assert 'arg2' in repr(e)
|
||||
|
||||
def test__xml_escape():
|
||||
# this is a really bad xml escaper
|
||||
from roslaunch.core import _xml_escape
|
||||
assert _xml_escape("&<foo>") == "&<foo>"
|
||||
|
||||
def test_RosbinExecutable():
|
||||
from roslaunch.core import RosbinExecutable, PHASE_SETUP, PHASE_RUN
|
||||
e = RosbinExecutable('cmd', ('arg1', 'arg2'), PHASE_SETUP)
|
||||
assert e.command == 'cmd'
|
||||
assert e.args == ('arg1', 'arg2')
|
||||
assert e.phase == PHASE_SETUP
|
||||
assert 'cmd' in str(e)
|
||||
assert 'arg2' in str(e)
|
||||
assert 'cmd' in repr(e)
|
||||
assert 'arg2' in repr(e)
|
||||
assert 'ros/bin' in str(e)
|
||||
assert 'ros/bin' in repr(e)
|
||||
|
||||
e = RosbinExecutable('cmd', ('arg1', 'arg2'))
|
||||
assert e.phase == PHASE_RUN
|
||||
|
||||
def test_generate_run_id():
|
||||
from roslaunch.core import generate_run_id
|
||||
assert generate_run_id()
|
||||
|
||||
def test_Node():
|
||||
from roslaunch.core import Node
|
||||
n = Node('package', 'node_type')
|
||||
assert n.package == 'package'
|
||||
assert n.type == 'node_type'
|
||||
assert n.xmltype() == 'node'
|
||||
assert n.xmlattrs() == [('pkg', 'package'), ('type', 'node_type'),
|
||||
('machine', None), ('ns', '/'), ('args', ''), ('output', None),
|
||||
('cwd', None), ('respawn', False), ('respawn_delay', 0.0),
|
||||
('name', None), ('launch-prefix', None), ('required', False)], \
|
||||
n.xmlattrs()
|
||||
assert n.output == None
|
||||
|
||||
#tripwire for now
|
||||
n.to_xml()
|
||||
val = n.to_remote_xml()
|
||||
assert 'machine' not in val
|
||||
|
||||
# test bad constructors
|
||||
try:
|
||||
n = Node('package', 'node_type', cwd='foo')
|
||||
assert False
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
n = Node('package', 'node_type', output='foo')
|
||||
assert False
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
n = Node('package', '')
|
||||
assert False
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
n = Node('', 'node_type')
|
||||
assert False
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
n = Node('package', 'node_type', name='ns/node')
|
||||
assert False
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
n = Node('package', 'node_type', respawn=True, required=True)
|
||||
assert False
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
def test_Param():
|
||||
from roslaunch.core import Param
|
||||
p = Param('key/', 'value')
|
||||
|
||||
assert p.key == 'key'
|
||||
assert p.value == 'value'
|
||||
assert p == Param('key', 'value')
|
||||
assert p != Param('key2', 'value')
|
||||
assert p != 1
|
||||
|
||||
assert 'key' in str(p)
|
||||
assert 'key' in repr(p)
|
||||
assert 'value' in str(p)
|
||||
assert 'value' in repr(p)
|
||||
|
||||
def test_local_machine():
|
||||
from roslaunch.core import local_machine
|
||||
m = local_machine()
|
||||
assert m is local_machine()
|
||||
assert m == local_machine()
|
||||
assert m.env_loader == None
|
||||
assert m.name == ''
|
||||
assert m.address == 'localhost'
|
||||
assert m.ssh_port == 22
|
||||
|
||||
def test_Machine():
|
||||
from roslaunch.core import Machine
|
||||
m = Machine('foo', 'localhost')
|
||||
assert 'foo' in str(m)
|
||||
assert m.name == 'foo'
|
||||
assert m.env_loader == None
|
||||
assert m.assignable == True
|
||||
assert m == m
|
||||
assert not m.__eq__(1)
|
||||
assert not m.config_equals(1)
|
||||
assert m == Machine('foo', 'localhost')
|
||||
assert m.config_equals(Machine('foo', 'localhost'))
|
||||
assert m.config_key() == Machine('foo', 'localhost').config_key()
|
||||
assert m.config_equals(Machine('foo', 'localhost'))
|
||||
assert m.config_key() == Machine('foo', 'localhost', ssh_port=22).config_key()
|
||||
assert m.config_equals(Machine('foo', 'localhost', ssh_port=22))
|
||||
assert m.config_key() == Machine('foo', 'localhost', assignable=False).config_key()
|
||||
assert m.config_equals(Machine('foo', 'localhost', assignable=False))
|
||||
|
||||
# original test suite
|
||||
m = Machine('name1', '1.2.3.4')
|
||||
str(m), m.config_key() #test for error
|
||||
assert m == m
|
||||
assert m == Machine('name1', '1.2.3.4')
|
||||
# verify that config_equals is not tied to name or assignable, but is tied to other properties
|
||||
assert m.config_equals(Machine('name1b', '1.2.3.4'))
|
||||
assert m.config_equals(Machine('name1c', '1.2.3.4', assignable=False))
|
||||
assert not m.config_equals(Machine('name1f', '2.2.3.4'))
|
||||
|
||||
assert m.name == 'name1'
|
||||
assert m.address == '1.2.3.4'
|
||||
assert m.assignable == True
|
||||
assert m.ssh_port == 22
|
||||
assert m.env_loader == None
|
||||
for p in ['user', 'password']:
|
||||
assert getattr(m, p) is None
|
||||
|
||||
m = Machine('name2', '2.2.3.4', assignable=False)
|
||||
assert not m.assignable
|
||||
str(m), m.config_key() #test for error
|
||||
assert m == m
|
||||
assert m == Machine('name2', '2.2.3.4', assignable=False)
|
||||
assert m.config_equals(Machine('name2b', '2.2.3.4', assignable=False))
|
||||
assert m.config_equals(Machine('name2c', '2.2.3.4', assignable=True))
|
||||
|
||||
m = Machine('name3', '3.3.3.4')
|
||||
str(m) #test for error
|
||||
assert m == m
|
||||
assert m == Machine('name3', '3.3.3.4')
|
||||
assert m.config_equals(Machine('name3b', '3.3.3.4'))
|
||||
|
||||
m = Machine('name4', '4.4.3.4', user='user4')
|
||||
assert m.user == 'user4'
|
||||
str(m), m.config_key() #test for error
|
||||
assert m == m
|
||||
assert m == Machine('name4', '4.4.3.4', user='user4')
|
||||
assert m.config_equals(Machine('name4b', '4.4.3.4', user='user4'))
|
||||
assert not m.config_equals(Machine('name4b', '4.4.3.4', user='user4b'))
|
||||
|
||||
m = Machine('name5', '5.5.3.4', password='password5')
|
||||
assert m.password == 'password5'
|
||||
str(m), m.config_key() #test for error
|
||||
assert m == m
|
||||
assert m == Machine('name5', '5.5.3.4', password='password5')
|
||||
assert m.config_equals(Machine('name5b', '5.5.3.4', password='password5'))
|
||||
assert not m.config_equals(Machine('name5c', '5.5.3.4', password='password5c'))
|
||||
|
||||
m = Machine('name6', '6.6.3.4', ssh_port=23)
|
||||
assert m.ssh_port == 23
|
||||
str(m) #test for error
|
||||
m.config_key()
|
||||
assert m == m
|
||||
assert m == Machine('name6', '6.6.3.4', ssh_port=23)
|
||||
assert m.config_equals(Machine('name6b', '6.6.3.4', ssh_port=23))
|
||||
assert not m.config_equals(Machine('name6c', '6.6.3.4', ssh_port=24))
|
||||
|
||||
m = Machine('name6', '6.6.3.4', env_loader='/opt/ros/fuerte/setup.sh')
|
||||
assert m.env_loader == '/opt/ros/fuerte/setup.sh'
|
||||
str(m) #test for error
|
||||
m.config_key()
|
||||
assert m == m
|
||||
assert m == Machine('name6', '6.6.3.4', env_loader='/opt/ros/fuerte/setup.sh')
|
||||
assert m.config_equals(Machine('name6b', '6.6.3.4', env_loader='/opt/ros/fuerte/setup.sh'))
|
||||
assert not m.config_equals(Machine('name6c', '6.6.3.4', env_loader='/opt/ros/groovy/setup.sh'))
|
||||
|
||||
def test_Master():
|
||||
from roslaunch.core import Master
|
||||
# can't verify value of is_running for actual master
|
||||
m = Master(uri='http://localhost:11311')
|
||||
assert m .type == Master.ROSMASTER
|
||||
m.get_host() == 'localhost'
|
||||
m.get_port() == 11311
|
||||
assert m.is_running() in [True, False]
|
||||
assert isinstance(m.get(), ServerProxy)
|
||||
assert isinstance(m.get_multi(), MultiCall)
|
||||
|
||||
m = Master(uri='http://badhostname:11312')
|
||||
m.get_host() == 'badhostname'
|
||||
m.get_port() == 11312
|
||||
assert m.is_running() == False
|
||||
|
||||
|
||||
def test_Test():
|
||||
from roslaunch.core import Test, TEST_TIME_LIMIT_DEFAULT
|
||||
t = Test('test_name', 'package', 'node_type')
|
||||
assert t.xmltype() == 'test'
|
||||
assert t.xmlattrs() == [('pkg', 'package'), ('type', 'node_type'), ('machine', None), ('ns', '/'), ('args', ''), ('output', 'log'), ('cwd', None), ('name', None), ('launch-prefix', None), ('required', False), ('test-name', 'test_name')]
|
||||
|
||||
assert t.output == 'log'
|
||||
assert t.test_name == 'test_name'
|
||||
assert t.package == 'package'
|
||||
assert t.type == 'node_type'
|
||||
assert t.name == None
|
||||
assert t.namespace == '/'
|
||||
assert t.machine_name == None
|
||||
assert t.args == ''
|
||||
assert t.remap_args == [], t.remap_args
|
||||
assert t.env_args == []
|
||||
assert t.time_limit == TEST_TIME_LIMIT_DEFAULT
|
||||
assert t.cwd is None
|
||||
assert t.launch_prefix is None
|
||||
assert t.retry == 0
|
||||
assert t.filename == '<unknown>'
|
||||
|
||||
|
||||
t = Test('test_name', 'package', 'node_type', 'name',
|
||||
'/namespace', 'machine_name', 'arg1 arg2',
|
||||
remap_args=[('from', 'to')], env_args=[('ENV', 'val')], time_limit=1.0, cwd='ros_home',
|
||||
launch_prefix='foo', retry=1, filename="filename.txt")
|
||||
|
||||
xmlattrs = t.xmlattrs()
|
||||
assert ('time-limit', 1.0) in xmlattrs
|
||||
assert ('retry', '1') in xmlattrs
|
||||
|
||||
assert t.launch_prefix == 'foo'
|
||||
assert t.remap_args == [('from', 'to')]
|
||||
assert t.env_args == [('ENV', 'val')]
|
||||
assert t.name == 'name'
|
||||
assert t.namespace == '/namespace/', t.namespace
|
||||
assert t.machine_name == 'machine_name'
|
||||
assert t.args == 'arg1 arg2'
|
||||
assert t.filename == 'filename.txt'
|
||||
assert t.time_limit == 1.0
|
||||
assert t.cwd == 'ROS_HOME'
|
||||
assert t.retry == 1
|
||||
|
||||
try:
|
||||
t = Test('test_name', 'package', 'node_type', time_limit=-1.0)
|
||||
assert False
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
t = Test('test_name', 'package', 'node_type', time_limit=True)
|
||||
assert False
|
||||
except ValueError:
|
||||
pass
|
||||
161
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_depends.py
vendored
Normal file
161
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_depends.py
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2012, 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 rospkg
|
||||
|
||||
class Foo: pass
|
||||
|
||||
def test_RoslaunchDeps():
|
||||
from roslaunch.depends import RoslaunchDeps
|
||||
min_deps = RoslaunchDeps(nodes=[('rospy', 'talker.py')], pkgs=['rospy'])
|
||||
assert min_deps == min_deps
|
||||
assert min_deps == RoslaunchDeps(nodes=[('rospy', 'talker.py')], pkgs=['rospy'])
|
||||
assert not min_deps.__eq__(Foo())
|
||||
assert Foo() != min_deps
|
||||
assert min_deps != RoslaunchDeps(nodes=[('rospy', 'talker.py')])
|
||||
assert min_deps != RoslaunchDeps(pkgs=['rospy'])
|
||||
|
||||
assert 'talker.py' in repr(min_deps)
|
||||
assert 'talker.py' in str(min_deps)
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
from contextlib import contextmanager
|
||||
@contextmanager
|
||||
def fakestdout():
|
||||
realstdout = sys.stdout
|
||||
fakestdout = StringIO()
|
||||
sys.stdout = fakestdout
|
||||
yield fakestdout
|
||||
sys.stdout = realstdout
|
||||
|
||||
def test_roslaunch_deps_main():
|
||||
from roslaunch.depends import roslaunch_deps_main
|
||||
roslaunch_d = rospkg.RosPack().get_path('roslaunch')
|
||||
rosmaster_d = rospkg.RosPack().get_path('rosmaster')
|
||||
f = os.path.join(roslaunch_d, 'resources', 'example.launch')
|
||||
rosmaster_f = os.path.join(rosmaster_d, 'test', 'rosmaster.test')
|
||||
invalid_f = os.path.join(roslaunch_d, 'test', 'xml', 'invalid-xml.xml')
|
||||
not_f = os.path.join(roslaunch_d, 'test', 'xml', 'not-launch.xml')
|
||||
|
||||
with fakestdout() as b:
|
||||
roslaunch_deps_main(['roslaunch-deps', f])
|
||||
s = b.getvalue()
|
||||
assert s.strip() == 'rospy', "buffer value [%s]"%(s)
|
||||
with fakestdout() as b:
|
||||
roslaunch_deps_main(['roslaunch-deps', f, '--warn'])
|
||||
s = b.getvalue()
|
||||
assert s.strip() == """Dependencies:
|
||||
rospy
|
||||
|
||||
Missing declarations:
|
||||
roslaunch/manifest.xml:
|
||||
<depend package="rospy" />""", s
|
||||
|
||||
# tripwire, don't really care about exact verbose output
|
||||
with fakestdout() as b:
|
||||
roslaunch_deps_main(['roslaunch-deps', f, '--verbose'])
|
||||
|
||||
# try with no file
|
||||
with fakestdout() as b:
|
||||
try:
|
||||
roslaunch_deps_main(['roslaunch-deps'])
|
||||
assert False, "should have failed"
|
||||
except SystemExit:
|
||||
pass
|
||||
|
||||
# try with non-existent file
|
||||
with fakestdout() as b:
|
||||
try:
|
||||
roslaunch_deps_main(['roslaunch-deps', 'fakefile', '--verbose'])
|
||||
assert False, "should have failed"
|
||||
except SystemExit:
|
||||
pass
|
||||
|
||||
# try with bad file
|
||||
with fakestdout() as b:
|
||||
try:
|
||||
roslaunch_deps_main(['roslaunch-deps', invalid_f, '--verbose'])
|
||||
assert False, "should have failed: %s"%b.getvalue()
|
||||
except SystemExit:
|
||||
pass
|
||||
with fakestdout() as b:
|
||||
try:
|
||||
roslaunch_deps_main(['roslaunch-deps', not_f, '--verbose'])
|
||||
assert False, "should have failed: %s"%b.getvalue()
|
||||
except SystemExit:
|
||||
pass
|
||||
|
||||
# try with files from different pacakges
|
||||
with fakestdout() as b:
|
||||
try:
|
||||
roslaunch_deps_main(['roslaunch-deps', f, rosmaster_f, '--verbose'])
|
||||
assert False, "should have failed"
|
||||
except SystemExit:
|
||||
pass
|
||||
|
||||
def test_roslaunch_deps():
|
||||
from roslaunch.depends import roslaunch_deps, RoslaunchDeps
|
||||
example_d = os.path.join(rospkg.RosPack().get_path('roslaunch'), 'resources')
|
||||
|
||||
min_deps = RoslaunchDeps(nodes=[('rospy', 'talker.py')], pkgs=['rospy'])
|
||||
include_deps = RoslaunchDeps(nodes=[('rospy', 'talker.py'), ('rospy', 'listener.py')], pkgs=['rospy'])
|
||||
example_deps = RoslaunchDeps(nodes=[('rospy', 'talker.py'), ('rospy', 'listener.py')], pkgs=['rospy'],
|
||||
includes=[os.path.join(example_d, 'example-include.launch')])
|
||||
|
||||
example_file_deps = {
|
||||
os.path.join(example_d, 'example.launch') : example_deps,
|
||||
|
||||
os.path.join(example_d, 'example-include.launch') : include_deps,
|
||||
}
|
||||
example_min_file_deps = {
|
||||
os.path.join(example_d, 'example-min.launch') : min_deps,
|
||||
}
|
||||
r_missing = {'roslaunch': set(['rospy'])}
|
||||
tests = [
|
||||
([os.path.join(example_d, 'example-min.launch')], ('roslaunch', example_min_file_deps, r_missing)),
|
||||
|
||||
([os.path.join(example_d, 'example.launch')], ('roslaunch', example_file_deps, r_missing)),
|
||||
|
||||
]
|
||||
for files, results in tests:
|
||||
for v in [True, False]:
|
||||
base_pkg, file_deps, missing = roslaunch_deps(files, verbose=v)
|
||||
assert base_pkg == results[0]
|
||||
assert file_deps == results[1], "\n%s vs \n%s"%(file_deps, results[1])
|
||||
assert missing == results[2], "\n%s vs \n%s"%(missing, results[2])
|
||||
|
||||
108
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_dump_params.py
vendored
Normal file
108
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_dump_params.py
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2010, 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 time
|
||||
import unittest
|
||||
import yaml
|
||||
|
||||
from subprocess import Popen, PIPE, check_call, call
|
||||
|
||||
class TestDumpParams(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def test_roslaunch(self):
|
||||
# network is initialized
|
||||
cmd = 'roslaunch'
|
||||
|
||||
# Smoke test for testing parameters
|
||||
p = Popen([cmd, '--dump-params', 'roslaunch', 'noop.launch'], stdout = PIPE)
|
||||
o, e = p.communicate()
|
||||
self.assert_(p.returncode == 0, "Return code nonzero for param dump! Code: %d" % (p.returncode))
|
||||
|
||||
self.assertEquals({'/noop': 'noop'}, yaml.load(o))
|
||||
|
||||
p = Popen([cmd, '--dump-params', 'roslaunch', 'test-dump-rosparam.launch'], stdout = PIPE)
|
||||
o, e = p.communicate()
|
||||
self.assert_(p.returncode == 0, "Return code nonzero for param dump! Code: %d" % (p.returncode))
|
||||
|
||||
val = {
|
||||
'/string1': 'bar',
|
||||
'/dict1/head': 1,
|
||||
'/dict1/shoulders': 2,
|
||||
'/dict1/knees': 3,
|
||||
'/dict1/toes': 4,
|
||||
|
||||
'/rosparam/string1': 'bar',
|
||||
'/rosparam/dict1/head': 1,
|
||||
'/rosparam/dict1/shoulders': 2,
|
||||
'/rosparam/dict1/knees': 3,
|
||||
'/rosparam/dict1/toes': 4,
|
||||
|
||||
'/node_rosparam/string1': 'bar',
|
||||
'/node_rosparam/dict1/head': 1,
|
||||
'/node_rosparam/dict1/shoulders': 2,
|
||||
'/node_rosparam/dict1/knees': 3,
|
||||
'/node_rosparam/dict1/toes': 4,
|
||||
'/node_rosparam/tilde1': 'foo',
|
||||
'/node_rosparam/local_param': 'baz',
|
||||
|
||||
'/node_rosparam2/tilde1': 'foo',
|
||||
|
||||
'/inline_str': 'value1',
|
||||
'/inline_list': [1, 2, 3, 4],
|
||||
'/inline_dict/key1': 'value1',
|
||||
'/inline_dict/key2': 'value2',
|
||||
|
||||
'/inline_dict2/key3': 'value3',
|
||||
'/inline_dict2/key4': 'value4',
|
||||
|
||||
'/override/key1': 'override1',
|
||||
'/override/key2': 'value2',
|
||||
'/noparam1': 'value1',
|
||||
'/noparam2': 'value2',
|
||||
}
|
||||
output_val = yaml.load(o)
|
||||
if not val == output_val:
|
||||
for k, v in val.items():
|
||||
if k not in output_val:
|
||||
self.fail("key [%s] not in output: %s"%(k, output_val))
|
||||
elif v != output_val[k]:
|
||||
self.fail("key [%s] value [%s] does not match output: %s"%(k, v, output_val[k]))
|
||||
self.assertEquals(val, output_val)
|
||||
for k in ('/node_rosparam/tilde2', '/node_rosparam2/tilde2', '/node_rosparam2/local_param'):
|
||||
if k in output_val:
|
||||
self.fail("key [%s] should not be in output: %s"%(k, output_val))
|
||||
179
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_launch.py
vendored
Normal file
179
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_launch.py
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
# 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 unittest
|
||||
|
||||
## Test roslaunch.launch
|
||||
class TestRoslaunchLaunch(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.printerrlog_msg = None
|
||||
|
||||
def my_printerrlog(self, msg):
|
||||
self.printerrlog_msg = msg
|
||||
|
||||
def test_validate_master_launch(self):
|
||||
import roslaunch.launch
|
||||
from roslaunch.core import Master
|
||||
from roslaunch.launch import validate_master_launch
|
||||
roslaunch.launch.printerrlog = self.my_printerrlog
|
||||
|
||||
# Good configurations
|
||||
os.environ['ROS_MASTER_URI'] = 'http://localhost:11311'
|
||||
m = Master(uri='http://localhost:11311')
|
||||
validate_master_launch(m, True)
|
||||
self.assertEquals(None, self.printerrlog_msg)
|
||||
validate_master_launch(m, False)
|
||||
self.assertEquals(None, self.printerrlog_msg)
|
||||
|
||||
# roscore with mismatched port in environment
|
||||
os.environ['ROS_MASTER_URI'] = 'http://localhost:11312'
|
||||
validate_master_launch(m, True)
|
||||
self.assert_('port' in self.printerrlog_msg)
|
||||
self.printerrlog_msg = None
|
||||
|
||||
# roscore with mismatched hostname in environment
|
||||
os.environ['ROS_MASTER_URI'] = 'http://fake:11311'
|
||||
validate_master_launch(m, True)
|
||||
self.assert_('host' in self.printerrlog_msg)
|
||||
self.printerrlog_msg = None
|
||||
|
||||
# roslaunch with remote master that cannot be contacted
|
||||
os.environ['ROS_MASTER_URI'] = 'http://fake:11311'
|
||||
self.assertEquals(None, self.printerrlog_msg)
|
||||
|
||||
# environment doesn't matter for remaining tests
|
||||
os.environ['ROS_MASTER_URI'] = 'http://localhost:11311'
|
||||
m = Master(uri="http://fake:11311")
|
||||
|
||||
# roscore with hostname that points elsewhere, warn user. This
|
||||
# generally could only happen if the user has a bad local host
|
||||
# config.
|
||||
validate_master_launch(m, True)
|
||||
self.assert_("WARNING" in self.printerrlog_msg)
|
||||
self.printerrlog_msg = None
|
||||
|
||||
# roscore with host that is not ours
|
||||
m = Master(uri="http://willowgarage.com:11311")
|
||||
validate_master_launch(m, True)
|
||||
self.assert_("WARNING" in self.printerrlog_msg)
|
||||
self.printerrlog_msg = None
|
||||
|
||||
# roslaunch with remote master that is out of contact, fail
|
||||
try:
|
||||
validate_master_launch(m, False)
|
||||
self.fail("should not pass if remote master cannot be contacted")
|
||||
except roslaunch.RLException:
|
||||
pass
|
||||
|
||||
def test__unify_clear_params(self):
|
||||
from roslaunch.launch import _unify_clear_params
|
||||
self.assertEquals([], _unify_clear_params([]))
|
||||
for t in [['/foo'], ['/foo/'], ['/foo/', '/foo'],
|
||||
['/foo/', '/foo/'], ['/foo/', '/foo/bar', '/foo/'],
|
||||
['/foo/', '/foo/bar', '/foo/bar/baz']]:
|
||||
self.assertEquals(['/foo/'], _unify_clear_params(t))
|
||||
for t in [['/'], ['/', '/foo/'], ['/foo/', '/', '/baz', '/car/dog']]:
|
||||
self.assertEquals(['/'], _unify_clear_params(t))
|
||||
|
||||
self.assertEquals(['/foo/', '/bar/', '/baz/'], _unify_clear_params(['/foo', '/bar', '/baz']))
|
||||
self.assertEquals(['/foo/', '/bar/', '/baz/'], _unify_clear_params(['/foo', '/bar', '/baz', '/bar/delta', '/baz/foo']))
|
||||
self.assertEquals(['/foo/bar/'], _unify_clear_params(['/foo/bar', '/foo/bar/baz']))
|
||||
|
||||
|
||||
def test__hostname_to_rosname(self):
|
||||
from roslaunch.launch import _hostname_to_rosname
|
||||
self.assertEquals("host_ann", _hostname_to_rosname('ann'))
|
||||
self.assertEquals("host_ann", _hostname_to_rosname('ANN'))
|
||||
self.assertEquals("host_", _hostname_to_rosname(''))
|
||||
self.assertEquals("host_1", _hostname_to_rosname('1'))
|
||||
self.assertEquals("host__", _hostname_to_rosname('_'))
|
||||
self.assertEquals("host__", _hostname_to_rosname('-'))
|
||||
self.assertEquals("host_foo_laptop", _hostname_to_rosname('foo-laptop'))
|
||||
|
||||
def test_roslaunchListeners(self):
|
||||
import roslaunch.launch
|
||||
class L(roslaunch.launch.ROSLaunchListener):
|
||||
def process_died(self, process_name, exit_code):
|
||||
self.process_name = process_name
|
||||
self.exit_code = exit_code
|
||||
class LBad(roslaunch.launch.ROSLaunchListener):
|
||||
def process_died(self, process_name, exit_code):
|
||||
raise Exception("foo")
|
||||
|
||||
listeners = roslaunch.launch._ROSLaunchListeners()
|
||||
l1 = L()
|
||||
l2 = L()
|
||||
lbad = L()
|
||||
l3 = L()
|
||||
# test with no listeners
|
||||
listeners.process_died('p0', 0)
|
||||
# test with 1 listener
|
||||
listeners.add_process_listener(l1)
|
||||
listeners.process_died('p1', 1)
|
||||
self.assertEquals(l1.process_name, 'p1')
|
||||
self.assertEquals(l1.exit_code, 1)
|
||||
|
||||
# test with 2 listeners
|
||||
listeners.add_process_listener(l2)
|
||||
listeners.process_died('p2', 2)
|
||||
for l in [l1, l2]:
|
||||
self.assertEquals(l.process_name, 'p2')
|
||||
self.assertEquals(l.exit_code, 2)
|
||||
|
||||
listeners.add_process_listener(lbad)
|
||||
# make sure that this catches errors
|
||||
listeners.process_died('p3', 3)
|
||||
for l in [l1, l2]:
|
||||
self.assertEquals(l.process_name, 'p3')
|
||||
self.assertEquals(l.exit_code, 3)
|
||||
# also add a third listener to make sure that listeners continues after lbad throws
|
||||
listeners.add_process_listener(l3)
|
||||
listeners.process_died('p4', 4)
|
||||
for l in [l1, l2, l3]:
|
||||
self.assertEquals(l.process_name, 'p4')
|
||||
self.assertEquals(l.exit_code, 4)
|
||||
|
||||
# this is just to get coverage, it's an empty class
|
||||
def test_ROSRemoteRunnerIF():
|
||||
from roslaunch.launch import ROSRemoteRunnerIF
|
||||
r = ROSRemoteRunnerIF()
|
||||
r.setup()
|
||||
r.add_process_listener(1)
|
||||
r.launch_remote_nodes()
|
||||
|
||||
def test_ROSLaunchListener():
|
||||
from roslaunch.launch import ROSLaunchListener
|
||||
r = ROSLaunchListener()
|
||||
r.process_died(1, 2)
|
||||
76
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_list_files.py
vendored
Normal file
76
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_list_files.py
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2011, 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 time
|
||||
import unittest
|
||||
import roslib.packages
|
||||
|
||||
from subprocess import Popen, PIPE, check_call, call
|
||||
|
||||
def get_test_path():
|
||||
return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'xml'))
|
||||
|
||||
class TestListFiles(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def test_list_files(self):
|
||||
cmd = 'roslaunch'
|
||||
|
||||
# check error behavior
|
||||
p = Popen([cmd, '--files'], stdout = PIPE)
|
||||
p.communicate()
|
||||
self.assert_(p.returncode != 0, "Should have failed w/o file argument. Code: %d" % (p.returncode))
|
||||
|
||||
d = get_test_path()
|
||||
|
||||
p = Popen([cmd, '--files', 'roslaunch', 'test-valid.xml'], stdout = PIPE)
|
||||
o = p.communicate()[0]
|
||||
o = o.decode()
|
||||
self.assert_(p.returncode == 0, "Return code nonzero for list files! Code: %d" % (p.returncode))
|
||||
self.assertEquals(os.path.realpath(os.path.join(d, 'test-valid.xml')), os.path.realpath(o.strip()))
|
||||
|
||||
print("check 1", o)
|
||||
|
||||
p = Popen([cmd, '--files', 'roslaunch', 'test-env.xml'], stdout = PIPE)
|
||||
o = p.communicate()[0]
|
||||
o = o.decode()
|
||||
self.assert_(p.returncode == 0, "Return code nonzero for list files! Code: %d" % (p.returncode))
|
||||
self.assertEquals(set([os.path.realpath(os.path.join(d, 'test-env.xml')), os.path.realpath(os.path.join(d, 'test-env-include.xml'))]),
|
||||
set([os.path.realpath(x.strip()) for x in o.split() if x.strip()]))
|
||||
|
||||
print("check 2", o)
|
||||
122
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_param_dump.py
vendored
Normal file
122
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_param_dump.py
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# Copyright (c) 2012, 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
|
||||
from contextlib import contextmanager
|
||||
@contextmanager
|
||||
def fakestdout():
|
||||
realstdout = sys.stdout
|
||||
fakestdout = StringIO()
|
||||
sys.stdout = fakestdout
|
||||
yield fakestdout
|
||||
sys.stdout = realstdout
|
||||
|
||||
import rospkg
|
||||
import logging
|
||||
|
||||
SAMPLE1 = """/rosparam_load/dict1/head: 1
|
||||
/rosparam_load/dict1/knees: 3
|
||||
/rosparam_load/dict1/shoulders: 2
|
||||
/rosparam_load/dict1/toes: 4
|
||||
/rosparam_load/integer1: 1
|
||||
/rosparam_load/integer2: 2
|
||||
/rosparam_load/list1: [head, shoulders, knees, toes]
|
||||
/rosparam_load/list2: [1, 1, 2, 3, 5, 8]
|
||||
/rosparam_load/preformattedtext: 'This is the first line
|
||||
|
||||
This is the second line
|
||||
|
||||
Line breaks are preserved
|
||||
|
||||
Indentation is stripped
|
||||
|
||||
'
|
||||
/rosparam_load/robots/child/grandchildparam: a grandchild namespace param
|
||||
/rosparam_load/robots/childparam: a child namespace parameter
|
||||
/rosparam_load/string1: bar
|
||||
/rosparam_load/string2: '10'"""
|
||||
|
||||
SAMPLE2 = """/load_ns/subns/dict1/head: 1
|
||||
/load_ns/subns/dict1/knees: 3
|
||||
/load_ns/subns/dict1/shoulders: 2
|
||||
/load_ns/subns/dict1/toes: 4
|
||||
/load_ns/subns/integer1: 1
|
||||
/load_ns/subns/integer2: 2
|
||||
/load_ns/subns/list1: [head, shoulders, knees, toes]
|
||||
/load_ns/subns/list2: [1, 1, 2, 3, 5, 8]
|
||||
/load_ns/subns/preformattedtext: 'This is the first line
|
||||
|
||||
This is the second line
|
||||
|
||||
Line breaks are preserved
|
||||
|
||||
Indentation is stripped
|
||||
|
||||
'
|
||||
/load_ns/subns/robots/child/grandchildparam: a grandchild namespace param
|
||||
/load_ns/subns/robots/childparam: a child namespace parameter
|
||||
/load_ns/subns/string1: bar
|
||||
/load_ns/subns/string2: '10'"""
|
||||
|
||||
|
||||
def test_dump_params():
|
||||
# normal entrypoint has logging configured
|
||||
logger = logging.getLogger('roslaunch').setLevel(logging.CRITICAL)
|
||||
from roslaunch.param_dump import dump_params
|
||||
roslaunch_d = rospkg.RosPack().get_path('roslaunch')
|
||||
test_d = os.path.join(roslaunch_d, 'test', 'xml')
|
||||
node_rosparam_f = os.path.join(test_d, 'test-node-rosparam-load.xml')
|
||||
with fakestdout() as b:
|
||||
assert dump_params([node_rosparam_f])
|
||||
s = b.getvalue().strip()
|
||||
# remove float vals as serialization is not stable
|
||||
s = '\n'.join([x for x in s.split('\n') if not 'float' in x])
|
||||
assert str(s) == str(SAMPLE1), "[%s]\nvs\n[%s]"%(s, SAMPLE1)
|
||||
node_rosparam_f = os.path.join(test_d, 'test-node-rosparam-load-ns.xml')
|
||||
with fakestdout() as b:
|
||||
assert dump_params([node_rosparam_f])
|
||||
s = b.getvalue().strip()
|
||||
# remove float vals as serialization is not stable
|
||||
s = '\n'.join([x for x in s.split('\n') if not 'float' in x])
|
||||
assert str(s) == str(SAMPLE2), "[%s]\nvs\n[%s]"%(s, SAMPLE2)
|
||||
|
||||
invalid_f = os.path.join(test_d, 'invalid-xml.xml')
|
||||
with fakestdout() as b:
|
||||
assert not dump_params([invalid_f])
|
||||
|
||||
244
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_parent.py
vendored
Normal file
244
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_parent.py
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
# 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 unittest
|
||||
import time
|
||||
|
||||
import rospkg
|
||||
import rosgraph.network
|
||||
import roslaunch.parent
|
||||
|
||||
import rosgraph
|
||||
master = rosgraph.Master('test_roslaunch_parent')
|
||||
def get_param(*args):
|
||||
return master.getParam(*args)
|
||||
|
||||
## Fake Process object
|
||||
class ProcessMock(roslaunch.pmon.Process):
|
||||
def __init__(self, package, name, args, env, respawn=False):
|
||||
super(ProcessMock, self).__init__(package, name, args, env, respawn)
|
||||
self.stopped = False
|
||||
def stop(self):
|
||||
self.stopped = True
|
||||
|
||||
## Fake ProcessMonitor object
|
||||
class ProcessMonitorMock(object):
|
||||
def __init__(self):
|
||||
self.core_procs = []
|
||||
self.procs = []
|
||||
self.listeners = []
|
||||
self.is_shutdown = False
|
||||
|
||||
def join(self, timeout=0):
|
||||
pass
|
||||
|
||||
def add_process_listener(self, l):
|
||||
self.listeners.append(l)
|
||||
|
||||
def register(self, p):
|
||||
self.procs.append(p)
|
||||
|
||||
def register_core_proc(self, p):
|
||||
self.core_procs.append(p)
|
||||
|
||||
def registrations_complete(self):
|
||||
pass
|
||||
|
||||
def unregister(self, p):
|
||||
self.procs.remove(p)
|
||||
|
||||
def has_process(self, name):
|
||||
return len([p for p in self.procs if p.name == name]) > 0
|
||||
|
||||
def get_process(self, name):
|
||||
val = [p for p in self.procs if p.name == name]
|
||||
if val:
|
||||
return val[0]
|
||||
return None
|
||||
|
||||
def has_main_thread_jobs(self):
|
||||
return False
|
||||
|
||||
def do_main_thread_jobs(self):
|
||||
pass
|
||||
|
||||
def kill_process(self, name):
|
||||
pass
|
||||
|
||||
def shutdown(self):
|
||||
self.is_shutdown = True
|
||||
|
||||
def get_active_names(self):
|
||||
return [p.name for p in self.procs]
|
||||
|
||||
def get_process_names_with_spawn_count(self):
|
||||
actives = [(p.name, p.spawn_count) for p in self.procs]
|
||||
deads = []
|
||||
return [actives, deads]
|
||||
|
||||
def mainthread_spin_once(self):
|
||||
pass
|
||||
|
||||
def mainthread_spin(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
## Test roslaunch.server
|
||||
class TestRoslaunchParent(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.pmon = ProcessMonitorMock()
|
||||
|
||||
def test_roslaunchParent(self):
|
||||
try:
|
||||
self._subroslaunchParent()
|
||||
finally:
|
||||
self.pmon.shutdown()
|
||||
|
||||
def _subroslaunchParent(self):
|
||||
from roslaunch.parent import ROSLaunchParent
|
||||
pmon = self.pmon
|
||||
try:
|
||||
# if there is a core up, we have to use its run id
|
||||
run_id = get_param('/run_id')
|
||||
except:
|
||||
run_id = 'test-rl-parent-%s'%time.time()
|
||||
name = 'foo-bob'
|
||||
server_uri = 'http://localhost:12345'
|
||||
|
||||
p = ROSLaunchParent(run_id, [], is_core = True, port=None, local_only=False)
|
||||
self.assertEquals(run_id, p.run_id)
|
||||
self.assertEquals(True, p.is_core)
|
||||
self.assertEquals(False, p.local_only)
|
||||
|
||||
rl_dir = rospkg.RosPack().get_path('roslaunch')
|
||||
rl_file = os.path.join(rl_dir, 'resources', 'example.launch')
|
||||
self.assert_(os.path.isfile(rl_file))
|
||||
|
||||
# validate load_config logic
|
||||
p = ROSLaunchParent(run_id, [rl_file], is_core = False, port=None, local_only=True)
|
||||
self.assertEquals(run_id, p.run_id)
|
||||
self.assertEquals(False, p.is_core)
|
||||
self.assertEquals(True, p.local_only)
|
||||
|
||||
self.assert_(p.config is None)
|
||||
p._load_config()
|
||||
self.assert_(p.config is not None)
|
||||
self.assert_(p.config.nodes)
|
||||
|
||||
# try again with port override
|
||||
p = ROSLaunchParent(run_id, [rl_file], is_core = False, port=11312, local_only=True)
|
||||
self.assertEquals(11312, p.port)
|
||||
self.assert_(p.config is None)
|
||||
p._load_config()
|
||||
# - make sure port got passed into master
|
||||
_, port = rosgraph.network.parse_http_host_and_port(p.config.master.uri)
|
||||
self.assertEquals(11312, port)
|
||||
|
||||
# try again with bad file
|
||||
p = ROSLaunchParent(run_id, ['non-existent-fake.launch'])
|
||||
self.assert_(p.config is None)
|
||||
try:
|
||||
p._load_config()
|
||||
self.fail("load config should have failed due to bad rl file")
|
||||
except roslaunch.core.RLException: pass
|
||||
|
||||
# try again with bad xml
|
||||
rl_dir = rospkg.RosPack().get_path('roslaunch')
|
||||
rl_file = os.path.join(rl_dir, 'test', 'xml', 'test-params-invalid-1.xml')
|
||||
self.assert_(os.path.isfile(rl_file))
|
||||
p = ROSLaunchParent(run_id, [rl_file])
|
||||
self.assert_(p.config is None)
|
||||
try:
|
||||
p._load_config()
|
||||
self.fail("load config should have failed due to bad rl file")
|
||||
except roslaunch.core.RLException: pass
|
||||
|
||||
# Mess around with internal repr to get code coverage on _init_runner/_init_remote
|
||||
p = ROSLaunchParent(run_id, [], is_core = False, port=None, local_only=True)
|
||||
# no config, _init_runner/_init_remote/_start_server should fail
|
||||
for m in ['_init_runner', '_init_remote', '_start_server']:
|
||||
try:
|
||||
getattr(p, m)()
|
||||
self.fail('should have raised')
|
||||
except roslaunch.core.RLException: pass
|
||||
|
||||
# - initialize p.config
|
||||
p.config = roslaunch.config.ROSLaunchConfig()
|
||||
|
||||
# no pm, _init_runner/_init_remote/_start_server should fail
|
||||
for m in ['_init_runner', '_init_remote', '_start_server']:
|
||||
try:
|
||||
getattr(p, m)()
|
||||
self.fail('should have raised')
|
||||
except roslaunch.core.RLException: pass
|
||||
|
||||
# - initialize p.pm
|
||||
p.pm = pmon
|
||||
|
||||
for m in ['_init_runner', '_init_remote']:
|
||||
try:
|
||||
getattr(p, m)()
|
||||
self.fail('should have raised')
|
||||
except roslaunch.core.RLException: pass
|
||||
|
||||
from roslaunch.server import ROSLaunchParentNode
|
||||
p.server = ROSLaunchParentNode(p.config, pmon)
|
||||
p._init_runner()
|
||||
# roslaunch runner should be initialized
|
||||
self.assert_(p.runner is not None)
|
||||
|
||||
# test _init_remote
|
||||
p.local_only = True
|
||||
p._init_remote()
|
||||
p.local_only = False
|
||||
# - this violates many abstractions to do this
|
||||
def ftrue():
|
||||
return True
|
||||
p.config.has_remote_nodes = ftrue
|
||||
p._init_remote()
|
||||
self.assert_(p.remote_runner is not None)
|
||||
|
||||
self.failIf(pmon.is_shutdown)
|
||||
p.shutdown()
|
||||
self.assert_(pmon.is_shutdown)
|
||||
|
||||
def kill_parent(p, delay=1.0):
|
||||
# delay execution so that whatever pmon method we're calling has time to enter
|
||||
time.sleep(delay)
|
||||
print("stopping parent")
|
||||
p.shutdown()
|
||||
|
||||
580
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_pmon.py
vendored
Normal file
580
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_pmon.py
vendored
Normal file
@@ -0,0 +1,580 @@
|
||||
# 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 unittest
|
||||
import time
|
||||
import threading
|
||||
|
||||
import roslaunch.server
|
||||
|
||||
## handy class for kill_pmon to check whether it was called
|
||||
class Marker(object):
|
||||
def __init__(self):
|
||||
self.marked = False
|
||||
def mark(self):
|
||||
self.marked = True
|
||||
|
||||
## Fake ProcessMonitor object
|
||||
class ProcessMonitorMock(object):
|
||||
def __init__(self):
|
||||
self.core_procs = []
|
||||
self.procs = []
|
||||
self.listeners = []
|
||||
self.alive = False
|
||||
self.is_shutdown = False
|
||||
|
||||
def isAlive(self):
|
||||
return self.alive
|
||||
|
||||
def join(self, *args):
|
||||
return
|
||||
|
||||
def add_process_listener(self, l):
|
||||
self.listeners.append(l)
|
||||
|
||||
def register(self, p):
|
||||
self.procs.append(p)
|
||||
|
||||
def register_core_proc(self, p):
|
||||
self.core_procs.append(p)
|
||||
|
||||
def registrations_complete(self):
|
||||
pass
|
||||
|
||||
def unregister(self, p):
|
||||
self.procs.remove(p)
|
||||
|
||||
def has_process(self, name):
|
||||
return len([p for p in self.procs if p.name == name]) > 0
|
||||
|
||||
def get_process(self, name):
|
||||
return self.procs.get(p, None)
|
||||
|
||||
def has_main_thread_jobs(self):
|
||||
return False
|
||||
|
||||
def do_main_thread_jobs(self):
|
||||
pass
|
||||
|
||||
def kill_process(self, name):
|
||||
pass
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def get_active_names(self):
|
||||
return [p.name for p in self.procs]
|
||||
|
||||
def get_process_names_with_spawn_count(self):
|
||||
actives = [(p.name, p.spawn_count) for p in self.procs]
|
||||
deads = []
|
||||
retval = [actives, deads]
|
||||
|
||||
def mainthread_spin_once(self):
|
||||
pass
|
||||
|
||||
def mainthread_spin(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
class ProcessMock(roslaunch.pmon.Process):
|
||||
def __init__(self, package, name, args, env, respawn=False):
|
||||
super(ProcessMock, self).__init__(package, name, args, env, respawn)
|
||||
self.stopped = False
|
||||
def stop(self, errors):
|
||||
self.stopped = True
|
||||
|
||||
class RespawnOnceProcessMock(ProcessMock):
|
||||
def __init__(self, package, name, args, env, respawn=True):
|
||||
super(ProcessMock, self).__init__(package, name, args, env, respawn)
|
||||
self.spawn_count = 0
|
||||
|
||||
def is_alive(self):
|
||||
self.time_of_death = time.time()
|
||||
return False
|
||||
|
||||
def start(self):
|
||||
self.spawn_count += 1
|
||||
if self.spawn_count > 1:
|
||||
self.respawn = False
|
||||
self.time_of_death = None
|
||||
|
||||
class RespawnOnceWithDelayProcessMock(ProcessMock):
|
||||
def __init__(self, package, name, args, env, respawn=True,
|
||||
respawn_delay=1.0):
|
||||
super(ProcessMock, self).__init__(package, name, args, env, respawn,
|
||||
respawn_delay=respawn_delay)
|
||||
self.spawn_count = 0
|
||||
self.respawn_interval = None
|
||||
|
||||
def is_alive(self):
|
||||
if self.time_of_death is None:
|
||||
self.time_of_death = time.time()
|
||||
return False
|
||||
|
||||
def start(self):
|
||||
self.spawn_count += 1
|
||||
if self.spawn_count > 1:
|
||||
self.respawn = False
|
||||
self.respawn_interval = time.time() - self.time_of_death
|
||||
self.time_of_death = None
|
||||
|
||||
## Test roslaunch.server
|
||||
class TestRoslaunchPmon(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.pmon = roslaunch.pmon.ProcessMonitor()
|
||||
|
||||
## test all apis of Process instance. part coverage/sanity test
|
||||
def _test_Process(self, p, package, name, args, env, respawn, respawn_delay):
|
||||
self.assertEquals(package, p.package)
|
||||
self.assertEquals(name, p.name)
|
||||
self.assertEquals(args, p.args)
|
||||
self.assertEquals(env, p.env)
|
||||
self.assertEquals(respawn, p.respawn)
|
||||
self.assertEquals(respawn_delay, p.respawn_delay)
|
||||
self.assertEquals(0, p.spawn_count)
|
||||
self.assertEquals(None, p.exit_code)
|
||||
self.assert_(p.get_exit_description())
|
||||
self.failIf(p.is_alive())
|
||||
|
||||
info = p.get_info()
|
||||
self.assertEquals(package, info['package'])
|
||||
self.assertEquals(name, info['name'])
|
||||
self.assertEquals(args, info['args'])
|
||||
self.assertEquals(env, info['env'])
|
||||
self.assertEquals(respawn, info['respawn'])
|
||||
self.assertEquals(respawn_delay, info['respawn_delay'])
|
||||
self.assertEquals(0, info['spawn_count'])
|
||||
self.failIf('exit_code' in info)
|
||||
|
||||
p.start()
|
||||
self.assertEquals(1, p.spawn_count)
|
||||
self.assertEquals(1, p.get_info()['spawn_count'])
|
||||
p.start()
|
||||
self.assertEquals(2, p.spawn_count)
|
||||
self.assertEquals(2, p.get_info()['spawn_count'])
|
||||
|
||||
# noop
|
||||
p.stop()
|
||||
|
||||
p.exit_code = 0
|
||||
self.assertEquals(0, p.get_info()['exit_code'])
|
||||
self.assert_('cleanly' in p.get_exit_description())
|
||||
p.exit_code = 1
|
||||
self.assertEquals(1, p.get_info()['exit_code'])
|
||||
self.assert_('[exit code 1]' in p.get_exit_description())
|
||||
|
||||
## tests to make sure that our Process base class has 100% coverage
|
||||
def test_Process(self):
|
||||
from roslaunch.pmon import Process
|
||||
# test constructor params
|
||||
respawn = False
|
||||
package = 'foo-%s'%time.time()
|
||||
name = 'name-%s'%time.time()
|
||||
args = [time.time(), time.time(), time.time()]
|
||||
env = { 'key': time.time(), 'key2': time.time() }
|
||||
|
||||
p = Process(package, name, args, env, 0.0)
|
||||
self._test_Process(p, package, name, args, env, False, 0.0)
|
||||
p = Process(package, name, args, env, True, 0.0)
|
||||
self._test_Process(p, package, name, args, env, True, 0.0)
|
||||
p = Process(package, name, args, env, False, 0.0)
|
||||
self._test_Process(p, package, name, args, env, False, 0.0)
|
||||
p = Process(package, name, args, env, True, 1.0)
|
||||
self._test_Process(p, package, name, args, env, True, 1.0)
|
||||
|
||||
def _test_DeadProcess(self, p0, package, name, args, env, respawn,
|
||||
respawn_delay):
|
||||
from roslaunch.pmon import DeadProcess
|
||||
p0.exit_code = -1
|
||||
dp = DeadProcess(p0)
|
||||
self.assertEquals(package, dp.package)
|
||||
self.assertEquals(name, dp.name)
|
||||
self.assertEquals(args, dp.args)
|
||||
self.assertEquals(env, dp.env)
|
||||
self.assertEquals(respawn, dp.respawn)
|
||||
self.assertEquals(respawn_delay, dp.respawn_delay)
|
||||
self.assertEquals(0, dp.spawn_count)
|
||||
self.assertEquals(-1, dp.exit_code)
|
||||
self.failIf(dp.is_alive())
|
||||
|
||||
info = dp.get_info()
|
||||
info0 = p0.get_info()
|
||||
self.assertEquals(info0['package'], info['package'])
|
||||
self.assertEquals(info0['name'], info['name'])
|
||||
self.assertEquals(info0['args'], info['args'])
|
||||
self.assertEquals(info0['env'], info['env'])
|
||||
self.assertEquals(info0['respawn'], info['respawn'])
|
||||
self.assertEquals(info0['respawn_delay'], info['respawn_delay'])
|
||||
self.assertEquals(0, info['spawn_count'])
|
||||
|
||||
try:
|
||||
dp.start()
|
||||
self.fail("should not be able to start a dead process")
|
||||
except: pass
|
||||
|
||||
# info should be frozen
|
||||
p0.package = 'dead package'
|
||||
p0.name = 'dead name'
|
||||
p0.spawn_count = 1
|
||||
self.assertEquals(package, dp.package)
|
||||
self.assertEquals(name, dp.name)
|
||||
self.assertEquals(0, dp.spawn_count)
|
||||
self.assertEquals(package, dp.get_info()['package'])
|
||||
self.assertEquals(name, dp.get_info()['name'])
|
||||
self.assertEquals(0, dp.get_info()['spawn_count'])
|
||||
p0.start()
|
||||
self.assertEquals(0, dp.spawn_count)
|
||||
self.assertEquals(0, dp.get_info()['spawn_count'])
|
||||
|
||||
# noop
|
||||
p0.stop()
|
||||
|
||||
|
||||
def test_DeadProcess(self):
|
||||
from roslaunch.pmon import Process, DeadProcess
|
||||
# test constructor params
|
||||
respawn = False
|
||||
package = 'foo-%s'%time.time()
|
||||
name = 'name-%s'%time.time()
|
||||
args = [time.time(), time.time(), time.time()]
|
||||
env = { 'key': time.time(), 'key2': time.time() }
|
||||
|
||||
p = Process(package, name, args, env, 0.0)
|
||||
self._test_DeadProcess(p, package, name, args, env, False, 0.0)
|
||||
p = Process(package, name, args, env, True, 0.0)
|
||||
self._test_DeadProcess(p, package, name, args, env, True, 0.0)
|
||||
p = Process(package, name, args, env, False, 0.0)
|
||||
self._test_DeadProcess(p, package, name, args, env, False, 0.0)
|
||||
p = Process(package, name, args, env, True, 1.0)
|
||||
self._test_DeadProcess(p, package, name, args, env, True, 1.0)
|
||||
|
||||
def test_start_shutdown_process_monitor(self):
|
||||
def failer():
|
||||
raise Exception("oops")
|
||||
# noop
|
||||
self.failIf(roslaunch.pmon.shutdown_process_monitor(None))
|
||||
|
||||
# test with fake pmon so we can get branch-complete
|
||||
pmon = ProcessMonitorMock()
|
||||
# - by setting alive to true, shutdown fails, though it can't really do anything about it
|
||||
pmon.alive = True
|
||||
self.failIf(roslaunch.pmon.shutdown_process_monitor(pmon))
|
||||
|
||||
# make sure that exceptions get trapped
|
||||
pmon.shutdown = failer
|
||||
# should cause an exception during execution, but should get caught
|
||||
self.failIf(roslaunch.pmon.shutdown_process_monitor(pmon))
|
||||
|
||||
# Test with a real process monitor
|
||||
pmon = roslaunch.pmon.start_process_monitor()
|
||||
self.assert_(pmon.isAlive())
|
||||
self.assert_(roslaunch.pmon.shutdown_process_monitor(pmon))
|
||||
self.failIf(pmon.isAlive())
|
||||
|
||||
# fiddle around with some state that would shouldn't be
|
||||
roslaunch.pmon._shutting_down = True
|
||||
pmon = roslaunch.pmon.start_process_monitor()
|
||||
if pmon != None:
|
||||
self.failIf(roslaunch.pmon.shutdown_process_monitor(pmon))
|
||||
self.fail("start_process_monitor should fail if during shutdown sequence")
|
||||
|
||||
def test_pmon_shutdown(self):
|
||||
# should be noop
|
||||
roslaunch.pmon.pmon_shutdown()
|
||||
|
||||
# start two real process monitors and kill them
|
||||
# pmon_shutdown
|
||||
pmon1 = roslaunch.pmon.start_process_monitor()
|
||||
pmon2 = roslaunch.pmon.start_process_monitor()
|
||||
self.assert_(pmon1.isAlive())
|
||||
self.assert_(pmon2.isAlive())
|
||||
|
||||
roslaunch.pmon.pmon_shutdown()
|
||||
|
||||
self.failIf(pmon1.isAlive())
|
||||
self.failIf(pmon2.isAlive())
|
||||
|
||||
def test_add_process_listener(self):
|
||||
# coverage test, not a functionality test as that would be much more difficult to simulate
|
||||
from roslaunch.pmon import ProcessListener
|
||||
l = ProcessListener()
|
||||
self.pmon.add_process_listener(l)
|
||||
|
||||
def test_kill_process(self):
|
||||
from roslaunch.core import RLException
|
||||
pmon = self.pmon
|
||||
|
||||
# should return False
|
||||
self.failIf(pmon.kill_process('foo'))
|
||||
|
||||
p1 = ProcessMock('foo', 'name1', [], {})
|
||||
p2 = ProcessMock('bar', 'name2', [], {})
|
||||
pmon.register(p1)
|
||||
pmon.register(p2)
|
||||
self.failIf(p1.stopped)
|
||||
self.failIf(p2.stopped)
|
||||
self.assert_(p1.name in pmon.get_active_names())
|
||||
self.assert_(p2.name in pmon.get_active_names())
|
||||
|
||||
# should fail as pmon API is string-based
|
||||
try:
|
||||
self.assert_(pmon.kill_process(p1))
|
||||
self.fail("kill_process should have thrown RLException")
|
||||
except RLException: pass
|
||||
|
||||
self.assert_(pmon.kill_process(p1.name))
|
||||
self.assert_(p1.stopped)
|
||||
|
||||
# - pmon should not have removed yet as the pmon thread cannot catch the death
|
||||
self.assert_(pmon.has_process(p1.name))
|
||||
self.assert_(p1.name in pmon.get_active_names())
|
||||
|
||||
self.failIf(p2.stopped)
|
||||
self.assert_(p2.name in pmon.get_active_names())
|
||||
pmon.kill_process(p2.name)
|
||||
self.assert_(p2.stopped)
|
||||
|
||||
# - pmon should not have removed yet as the pmon thread cannot catch the death
|
||||
self.assert_(pmon.has_process(p2.name))
|
||||
self.assert_(p2.name in pmon.get_active_names())
|
||||
|
||||
p3 = ProcessMock('bar', 'name3', [], {})
|
||||
def bad(x):
|
||||
raise Exception("ha ha ha")
|
||||
p3.stop = bad
|
||||
pmon.register(p3)
|
||||
# make sure kill_process is safe
|
||||
pmon.kill_process(p3.name)
|
||||
def f():
|
||||
return False
|
||||
|
||||
p1.is_alive = f
|
||||
p2.is_alive = f
|
||||
p3.is_alive = f
|
||||
|
||||
# Now that we've 'killed' all the processes, we should be able
|
||||
# to run through the ProcessMonitor run loop and it should
|
||||
# exit. But first, important that we check that pmon has no
|
||||
# other extra state in it
|
||||
self.assertEquals(3, len(pmon.get_active_names()))
|
||||
|
||||
# put pmon into exitable state
|
||||
pmon.registrations_complete()
|
||||
|
||||
# and run it -- but setup a safety timer to kill it if it doesn't exit
|
||||
marker = Marker()
|
||||
t = threading.Thread(target=kill_pmon, args=(pmon, marker, 10.))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
pmon.run()
|
||||
|
||||
self.failIf(marker.marked, "pmon had to be externally killed")
|
||||
|
||||
|
||||
self.assert_(pmon.done)
|
||||
self.failIf(pmon.has_process(p1.name))
|
||||
self.failIf(pmon.has_process(p2.name))
|
||||
alive, dead = pmon.get_process_names_with_spawn_count()
|
||||
self.failIf(alive)
|
||||
self.assert_((p1.name, p1.spawn_count) in dead)
|
||||
self.assert_((p2.name, p2.spawn_count) in dead)
|
||||
|
||||
|
||||
def test_run(self):
|
||||
# run is really hard to test...
|
||||
pmon = self.pmon
|
||||
|
||||
# put pmon into exitable state
|
||||
pmon.registrations_complete()
|
||||
|
||||
# give the pmon a process that raises an exception when it's
|
||||
# is_alive is checked. this should be marked as a dead process
|
||||
p1 = ProcessMock('bar', 'name1', [], {})
|
||||
def bad():
|
||||
raise Exception('ha ha')
|
||||
p1.is_alive = bad
|
||||
pmon.register(p1)
|
||||
|
||||
# give pmon a well-behaved but dead process
|
||||
p2 = ProcessMock('bar', 'name2', [], {})
|
||||
def f():
|
||||
return False
|
||||
p2.is_alive = f
|
||||
pmon.register(p2)
|
||||
|
||||
# give pmon a process that wants to respawn once
|
||||
p3 = RespawnOnceProcessMock('bar', 'name3', [], {})
|
||||
pmon.register(p3)
|
||||
|
||||
# give pmon a process that wants to respawn once after a delay
|
||||
p4 = RespawnOnceWithDelayProcessMock('bar', 'name4', [], {})
|
||||
pmon.register(p4)
|
||||
|
||||
# test assumptions about pmon's internal data structures
|
||||
# before we begin test
|
||||
self.assert_(p1 in pmon.procs)
|
||||
self.assert_(pmon._registrations_complete)
|
||||
self.failIf(pmon.is_shutdown)
|
||||
|
||||
# and run it -- but setup a safety timer to kill it if it doesn't exit
|
||||
marker = Marker()
|
||||
t = threading.Thread(target=kill_pmon, args=(self.pmon, marker, 10.))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
pmon.run()
|
||||
|
||||
self.failIf(marker.marked, "pmon had to be externally killed")
|
||||
|
||||
self.failIf(p3.spawn_count < 2, "process did not respawn")
|
||||
|
||||
self.failIf(p4.respawn_interval < p4.respawn_delay,
|
||||
"Respawn delay not respected: %s %s" % (p4.respawn_interval,
|
||||
p4.respawn_delay))
|
||||
|
||||
# retest assumptions
|
||||
self.failIf(pmon.procs)
|
||||
self.assert_(pmon.is_shutdown)
|
||||
|
||||
pmon.is_shutdown = False
|
||||
|
||||
def test_get_process_names_with_spawn_count(self):
|
||||
p1 = ProcessMock('foo', 'name1', [], {})
|
||||
p2 = ProcessMock('bar', 'name2', [], {})
|
||||
|
||||
pmon = self.pmon
|
||||
self.assertEquals([[], []], pmon.get_process_names_with_spawn_count())
|
||||
pmon.register(p1)
|
||||
self.assertEquals([[('name1', 0),], []], pmon.get_process_names_with_spawn_count())
|
||||
pmon.register(p2)
|
||||
alive, dead = pmon.get_process_names_with_spawn_count()
|
||||
self.assertEquals([], dead)
|
||||
self.assert_(('name1', 0) in alive)
|
||||
self.assert_(('name2', 0) in alive)
|
||||
|
||||
import random
|
||||
p1.spawn_count = random.randint(1, 10000)
|
||||
p2.spawn_count = random.randint(1, 10000)
|
||||
|
||||
alive, dead = pmon.get_process_names_with_spawn_count()
|
||||
self.assertEquals([], dead)
|
||||
self.assert_((p1.name, p1.spawn_count) in alive)
|
||||
self.assert_((p2.name, p2.spawn_count) in alive)
|
||||
|
||||
#TODO figure out how to test dead_list
|
||||
|
||||
|
||||
## Tests ProcessMonitor.register(), unregister(), has_process(), and get_process()
|
||||
def test_registration(self):
|
||||
from roslaunch.core import RLException
|
||||
from roslaunch.pmon import Process
|
||||
pmon = self.pmon
|
||||
|
||||
p1 = Process('foo', 'name1', [], {})
|
||||
p2 = Process('bar', 'name2', [], {})
|
||||
corep1 = Process('core', 'core1', [], {})
|
||||
corep2 = Process('core', 'core2', [], {})
|
||||
|
||||
pmon.register(p1)
|
||||
self.assert_(pmon.has_process('name1'))
|
||||
self.assertEquals(p1, pmon.get_process('name1'))
|
||||
self.failIf(pmon.has_process('name2'))
|
||||
self.assertEquals(['name1'], pmon.get_active_names())
|
||||
try:
|
||||
pmon.register(Process('foo', p1.name, [], {}))
|
||||
self.fail("should not allow duplicate process name")
|
||||
except RLException: pass
|
||||
|
||||
pmon.register(p2)
|
||||
self.assert_(pmon.has_process('name2'))
|
||||
self.assertEquals(p2, pmon.get_process('name2'))
|
||||
self.assertEquals(set(['name1', 'name2']), set(pmon.get_active_names()))
|
||||
|
||||
pmon.register_core_proc(corep1)
|
||||
self.assert_(pmon.has_process('core1'))
|
||||
self.assertEquals(corep1, pmon.get_process('core1'))
|
||||
self.assertEquals(set(['name1', 'name2', 'core1']), set(pmon.get_active_names()))
|
||||
|
||||
pmon.register_core_proc(corep2)
|
||||
self.assert_(pmon.has_process('core2'))
|
||||
self.assertEquals(corep2, pmon.get_process('core2'))
|
||||
self.assertEquals(set(['name1', 'name2', 'core1', 'core2']), set(pmon.get_active_names()))
|
||||
|
||||
|
||||
pmon.unregister(p2)
|
||||
self.failIf(pmon.has_process('name2'))
|
||||
pmon.unregister(p1)
|
||||
self.failIf(pmon.has_process('name1'))
|
||||
pmon.unregister(corep1)
|
||||
self.failIf(pmon.has_process('core1'))
|
||||
pmon.unregister(corep2)
|
||||
self.failIf(pmon.has_process('core2'))
|
||||
|
||||
pmon.shutdown()
|
||||
try:
|
||||
pmon.register(Process('shutdown_fail', 'shutdown_fail', [], {}))
|
||||
self.fail("registration should fail post-shutdown")
|
||||
except RLException: pass
|
||||
|
||||
|
||||
|
||||
def test_mainthread_spin_once(self):
|
||||
# shouldn't do anything
|
||||
self.pmon.done = False
|
||||
self.pmon.mainthread_spin_once()
|
||||
self.pmon.done = True
|
||||
self.pmon.mainthread_spin_once()
|
||||
|
||||
def test_mainthread_spin(self):
|
||||
# can't test actual spin as that would go forever
|
||||
self.pmon.done = False
|
||||
t = threading.Thread(target=kill_pmon, args=(self.pmon, Marker()))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
self.pmon.mainthread_spin()
|
||||
|
||||
def kill_pmon(pmon, marker, delay=1.0):
|
||||
# delay execution so that whatever pmon method we're calling has time to enter
|
||||
time.sleep(delay)
|
||||
if not pmon.is_shutdown:
|
||||
marker.mark()
|
||||
print("stopping pmon")
|
||||
# pmon has two states that need to be set, as many of the tests do not start the actual process monitor
|
||||
pmon.shutdown()
|
||||
pmon.done = True
|
||||
146
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_remote.py
vendored
Normal file
146
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_remote.py
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
# 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 unittest
|
||||
|
||||
import roslaunch.core
|
||||
import roslaunch.remote
|
||||
|
||||
## Unit tests for roslaunch.remote
|
||||
class TestRoslaunchRemote(unittest.TestCase):
|
||||
|
||||
def test_remote_node_xml(self):
|
||||
# these are fairly brittle tests, but need to make sure there aren't regressions here
|
||||
Node = roslaunch.core.Node
|
||||
n = Node('pkg1', 'type1')
|
||||
self.assertEquals('<node pkg="pkg1" type="type1" ns="/" args="" respawn="False" respawn_delay="0.0" required="False">\n</node>', n.to_remote_xml())
|
||||
n = Node('pkg2', 'type2', namespace="/ns2/")
|
||||
self.assertEquals('<node pkg="pkg2" type="type2" ns="/ns2/" args="" respawn="False" respawn_delay="0.0" required="False">\n</node>', n.to_remote_xml())
|
||||
# machine_name should be a noop for remote xml
|
||||
n = Node('pkg3', 'type3', namespace="/ns3/", machine_name="machine3")
|
||||
self.assertEquals('<node pkg="pkg3" type="type3" ns="/ns3/" args="" respawn="False" respawn_delay="0.0" required="False">\n</node>', n.to_remote_xml())
|
||||
|
||||
# test args
|
||||
n = Node('pkg4', 'type4', args="arg4a arg4b")
|
||||
self.assertEquals('<node pkg="pkg4" type="type4" ns="/" args="arg4a arg4b" respawn="False" respawn_delay="0.0" required="False">\n</node>', n.to_remote_xml())
|
||||
# test respawn
|
||||
n = Node('pkg5', 'type5', respawn=True)
|
||||
self.assertEquals('<node pkg="pkg5" type="type5" ns="/" args="" respawn="True" respawn_delay="0.0" required="False">\n</node>', n.to_remote_xml())
|
||||
n = Node('pkg5', 'type5', respawn=True, respawn_delay=1.0)
|
||||
self.assertEquals('<node pkg="pkg5" type="type5" ns="/" args="" respawn="True" respawn_delay="1.0" required="False">\n</node>', n.to_remote_xml())
|
||||
n = Node('pkg6', 'type6', respawn=False)
|
||||
self.assertEquals('<node pkg="pkg6" type="type6" ns="/" args="" respawn="False" respawn_delay="0.0" required="False">\n</node>', n.to_remote_xml())
|
||||
# test remap_args
|
||||
n = Node('pkg6', 'type6', remap_args=[('from6a', 'to6a'), ('from6b', 'to6b')])
|
||||
self.assertEquals("""<node pkg="pkg6" type="type6" ns="/" args="" respawn="False" respawn_delay="0.0" required="False">
|
||||
<remap from="from6a" to="to6a" />
|
||||
<remap from="from6b" to="to6b" />
|
||||
</node>""", n.to_remote_xml())
|
||||
# test env args
|
||||
n = Node('pkg7', 'type7', env_args=[('key7a', 'val7a'), ('key7b', 'val7b')])
|
||||
self.assertEquals("""<node pkg="pkg7" type="type7" ns="/" args="" respawn="False" respawn_delay="0.0" required="False">
|
||||
<env name="key7a" value="val7a" />
|
||||
<env name="key7b" value="val7b" />
|
||||
</node>""", n.to_remote_xml())
|
||||
# test cwd
|
||||
n = Node('pkg8', 'type8', cwd='ROS_HOME')
|
||||
self.assertEquals('<node pkg="pkg8" type="type8" ns="/" args="" cwd="ROS_HOME" respawn="False" respawn_delay="0.0" required="False">\n</node>', n.to_remote_xml())
|
||||
n = Node('pkg9', 'type9', cwd='node')
|
||||
self.assertEquals('<node pkg="pkg9" type="type9" ns="/" args="" cwd="node" respawn="False" respawn_delay="0.0" required="False">\n</node>', n.to_remote_xml())
|
||||
# test output
|
||||
n = Node('pkg10', 'type10', output='screen')
|
||||
self.assertEquals('<node pkg="pkg10" type="type10" ns="/" args="" output="screen" respawn="False" respawn_delay="0.0" required="False">\n</node>', n.to_remote_xml())
|
||||
n = Node('pkg11', 'type11', output='log')
|
||||
self.assertEquals('<node pkg="pkg11" type="type11" ns="/" args="" output="log" respawn="False" respawn_delay="0.0" required="False">\n</node>', n.to_remote_xml())
|
||||
|
||||
# test launch-prefix
|
||||
n = Node('pkg12', 'type12', launch_prefix='xterm -e')
|
||||
self.assertEquals('<node pkg="pkg12" type="type12" ns="/" args="" respawn="False" respawn_delay="0.0" launch-prefix="xterm -e" required="False">\n</node>', n.to_remote_xml())
|
||||
|
||||
# test required
|
||||
n = Node('pkg13', 'type13', required=True)
|
||||
self.assertEquals('<node pkg="pkg13" type="type13" ns="/" args="" respawn="False" respawn_delay="0.0" required="True">\n</node>', n.to_remote_xml())
|
||||
|
||||
#test everything
|
||||
n = Node('pkg20', 'type20', namespace="/ns20/", machine_name="foo", remap_args=[('from20a', 'to20a'), ('from20b', 'to20b')], env_args=[('key20a', 'val20a'), ('key20b', 'val20b')], output="screen", cwd="ROS_HOME", respawn=True, args="arg20a arg20b", launch_prefix="nice", required=False)
|
||||
self.assertEquals("""<node pkg="pkg20" type="type20" ns="/ns20/" args="arg20a arg20b" output="screen" cwd="ROS_HOME" respawn="True" respawn_delay="0.0" launch-prefix="nice" required="False">
|
||||
<remap from="from20a" to="to20a" />
|
||||
<remap from="from20b" to="to20b" />
|
||||
<env name="key20a" value="val20a" />
|
||||
<env name="key20b" value="val20b" />
|
||||
</node>""", n.to_remote_xml())
|
||||
|
||||
def test_remote_test_node_xml(self):
|
||||
Test = roslaunch.core.Test
|
||||
#TODO: will certainly fail right now
|
||||
# these are fairly brittle tests, but need to make sure there aren't regressions here
|
||||
Test = roslaunch.core.Test
|
||||
n = Test('test1', 'pkg1', 'type1')
|
||||
self.assertEquals('<test pkg="pkg1" type="type1" ns="/" args="" output="log" required="False" test-name="test1">\n</test>', n.to_remote_xml())
|
||||
n = Test('test2', 'pkg2', 'type2', namespace="/ns2/")
|
||||
self.assertEquals('<test pkg="pkg2" type="type2" ns="/ns2/" args="" output="log" required="False" test-name="test2">\n</test>', n.to_remote_xml())
|
||||
# machine_name should be a noop for remote xml
|
||||
n = Test('test3', 'pkg3', 'type3', namespace="/ns3/", machine_name="machine3")
|
||||
self.assertEquals('<test pkg="pkg3" type="type3" ns="/ns3/" args="" output="log" required="False" test-name="test3">\n</test>', n.to_remote_xml())
|
||||
|
||||
# test args
|
||||
n = Test('test4', 'pkg4', 'type4', args="arg4a arg4b")
|
||||
self.assertEquals('<test pkg="pkg4" type="type4" ns="/" args="arg4a arg4b" output="log" required="False" test-name="test4">\n</test>', n.to_remote_xml())
|
||||
# test remap_args
|
||||
n = Test('test6', 'pkg6', 'type6', remap_args=[('from6a', 'to6a'), ('from6b', 'to6b')])
|
||||
self.assertEquals("""<test pkg="pkg6" type="type6" ns="/" args="" output="log" required="False" test-name="test6">
|
||||
<remap from="from6a" to="to6a" />
|
||||
<remap from="from6b" to="to6b" />
|
||||
</test>""", n.to_remote_xml())
|
||||
# test env args
|
||||
n = Test('test7', 'pkg7', 'type7', env_args=[('key7a', 'val7a'), ('key7b', 'val7b')])
|
||||
self.assertEquals("""<test pkg="pkg7" type="type7" ns="/" args="" output="log" required="False" test-name="test7">
|
||||
<env name="key7a" value="val7a" />
|
||||
<env name="key7b" value="val7b" />
|
||||
</test>""", n.to_remote_xml())
|
||||
# test cwd
|
||||
n = Test('test8', 'pkg8', 'type8', cwd='ROS_HOME')
|
||||
self.assertEquals('<test pkg="pkg8" type="type8" ns="/" args="" output="log" cwd="ROS_HOME" required="False" test-name="test8">\n</test>', n.to_remote_xml())
|
||||
n = Test('test9', 'pkg9', 'type9', cwd='node')
|
||||
self.assertEquals('<test pkg="pkg9" type="type9" ns="/" args="" output="log" cwd="node" required="False" test-name="test9">\n</test>', n.to_remote_xml())
|
||||
|
||||
#test everything
|
||||
n = Test('test20', 'pkg20', 'type20', namespace="/ns20/", machine_name="foo", remap_args=[('from20a', 'to20a'), ('from20b', 'to20b')], env_args=[('key20a', 'val20a'), ('key20b', 'val20b')], cwd="ROS_HOME", args="arg20a arg20b")
|
||||
self.assertEquals("""<test pkg="pkg20" type="type20" ns="/ns20/" args="arg20a arg20b" output="log" cwd="ROS_HOME" required="False" test-name="test20">
|
||||
<remap from="from20a" to="to20a" />
|
||||
<remap from="from20b" to="to20b" />
|
||||
<env name="key20a" value="val20a" />
|
||||
<env name="key20b" value="val20b" />
|
||||
</test>""", n.to_remote_xml())
|
||||
|
||||
91
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_rlutil.py
vendored
Normal file
91
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_rlutil.py
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/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.
|
||||
#
|
||||
# Revision $Id: roslaunch_node_args.py 5229 2009-07-16 22:31:17Z sfkwc $
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import roslaunch
|
||||
import roslaunch.rlutil
|
||||
|
||||
def get_test_path():
|
||||
# two directories up from here
|
||||
return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
# path to example.launch directory
|
||||
def get_example_path():
|
||||
return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
|
||||
|
||||
## Test roslaunch.node_args
|
||||
class TestRoslaunchRlutil(unittest.TestCase):
|
||||
|
||||
def test_resolve_launch_arguments(self):
|
||||
from roslaunch.rlutil import resolve_launch_arguments
|
||||
|
||||
roslaunch_dir = get_test_path()
|
||||
example_xml_p = os.path.join(get_example_path(), 'example.launch')
|
||||
tests = [
|
||||
([], []),
|
||||
(['roslaunch', 'example.launch'], [example_xml_p]),
|
||||
([example_xml_p], [example_xml_p]),
|
||||
|
||||
(['roslaunch', 'example.launch', 'foo', 'bar'], [example_xml_p, 'foo', 'bar']),
|
||||
([example_xml_p, 'foo', 'bar'], [example_xml_p,'foo', 'bar']),
|
||||
|
||||
]
|
||||
bad = [
|
||||
['does_not_exist'],
|
||||
['does_not_exist', 'foo.launch'],
|
||||
['roslaunch', 'does_not_exist.launch'],
|
||||
]
|
||||
|
||||
for test, result in tests:
|
||||
for v1, v2 in zip(result, resolve_launch_arguments(test)):
|
||||
# workaround for nfs
|
||||
if os.path.exists(v1):
|
||||
self.assert_(os.path.samefile(v1, v2))
|
||||
else:
|
||||
self.assertEquals(v1, v2)
|
||||
for test in bad:
|
||||
try:
|
||||
resolve_launch_arguments(test)
|
||||
self.fail("should have failed")
|
||||
except roslaunch.RLException:
|
||||
pass
|
||||
|
||||
def test_roslaunch_check_pass_all_args(self):
|
||||
filename = os.path.join(get_example_path(), 'example-pass_all_args.launch')
|
||||
error_msg = roslaunch.rlutil.check_roslaunch(filename)
|
||||
assert error_msg is None
|
||||
482
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_server.py
vendored
Normal file
482
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_roslaunch_server.py
vendored
Normal file
@@ -0,0 +1,482 @@
|
||||
# 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 unittest
|
||||
import time
|
||||
|
||||
import roslaunch.pmon
|
||||
import roslaunch.server
|
||||
from roslaunch.server import ProcessListener
|
||||
|
||||
try:
|
||||
from xmlrpc.client import ServerProxy
|
||||
except ImportError:
|
||||
from xmlrpclib import ServerProxy
|
||||
|
||||
import rosgraph
|
||||
master = rosgraph.Master('test_roslaunch_server')
|
||||
def get_param(*args):
|
||||
return master.getParam(*args)
|
||||
|
||||
class MockProcessListener(ProcessListener):
|
||||
def process_died(self, name, code):
|
||||
self.process_name = name
|
||||
self.exit_code = code
|
||||
|
||||
## Fake Process object
|
||||
class ProcessMock(roslaunch.pmon.Process):
|
||||
def __init__(self, package, name, args, env, respawn=False):
|
||||
super(ProcessMock, self).__init__(package, name, args, env, respawn)
|
||||
self.stopped = False
|
||||
def stop(self):
|
||||
self.stopped = True
|
||||
|
||||
## Fake ProcessMonitor object
|
||||
class ProcessMonitorMock(object):
|
||||
def __init__(self):
|
||||
self.core_procs = []
|
||||
self.procs = []
|
||||
self.listeners = []
|
||||
self.is_shutdown = False
|
||||
|
||||
def join(self, timeout=0):
|
||||
pass
|
||||
|
||||
def add_process_listener(self, l):
|
||||
self.listeners.append(l)
|
||||
|
||||
def register(self, p):
|
||||
self.procs.append(p)
|
||||
|
||||
def register_core_proc(self, p):
|
||||
self.core_procs.append(p)
|
||||
|
||||
def registrations_complete(self):
|
||||
pass
|
||||
|
||||
def unregister(self, p):
|
||||
self.procs.remove(p)
|
||||
|
||||
def has_process(self, name):
|
||||
return len([p for p in self.procs if p.name == name]) > 0
|
||||
|
||||
def get_process(self, name):
|
||||
val = [p for p in self.procs if p.name == name]
|
||||
if val:
|
||||
return val[0]
|
||||
return None
|
||||
|
||||
def has_main_thread_jobs(self):
|
||||
return False
|
||||
|
||||
def do_main_thread_jobs(self):
|
||||
pass
|
||||
|
||||
def kill_process(self, name):
|
||||
pass
|
||||
|
||||
def shutdown(self):
|
||||
self.is_shutdown = True
|
||||
|
||||
def get_active_names(self):
|
||||
return [p.name for p in self.procs]
|
||||
|
||||
def get_process_names_with_spawn_count(self):
|
||||
actives = [(p.name, p.spawn_count) for p in self.procs]
|
||||
deads = []
|
||||
return [actives, deads]
|
||||
|
||||
def mainthread_spin_once(self):
|
||||
pass
|
||||
|
||||
def mainthread_spin(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
class TestHandler(roslaunch.server.ROSLaunchBaseHandler):
|
||||
def __init__(self, pm):
|
||||
super(TestHandler, self).__init__(pm)
|
||||
self.pinged = None
|
||||
def ping(self, val):
|
||||
self.pinged = val
|
||||
return True
|
||||
|
||||
## Test roslaunch.server
|
||||
class TestRoslaunchServer(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.pmon = ProcessMonitorMock()
|
||||
roslaunch.core.clear_printlog_handlers()
|
||||
roslaunch.core.clear_printerrlog_handlers()
|
||||
|
||||
def test_ChildRoslaunchProcess(self):
|
||||
# test that constructor is wired up correctly
|
||||
from roslaunch.server import ChildROSLaunchProcess
|
||||
name = 'foo-%s'%time.time()
|
||||
args = [time.time(), time.time()]
|
||||
env = { 'key-%s'%time.time() : str(time.time()) }
|
||||
cp = ChildROSLaunchProcess(name, args, env)
|
||||
self.assertEquals(name, cp.name)
|
||||
self.assertEquals(args, cp.args)
|
||||
self.assertEquals(env, cp.env)
|
||||
self.assertEquals(None, cp.uri)
|
||||
|
||||
uri = 'http://foo:1234'
|
||||
cp.set_uri(uri)
|
||||
self.assertEquals(uri, cp.uri)
|
||||
|
||||
def _succeed(self, retval):
|
||||
code, msg, val = retval
|
||||
self.assertEquals(1, code)
|
||||
self.assert_(type(msg) == str)
|
||||
return val
|
||||
|
||||
def test_ROSLaunchBaseHandler(self):
|
||||
from roslaunch.server import ROSLaunchBaseHandler
|
||||
|
||||
try:
|
||||
ROSLaunchBaseHandler(None)
|
||||
self.fail("should not allow pm as None")
|
||||
except: pass
|
||||
|
||||
pmon = self.pmon
|
||||
h = ROSLaunchBaseHandler(pmon)
|
||||
self._test_ROSLaunchBaseHandler(h)
|
||||
|
||||
# reusable parent class test
|
||||
def _test_ROSLaunchBaseHandler(self, h):
|
||||
pmon = self.pmon
|
||||
# - test get pid
|
||||
self.assertEquals(os.getpid(), self._succeed(h.get_pid()))
|
||||
|
||||
# - test list processes
|
||||
process_list = self._succeed(h.list_processes())
|
||||
self.assertEquals([[], []], process_list)
|
||||
|
||||
p = ProcessMock('pack', 'name', [], {})
|
||||
p.spawn_count = 1
|
||||
pmon.register(p)
|
||||
|
||||
process_list = self._succeed(h.list_processes())
|
||||
self.assertEquals([('name', 1),], process_list[0])
|
||||
self.assertEquals([], process_list[1])
|
||||
|
||||
p.spawn_count = 2
|
||||
process_list = self._succeed(h.list_processes())
|
||||
self.assertEquals([('name', 2),], process_list[0])
|
||||
self.assertEquals([], process_list[1])
|
||||
# - cleanup our work
|
||||
pmon.unregister(p)
|
||||
|
||||
# - test process_info
|
||||
code, msg, val = h.process_info('fubar')
|
||||
self.assertEquals(-1, code)
|
||||
self.assert_(type(msg) == str)
|
||||
self.assertEquals({}, val)
|
||||
|
||||
pmon.register(p)
|
||||
self.assertEquals(p.get_info(), self._succeed(h.process_info(p.name)))
|
||||
pmon.unregister(p)
|
||||
|
||||
# - test get_node_names
|
||||
# - reach into instance to get branch-complete
|
||||
h.pm = None
|
||||
code, msg, val = h.get_node_names()
|
||||
self.assertEquals(0, code)
|
||||
self.assert_(type(msg) == str)
|
||||
self.assertEquals([], val)
|
||||
h.pm = pmon
|
||||
|
||||
self.assertEquals(pmon.get_active_names(), self._succeed(h.get_node_names()))
|
||||
pmon.register(p)
|
||||
self.assertEquals(pmon.get_active_names(), self._succeed(h.get_node_names()))
|
||||
pmon.unregister(p)
|
||||
|
||||
def test_ROSLaunchParentHandler(self):
|
||||
from roslaunch.server import ROSLaunchParentHandler
|
||||
from roslaunch.server import ChildROSLaunchProcess
|
||||
try:
|
||||
ROSLaunchParentHandler(None, {}, [])
|
||||
self.fail("should not allow pm as None")
|
||||
except: pass
|
||||
|
||||
pmon = self.pmon
|
||||
child_processes = {}
|
||||
listeners = []
|
||||
h = ROSLaunchParentHandler(pmon, child_processes, listeners)
|
||||
self.assertEquals(child_processes, h.child_processes)
|
||||
self.assertEquals(listeners, h.listeners)
|
||||
self._test_ROSLaunchBaseHandler(h)
|
||||
|
||||
from rosgraph_msgs.msg import Log
|
||||
h.log('client-1', Log.FATAL, "message")
|
||||
h.log('client-1', Log.ERROR, "message")
|
||||
h.log('client-1', Log.DEBUG, "message")
|
||||
h.log('client-1', Log.INFO, "started with pid 1234")
|
||||
|
||||
# test process_died
|
||||
# - no listeners
|
||||
self._succeed(h.process_died('dead1', -1))
|
||||
# - well-behaved listener
|
||||
l = roslaunch.pmon.ProcessListener()
|
||||
listeners.append(l)
|
||||
self._succeed(h.process_died('dead2', -1))
|
||||
# - bad listener with exception
|
||||
def bad():
|
||||
raise Exception("haha")
|
||||
l.process_died = bad
|
||||
self._succeed(h.process_died('dead3', -1))
|
||||
|
||||
# test register
|
||||
|
||||
# - verify clean slate with list_children
|
||||
self.assertEquals([], self._succeed(h.list_children()))
|
||||
|
||||
# - first register with unknown
|
||||
code, msg, val = h.register('client-unknown', 'http://unroutable:1234')
|
||||
self.assertEquals(-1, code)
|
||||
self.assertEquals([], self._succeed(h.list_children()))
|
||||
|
||||
# - now register with known
|
||||
uri = 'http://unroutable:1324'
|
||||
child_processes['client-1'] = ChildROSLaunchProcess('foo', [], {})
|
||||
val = self._succeed(h.register('client-1', uri))
|
||||
self.assert_(type(val) == int)
|
||||
self.assertEquals([uri], self._succeed(h.list_children()))
|
||||
|
||||
def test_ROSLaunchChildHandler(self):
|
||||
from roslaunch.server import ROSLaunchChildHandler
|
||||
pmon = self.pmon
|
||||
try:
|
||||
# if there is a core up, we have to use its run id
|
||||
run_id = get_param('/run_id')
|
||||
except:
|
||||
run_id = 'foo-%s'%time.time()
|
||||
name = 'foo-bob'
|
||||
server_uri = 'http://localhost:12345'
|
||||
try:
|
||||
h = ROSLaunchChildHandler(run_id, name, server_uri, None)
|
||||
self.fail("should not allow pm as None")
|
||||
except: pass
|
||||
try:
|
||||
h = ROSLaunchChildHandler(run_id, name, 'http://bad_uri:0', pmon)
|
||||
self.fail("should not allow bad uri")
|
||||
except: pass
|
||||
try:
|
||||
h = ROSLaunchChildHandler(run_id, name, None, pmon)
|
||||
self.fail("should not allow None server_uri")
|
||||
except: pass
|
||||
|
||||
h = ROSLaunchChildHandler(run_id, name, server_uri, pmon)
|
||||
self.assertEquals(run_id, h.run_id)
|
||||
self.assertEquals(name, h.name)
|
||||
self.assertEquals(server_uri, h.server_uri)
|
||||
self._test_ROSLaunchBaseHandler(h)
|
||||
|
||||
# test _log()
|
||||
from rosgraph_msgs.msg import Log
|
||||
h._log(Log.INFO, 'hello')
|
||||
|
||||
# test shutdown()
|
||||
# should uninitialize pm
|
||||
h.shutdown()
|
||||
self.assert_(pmon.is_shutdown)
|
||||
# - this check is mostly to make sure that the launch() call below will exit
|
||||
self.assert_(h.pm is None)
|
||||
code, msg, val = h.launch('<launch></launch>')
|
||||
self.assertEquals(0, code)
|
||||
|
||||
# TODO: actual launch. more difficult as we need a core
|
||||
|
||||
def test__ProcessListenerForwarder(self):
|
||||
from roslaunch.server import _ProcessListenerForwarder, ProcessListener
|
||||
|
||||
# test with bad logic first
|
||||
f = _ProcessListenerForwarder(None)
|
||||
# - should trap exceptions
|
||||
f.process_died("foo", -1)
|
||||
# test with actual listener
|
||||
l = MockProcessListener()
|
||||
f = _ProcessListenerForwarder(l)
|
||||
# - should run normally
|
||||
f.process_died("foo", -1)
|
||||
|
||||
self.assertEquals(l.process_name, 'foo')
|
||||
self.assertEquals(l.exit_code, -1)
|
||||
|
||||
def test_ROSLaunchNode(self):
|
||||
#exercise the basic ROSLaunchNode API
|
||||
from roslaunch.server import ROSLaunchNode
|
||||
|
||||
# - create a node with a handler
|
||||
handler = TestHandler(self.pmon)
|
||||
node = ROSLaunchNode(handler)
|
||||
|
||||
# - start the node
|
||||
node.start()
|
||||
self.assert_(node.uri)
|
||||
|
||||
# - call the ping API that we added
|
||||
s = ServerProxy(node.uri)
|
||||
test_val = 'test-%s'%time.time()
|
||||
s.ping(test_val)
|
||||
self.assertEquals(handler.pinged, test_val)
|
||||
|
||||
# - call the pid API
|
||||
code, msg, pid = s.get_pid()
|
||||
self.assertEquals(1, code)
|
||||
self.assert_(type(msg) == str)
|
||||
self.assertEquals(os.getpid(), pid)
|
||||
|
||||
# - shut it down
|
||||
node.shutdown('test done')
|
||||
|
||||
def test_ROSLaunchParentNode(self):
|
||||
from roslaunch.server import ROSLaunchParentNode
|
||||
from roslaunch.server import ChildROSLaunchProcess
|
||||
from roslaunch.config import ROSLaunchConfig
|
||||
from roslaunch.pmon import ProcessListener
|
||||
rosconfig = ROSLaunchConfig()
|
||||
try:
|
||||
ROSLaunchParentNode(rosconfig, None)
|
||||
self.fail("should not allow pm as None")
|
||||
except: pass
|
||||
pmon = self.pmon
|
||||
n = ROSLaunchParentNode(rosconfig, pmon)
|
||||
self.assertEquals(rosconfig, n.rosconfig)
|
||||
self.assertEquals([], n.listeners)
|
||||
self.assertEquals({}, n.child_processes)
|
||||
self.assertEquals(n.handler.listeners, n.listeners)
|
||||
self.assertEquals(n.handler.child_processes, n.child_processes)
|
||||
|
||||
# test add listener
|
||||
self.assertEquals(n.handler.listeners, n.listeners)
|
||||
l = ProcessListener()
|
||||
n.add_process_listener(l)
|
||||
self.assertEquals([l], n.listeners)
|
||||
self.assertEquals(n.handler.listeners, n.listeners)
|
||||
|
||||
# now, lets make some xmlrpc calls against it
|
||||
import roslaunch.config
|
||||
server = roslaunch.server.ROSLaunchParentNode(roslaunch.config.ROSLaunchConfig(), self.pmon)
|
||||
|
||||
# it's really dangerous for logging when both a parent and a
|
||||
# child are in the same process, so out of paranoia, clear the
|
||||
# logging handlers
|
||||
roslaunch.core.clear_printlog_handlers()
|
||||
roslaunch.core.clear_printerrlog_handlers()
|
||||
|
||||
# - register a fake child with the server so that it accepts registration from ROSLaunchChild
|
||||
child_name = 'child-%s'%time.time()
|
||||
child_proc = ChildROSLaunchProcess('foo', [], {})
|
||||
server.add_child(child_name, child_proc)
|
||||
|
||||
try:
|
||||
server.start()
|
||||
self.assert_(server.uri, "server URI did not initialize")
|
||||
s = ServerProxy(server.uri)
|
||||
child_uri = 'http://fake-unroutable:1324'
|
||||
# - list children should be empty
|
||||
val = self._succeed(s.list_children())
|
||||
self.assertEquals([], val)
|
||||
# - register
|
||||
val = self._succeed(s.register(child_name, child_uri))
|
||||
self.assertEquals(1, val)
|
||||
# - list children
|
||||
val = self._succeed(s.list_children())
|
||||
self.assertEquals([child_uri], val)
|
||||
finally:
|
||||
server.shutdown('test done')
|
||||
|
||||
|
||||
|
||||
def test_ROSLaunchChildNode(self):
|
||||
from roslaunch.server import ROSLaunchChildNode
|
||||
from roslaunch.server import ChildROSLaunchProcess
|
||||
pmon = self.pmon
|
||||
try:
|
||||
# if there is a core up, we have to use its run id
|
||||
run_id = get_param('/run_id')
|
||||
except:
|
||||
run_id = 'foo-%s'%time.time()
|
||||
name = 'foo-bob'
|
||||
server_uri = 'http://localhost:12345'
|
||||
try:
|
||||
ROSLaunchChildNode(run_id, name, server_uri, None)
|
||||
self.fail("should not allow pm as None")
|
||||
except: pass
|
||||
try:
|
||||
ROSLaunchChildNode(run_id, name, 'http://bad_uri:0', pmon)
|
||||
self.fail("should not allow bad uri")
|
||||
except: pass
|
||||
|
||||
n = ROSLaunchChildNode(run_id, name, server_uri, pmon)
|
||||
self.assertEquals(run_id, n.run_id)
|
||||
self.assertEquals(name, n.name)
|
||||
self.assertEquals(server_uri, n.server_uri)
|
||||
|
||||
# tests for actual registration with server
|
||||
import roslaunch.config
|
||||
server = roslaunch.server.ROSLaunchParentNode(roslaunch.config.ROSLaunchConfig(), self.pmon)
|
||||
# - register a fake child with the server so that it accepts registration from ROSLaunchChild
|
||||
child_proc = ChildROSLaunchProcess('foo', [], {})
|
||||
server.add_child(name, child_proc)
|
||||
|
||||
try:
|
||||
server.start()
|
||||
self.assert_(server.uri, "server URI did not initialize")
|
||||
s = ServerProxy(server.uri)
|
||||
|
||||
print("SERVER STARTED")
|
||||
|
||||
# start the child
|
||||
n = ROSLaunchChildNode(run_id, name, server.uri, pmon)
|
||||
n.start()
|
||||
print("CHILD STARTED")
|
||||
self.assert_(n.uri, "child URI did not initialize")
|
||||
|
||||
# verify registration
|
||||
print("VERIFYING REGISTRATION")
|
||||
self.assertEquals(child_proc.uri, n.uri)
|
||||
child_uri = 'http://fake-unroutable:1324'
|
||||
# - list children
|
||||
val = self._succeed(s.list_children())
|
||||
self.assertEquals([n.uri], val)
|
||||
finally:
|
||||
print("SHUTTING DOWN")
|
||||
n.shutdown('test done')
|
||||
server.shutdown('test done')
|
||||
|
||||
199
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_substitution_args.py
vendored
Normal file
199
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_substitution_args.py
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
# 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 rospkg
|
||||
|
||||
def test__arg():
|
||||
import random
|
||||
from roslaunch.substitution_args import _arg, ArgException, SubstitutionException
|
||||
|
||||
ctx = { 'arg': {
|
||||
'foo': '12345',
|
||||
'bar': 'hello world',
|
||||
'baz': 'sim',
|
||||
'empty': '',
|
||||
}
|
||||
}
|
||||
|
||||
# test invalid
|
||||
try:
|
||||
_arg('$(arg)', 'arg', [], ctx)
|
||||
assert False, "should have thrown"
|
||||
except SubstitutionException:
|
||||
pass
|
||||
|
||||
# test normal
|
||||
tests = [
|
||||
('12345', ('$(arg foo)', 'arg foo', ['foo'], ctx)),
|
||||
('', ('$(arg empty)', 'arg empty', ['empty'], ctx)),
|
||||
('sim', ('$(arg baz)', 'arg baz', ['baz'], ctx)),
|
||||
|
||||
# test with other args present, should only resolve match
|
||||
('1234512345', ('$(arg foo)$(arg foo)', 'arg foo', ['foo'], ctx)),
|
||||
('12345$(arg baz)', ('$(arg foo)$(arg baz)', 'arg foo', ['foo'], ctx)),
|
||||
('$(arg foo)sim', ('$(arg foo)$(arg baz)', 'arg baz', ['baz'], ctx)),
|
||||
|
||||
# test double-resolve safe
|
||||
('12345', ('12345', 'arg foo', ['foo'], ctx)),
|
||||
]
|
||||
|
||||
for result, test in tests:
|
||||
resolved, a, args, context = test
|
||||
assert result == _arg(resolved, a, args, context)
|
||||
|
||||
# - test that all fail if ctx is not set
|
||||
for result, test in tests:
|
||||
resolved, a, args, context = test
|
||||
try:
|
||||
_arg(resolved, a, args, {})
|
||||
assert False, "should have thrown"
|
||||
except ArgException as e:
|
||||
assert args[0] == str(e)
|
||||
try:
|
||||
_arg(resolved, a, args, {'arg': {}})
|
||||
assert False, "should have thrown"
|
||||
except ArgException as e:
|
||||
assert args[0] == str(e)
|
||||
|
||||
def test_resolve_args():
|
||||
from roslaunch.substitution_args import resolve_args, SubstitutionException
|
||||
|
||||
r = rospkg.RosPack()
|
||||
roslaunch_dir = r.get_path('roslaunch')
|
||||
assert roslaunch_dir
|
||||
|
||||
anon_context = {'foo': 'bar'}
|
||||
arg_context = {'fuga': 'hoge', 'car': 'cdr', 'arg': 'foo', 'True': 'False'}
|
||||
context = {'anon': anon_context, 'arg': arg_context }
|
||||
|
||||
tests = [
|
||||
('$(find roslaunch)', roslaunch_dir),
|
||||
('hello$(find roslaunch)', 'hello'+roslaunch_dir),
|
||||
('$(find roslaunch )', roslaunch_dir),
|
||||
('$$(find roslaunch )', '$'+roslaunch_dir),
|
||||
('$( find roslaunch )', roslaunch_dir),
|
||||
('$(find roslaunch )', roslaunch_dir),
|
||||
('$(find roslaunch)$(find roslaunch)', roslaunch_dir+os.sep+roslaunch_dir),
|
||||
('$(find roslaunch)/foo/bar.xml', roslaunch_dir+os.sep+'foo'+os.sep+'bar.xml'),
|
||||
(r'$(find roslaunch)\foo\bar.xml $(find roslaunch)\bar.xml', roslaunch_dir+os.sep+'foo'+os.sep+'bar.xml '+roslaunch_dir+os.sep+'bar.xml'),
|
||||
('$(find roslaunch)\\foo\\bar.xml more/stuff\\here', roslaunch_dir+os.sep+'foo'+os.sep+'bar.xml more/stuff\\here'),
|
||||
('$(env ROS_ROOT)', os.environ['ROS_ROOT']),
|
||||
('$(env ROS_ROOT)', os.environ['ROS_ROOT']),
|
||||
('$(env ROS_ROOT )', os.environ['ROS_ROOT']),
|
||||
('$(optenv ROS_ROOT)', os.environ['ROS_ROOT']),
|
||||
('$(optenv ROS_ROOT)$(optenv ROS_ROOT)', os.environ['ROS_ROOT']+os.environ['ROS_ROOT']),
|
||||
('$(optenv ROS_ROOT alternate text)', os.environ['ROS_ROOT']),
|
||||
('$(optenv NOT_ROS_ROOT)', ''),
|
||||
('$(optenv NOT_ROS_ROOT)more stuff', 'more stuff'),
|
||||
('$(optenv NOT_ROS_ROOT alternate)', 'alternate'),
|
||||
('$(optenv NOT_ROS_ROOT alternate text)', 'alternate text'),
|
||||
|
||||
# #1776
|
||||
('$(anon foo)', 'bar'),
|
||||
('$(anon foo)/baz', 'bar/baz'),
|
||||
('$(anon foo)/baz/$(anon foo)', 'bar/baz/bar'),
|
||||
|
||||
# arg
|
||||
('$(arg fuga)', 'hoge'),
|
||||
('$(arg fuga)$(arg fuga)', 'hogehoge'),
|
||||
('$(arg car)$(arg fuga)', 'cdrhoge'),
|
||||
('$(arg fuga)hoge', 'hogehoge'),
|
||||
|
||||
# $(eval ...) versions of those tests
|
||||
("$(eval find('roslaunch'))", roslaunch_dir),
|
||||
("$(eval env('ROS_ROOT'))", os.environ['ROS_ROOT']),
|
||||
("$(eval optenv('ROS_ROOT', 'alternate text'))", os.environ['ROS_ROOT']),
|
||||
("$(eval optenv('NOT_ROS_ROOT', 'alternate text'))", "alternate text"),
|
||||
("$(eval optenv('NOT_ROS_ROOT'))", ""),
|
||||
("$(eval anon('foo'))", 'bar'),
|
||||
("$(eval arg('fuga'))", 'hoge'),
|
||||
('$(eval arg("fuga"))', 'hoge'),
|
||||
('$(eval arg("arg"))', 'foo'),
|
||||
('$(eval arg("True"))', 'False'),
|
||||
('$(eval 1==1)', 'True'),
|
||||
('$(eval [0,1,2][1])', '1'),
|
||||
# test implicit arg access
|
||||
('$(eval fuga)', 'hoge'),
|
||||
('$(eval True)', 'True'),
|
||||
# math expressions
|
||||
('$(eval round(sin(pi),1))', '0.0'),
|
||||
('$(eval cos(0))', '1.0'),
|
||||
# str, map
|
||||
("$(eval ''.join(map(str, [4,2])))", '42'),
|
||||
]
|
||||
for arg, val in tests:
|
||||
assert val == resolve_args(arg, context=context), arg
|
||||
|
||||
# more #1776
|
||||
r = resolve_args('$(anon foo)/bar')
|
||||
assert '/bar' in r
|
||||
assert not '$(anon foo)' in r
|
||||
|
||||
|
||||
# test against strings that should not match
|
||||
noop_tests = [
|
||||
'$(find roslaunch', '$find roslaunch', '', ' ', 'noop', 'find roslaunch', 'env ROS_ROOT', '$$', ')', '(', '()',
|
||||
None,
|
||||
]
|
||||
for t in noop_tests:
|
||||
assert t == resolve_args(t)
|
||||
failures = [
|
||||
'$((find roslaunch))', '$(find $roslaunch)',
|
||||
'$(find)', '$(find roslaunch roslaunch)', '$(export roslaunch)',
|
||||
'$(env)', '$(env ROS_ROOT alternate)',
|
||||
'$(env NOT_SET)',
|
||||
'$(optenv)',
|
||||
'$(anon)',
|
||||
'$(anon foo bar)',
|
||||
]
|
||||
for f in failures:
|
||||
try:
|
||||
resolve_args(f)
|
||||
assert False, "resolve_args(%s) should have failed"%f
|
||||
except SubstitutionException: pass
|
||||
|
||||
|
||||
def test_resolve_duplicate_anon():
|
||||
from roslaunch.config import ROSLaunchConfig
|
||||
from roslaunch.core import RLException
|
||||
from roslaunch.xmlloader import XmlLoader
|
||||
loader = XmlLoader()
|
||||
config = ROSLaunchConfig()
|
||||
test_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'xml'))
|
||||
try:
|
||||
loader.load(os.path.join(test_path, 'test-substitution-duplicate-anon-names.xml'), config)
|
||||
assert False, 'loading a launch file with duplicate anon node names should have raised an exception'
|
||||
except RLException:
|
||||
pass
|
||||
1074
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_xmlloader.py
vendored
Normal file
1074
thirdparty/ros/ros_comm/tools/roslaunch/test/unit/test_xmlloader.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user