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

View File

@@ -0,0 +1,2 @@
string1: bar
dict1: { head: 1, shoulders: 2, knees: 3, toes: 4}

View File

@@ -0,0 +1,22 @@
string1: bar
string2: !!str 10
preformattedtext: |
This is the first line
This is the second line
Line breaks are preserved
Indentation is stripped
list1:
- head
- shoulders
- knees
- toes
list2: [1, 1, 2, 3, 5, 8]
dict1: { head: 1, shoulders: 2, knees: 3, toes: 4}
integer1: 1
integer2: 2
float1: 3.14159
float2: 1.2345e+3
robots:
childparam: a child namespace parameter
child:
grandchildparam: a grandchild namespace param

View File

@@ -0,0 +1,3 @@
#
#
#

View File

@@ -0,0 +1 @@
string1: $(anon foo)

View 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('&lt;', _xml_escape('<'))
self.assertEquals('&amp;', _xml_escape('&'))
self.assertEquals('&amp;amp;', _xml_escape('&amp;'))
self.assertEquals('&amp;&quot;&gt;&lt;&quot;', _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))

View 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)

View 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()

View 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>") == "&amp;&lt;foo&gt;"
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

View 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])

View 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))

View 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)

View 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)

View 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])

View 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()

View 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

View 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())

View 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

View 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')

View 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
<blah>

View File

@@ -0,0 +1,4 @@
<launch>
<!-- roslaunch file that loads no nodes, and thus should exit immediately -->
<param name="noop" value="noop" />
</launch>

View File

@@ -0,0 +1 @@
<foo />

View File

@@ -0,0 +1,48 @@
<launch>
<arg name="required" />
<arg name="optional" default="not_set" />
<arg name="grounded" value="parent" />
<arg name="include_arg" value="dontcare" />
<arg name="if_test" value="dontcare" />
<arg name="param1_name" value="p1" />
<arg name="param2_name" value="p2" />
<arg name="param3_name" value="p3" />
<arg name="param1_value" value="$(arg required)" />
<arg name="param2_value" value="$(arg optional)" />
<arg name="param3_value" value="$(arg grounded)" />
<param name="$(arg param1_name)_test" value="$(arg param1_value)" />
<param name="$(arg param2_name)_test" value="$(arg param2_value)" />
<param name="$(arg param3_name)_test" value="$(arg param3_value)" />
<!-- Normal include: explicitly set args -->
<include ns="notall" file="$(find roslaunch)/test/xml/test-arg-include.xml">
<arg name="required" value="$(arg required)" />
<arg name="include_arg" value="$(arg include_arg)" />
<arg name="if_test" value="$(arg if_test)" />
</include>
<!-- Normal include: explicitly set args, including an optional one -->
<include ns="notall_optional" file="$(find roslaunch)/test/xml/test-arg-include.xml">
<arg name="required" value="$(arg required)" />
<arg name="optional" value="$(arg optional)" />
<arg name="include_arg" value="$(arg include_arg)" />
<arg name="if_test" value="$(arg if_test)" />
</include>
<!-- Include with passing in all args in my namespace -->
<include ns="all" file="$(find roslaunch)/test/xml/test-arg-include.xml"
pass_all_args="true">
</include>
<!-- Include with passing in all args in my namespace, and then override one
of them explicitly -->
<include ns="all_override" file="$(find roslaunch)/test/xml/test-arg-include.xml"
pass_all_args="true">
<arg name="required" value="override" />
</include>
</launch>

View File

@@ -0,0 +1,26 @@
<launch>
<arg name="required" />
<arg name="if_test" />
<arg name="include_arg" />
<arg name="optional" default="not_set" />
<arg name="grounded" value="set" />
<arg name="param1_name" value="p1" />
<arg name="param2_name" value="p2" />
<arg name="param3_name" value="p3" />
<arg name="param4_name" value="p4" />
<arg name="param1_value" value="$(arg required)" />
<arg name="param2_value" value="$(arg optional)" />
<arg name="param3_value" value="$(arg grounded)" />
<group ns="include_test">
<param name="$(arg param1_name)_test" value="$(arg param1_value)" />
<param name="$(arg param2_name)_test" value="$(arg param2_value)" />
<param name="$(arg param3_name)_test" value="$(arg param3_value)" />
<param name="$(arg param4_name)_test" value="$(arg include_arg)" />
</group>
</launch>

View File

@@ -0,0 +1,5 @@
<launch>
<include file="$(find roslaunch)/test/xml/test-arg-invalid-included.xml">
<arg name="grounded" value="not_set"/>
</include>
</launch>

View File

@@ -0,0 +1,6 @@
<launch>
<include file="$(find roslaunch)/test/xml/test-arg-invalid-included.xml" pass_all_args="true">
<arg name="grounded" value="not_set"/>
</include>
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<arg name="grounded" value="set"/>
</launch>

View File

@@ -0,0 +1,6 @@
<launch>
<arg name="grounded" value="1"/>
<arg name="grounded" value="regrounded"/>
</launch>

View File

@@ -0,0 +1,5 @@
<launch>
<arg name="invalid" value="$(arg missing)"/>
</launch>

View File

@@ -0,0 +1,5 @@
<launch>
<arg name="grounded" value="not_set"/>
<include file="$(find roslaunch)/test/xml/test-arg-invalid-included.xml" pass_all_args="true"/>
</launch>

View File

@@ -0,0 +1,98 @@
<launch>
<arg name="required" />
<arg name="if_test" />
<arg name="optional" default="not_set" />
<arg name="grounded" value="set" />
<arg name="include_arg" value="initial" />
<arg name="param1_name" value="p1" />
<arg name="param2_name" value="p2" />
<arg name="param3_name" value="p3" />
<arg name="param1_value" value="$(arg required)" />
<arg name="param2_value" value="$(arg optional)" />
<arg name="param3_value" value="$(arg grounded)" />
<arg name="int_value" value="1234" />
<arg name="float_value" value="3.0" />
<arg if="$(arg if_test)" name="if_param_value" value="true" />
<arg unless="$(arg if_test)" name="if_param_value" value="false" />
<arg if="$(arg if_test)" name="py_if_param_value" value="$(eval 1 == 1)"/>
<arg unless="$(arg if_test)" name="py_if_param_value" value="$(eval 1 == 0)"/>
<param name="$(arg param1_name)_test" value="$(arg param1_value)" />
<param name="$(arg param2_name)_test" value="$(arg param2_value)" />
<param name="$(arg param3_name)_test" value="$(arg param3_value)" />
<param name="if_param" value="$(arg if_param_value)" />
<param name="py_if_param" value="$(arg py_if_param_value)" />
<param name="int_param" value="$(arg int_value)" />
<param name="float_param" value="$(arg float_value)" />
<group>
<arg name="context" value="group1" />
<param name="context1" value="$(arg context)" />
</group>
<group>
<arg name="context" value="group2" />
<param name="context2" value="$(arg context)" />
</group>
<arg name="fail" value="0" />
<group if="$(arg fail)">
<param name="fail" value="fail" />
</group>
<group unless="$(arg fail)">
<param name="succeed" value="yes" />
</group>
<group if="$(arg if_test)">
<param name="if_test" value="ran" />
</group>
<group unless="$(arg if_test)">
<param name="if_test" value="not_ran" />
</group>
<arg name="py_fail" value="$(eval 0 &gt; 1)"/>
<group if="$(eval py_fail == True)">
<param name="py_fail" value="fail" />
</group>
<group unless="$(eval arg('py_fail') == True)">
<param name="py_succeed" value="yes" />
</group>
<group if="$(eval if_test == True)">
<param name="py_if_test" value="ran" />
</group>
<group unless="$(eval arg('if_test') == True)">
<param name="py_if_test" value="not_ran" />
</group>
<include file="$(find roslaunch)/test/xml/test-arg-include.xml">
<arg name="required" value="required1" />
<arg name="include_arg" value="$(arg include_arg)" />
</include>
<include ns="include2" file="$(find roslaunch)/test/xml/test-arg-include.xml">
<arg name="required" value="required2" />
<arg name="optional" value="optional2" />
<arg name="include_arg" value="new2" />
</include>
<include if="$(arg if_test)" ns="include3" file="$(find roslaunch)/test/xml/test-arg-include.xml">
<arg name="required" value="required3" />
<arg name="optional" value="optional3" />
<arg name="include_arg" value="new3" />
</include>
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<!-- intentionally empty -->
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node pkg="package" type="test_clear_params_no_name" clear_params="true" />
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<!-- group with no 'ns' attribute -->
<group clear_params="true" />
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<!-- include with no 'ns' attribute -->
<include clear_params="true" file="$(find roslaunch)/test/xml/test-clear-params-include.xml" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node pkg="package" name="node_name" type="test_clear_params_invalid_clear_params_attr" clear_params="foo" />
</launch>

View File

@@ -0,0 +1,28 @@
<launch>
<node pkg="package" type="type" name="test_clear_params1" clear_params="true" />
<node pkg="package" type="type" name="test_clear_params2" clear_params="True" />
<node pkg="package" type="type" name="test_clear_params_ns" ns="clear_params_ns" clear_params="true"/>
<node pkg="package" type="type" name="test_clear_params_default" ns="clear_params_default" />
<node pkg="package" type="type" name="test_clear_params_false" ns="clear_params_false" clear_params="False"/>
<group ns="group_test" clear_params="true">
</group>
<group ns="group_test_default">
</group>
<group ns="group_test_false" clear_params="false">
</group>
<group ns="embed_group_test">
<group ns="embedded_group" clear_params="true" />
</group>
<include ns="include_test" clear_params="true" file="$(find roslaunch)/test/xml/test-clear-params-include.xml" />
<include ns="include_test_false" clear_params="false" file="$(find roslaunch)/test/xml/test-clear-params-include.xml" />
<include ns="include_test_default" file="$(find roslaunch)/test/xml/test-clear-params-include.xml" />
</launch>

View File

@@ -0,0 +1,41 @@
<launch>
<param name="~tilde1" value="foo" />
<rosparam file="$(find roslaunch)/test/dump-params.yaml" command="load" />
<group ns="rosparam">
<param name="~tilde2" value="bar" />
<rosparam file="$(find roslaunch)/test/dump-params.yaml" command="load" />
</group>
<node pkg="package" type="test_base" name="node_rosparam">
<param name="local_param" value="baz" />
<rosparam file="$(find roslaunch)/test/dump-params.yaml" command="load" />
</node>
<node pkg="package" type="test_base" name="node_rosparam2">
</node>
<rosparam param="inline_str">value1</rosparam>
<rosparam param="inline_list">[1, 2, 3, 4]</rosparam>
<rosparam param="inline_dict">{key1: value1, key2: value2}</rosparam>
<rosparam param="inline_dict2">
key3: value3
key4: value4
</rosparam>
<rosparam param="override">{key1: value1, key2: value2}</rosparam>
<rosparam param="override">{key1: override1}</rosparam>
<!-- no key tests -->
<rosparam>
noparam1: value1
noparam2: value2
</rosparam>
<!-- allow empty files. we test absense of loading in test-rosparam-empty.
Here we include to make sure this doesn't blank out other parameters -->
<rosparam file="$(find roslaunch)/test/params_empty1.yaml" command="load" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node name="n12i" pkg="package" type="test_one_two_include" />
</launch>

View File

@@ -0,0 +1,18 @@
<launch>
<node name="n0" pkg="package" type="test_none" />
<env name="ONE" value="one" />
<node name="n1" pkg="package" type="test_one">
</node>
<env name="TWO" value="two" />
<node name="n2" pkg="package" type="test_one_two_priv">
<env name="PRIVATE_TWO" value="private_two" />
</node>
<node name="n3" pkg="package" type="test_one_two" />
<include file="$(find roslaunch)/test/xml/test-env-include.xml">
<env name="INCLUDE" value="include" />
</include>
</launch>

View File

@@ -0,0 +1,6 @@
<launch>
<group if="1" unless="1">
</group>
</launch>

View File

@@ -0,0 +1,63 @@
<launch>
<group if="1">
<param name="group_if_pass" value="1" />
</group>
<group if="0">
<param name="group_if_fail" value="1" />
</group>
<group unless="0">
<param name="group_unless_pass" value="1" />
</group>
<group unless="1">
<param name="group_unless_fail" value="1" />
</group>
<param name="param_if_pass" value="1" if="1" />
<param name="param_if_fail" value="1" if="0" />
<param name="param_unless_pass" value="1" unless="0" />
<param name="param_unless_fail" value="1" unless="1" />
<remap from="from_if_pass" to="to_if_pass" if="1" />
<remap from="from_if_fail" to="to_if_fail" if="0" />
<remap from="from_unless_pass" to="to_unless_pass" unless="0" />
<remap from="from_unless_fail" to="to_unless_fail" unless="1" />
<!-- Test Python parsing -->
<group if="$(eval 1 == 1)">
<param name="py_group_if_pass" value="1" />
</group>
<group if="$(eval 0 == 1)">
<param name="py_group_if_fail" value="1" />
</group>
<group unless="$(eval 0 == 1)">
<param name="py_group_unless_pass" value="1" />
</group>
<group unless="$(eval 1 == 1)">
<param name="py_group_unless_fail" value="1" />
</group>
<arg name="true_lower" value="true"/>
<arg name="true_upper" value="True"/>
<arg name="false_lower" value="false"/>
<arg name="false_upper" value="False"/>
<param name="py_param_if_pass" value="1" if="$(eval arg('true_lower') and (40+2) == 42)"/>
<param name="py_param_if_fail" value="1" if="$(eval false_lower or (40-2) != 38)"/>
<param name="py_param_unless_pass" value="1" unless="$(eval arg('false_upper') or 1 &lt; 1)"/>
<param name="py_param_unless_fail" value="1" unless="$(eval true_upper and 1 &gt;= 1)"/>
<remap from="py_from_if_pass" to="py_to_if_pass" if="$(eval arg('true_upper') == True)"/>
<remap from="py_from_if_fail" to="py_to_if_fail" if="$(eval false_upper != False)"/>
<remap from="py_from_unless_pass" to="py_to_unless_pass"
unless="$(eval arg('false_lower') or false_upper or arg('false_upper') != False)"/>
<remap from="py_from_unless_fail" to="py_to_unless_fail"
unless="$(eval arg('true_lower') and true_upper and arg('true_upper') == True)"/>
<node name="remap" pkg="rospy" type="talker.py" />
</launch>

View File

@@ -0,0 +1,20 @@
<launch>
<!-- no local params -->
<node pkg="pkg" type="type0" name="node0"/>
<group ns="group1">
<!-- basic test, named nodes -->
<node pkg="pkg" type="gtype0" name="g1node0" />
<param name="~gparam1" value="val1" />
<node pkg="pkg" type="g1type1" name="g1node1" />
<param name="~gparam2" value="val1" />
<node pkg="pkg" type="g1type2" name="g1node2" />
</group>
<!-- make sure scope is cleared by end of group -->
<param name="~param1" value="val1" />
<node pkg="pkg" type="type1" name="node1" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<machine name="machine3" address="address3" ros-ip="hostname" />
</launch>

View File

@@ -0,0 +1,9 @@
<launch>
<machine name="machine4" address="address4">
<env name="ENV1" value="value1" />
<env name="ENV2" value="value2" />
<env name="ENV3" value="value3" />
</machine>
</launch>

View File

@@ -0,0 +1,6 @@
<launch>
<!-- if ros-root is explicitly set and ros-package-path is not, ros-package-path should not get a default value -->
<machine name="machine5" address="address5" ros-root="/ros/root" />
</launch>

View File

@@ -0,0 +1,5 @@
<launch>
<!-- address is required -->
<machine name="machine1" />
</launch>

View File

@@ -0,0 +1,5 @@
<launch>
<!-- name is required -->
<machine address="address1" />
</launch>

View File

@@ -0,0 +1,5 @@
<launch>
<!-- timeout must be non-empty -->
<machine timeout="" name="one" address="address1" />
</launch>

View File

@@ -0,0 +1,5 @@
<launch>
<!-- timeout must be a number -->
<machine timeout="ten" name="one" address="address1" />
</launch>

View File

@@ -0,0 +1,5 @@
<launch>
<!-- timeout must be a number -->
<machine timeout="-1" name="one" address="address1" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<machine name="machine2" address="address2" ros-root="/ros/root" ros-package-path="/ros/package/path" ros-host-name="hostname" />
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<machine name="machine1" address="address1" default="foo" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<machine name="$(env NAME)" address="$(env ADDRESS)" />
</launch>

View File

@@ -0,0 +1,17 @@
<launch>
<machine name="machine1" address="address1" default="true" />
<!-- verify ros-ip and ros-host-name alias -->
<machine name="machine6" address="address6">
<!-- fake attrs are okay, but will print warnings to screen -->
<fake name="ENV3" value="value3" />
</machine>
<machine name="machine7" address="address7" timeout="10.0" />
<machine name="machine8" address="address8" timeout="1" />
<machine name="machine9" address="address19" env-loader="/opt/ros/fuerte/env.sh" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node name="n" pkg="package" type="test_cwd_invalid" cwd="foo" />
</launch>

View File

@@ -0,0 +1,6 @@
<launch>
<node name="n" pkg="package" type="env_test_invalid_name">
<env name="" value="env1 value1" />
</node>
</launch>

View File

@@ -0,0 +1,6 @@
<launch>
<node name="n" pkg="package" type="env_test_invalid_name">
<env value="env1 value1" />
</node>
</launch>

View File

@@ -0,0 +1,6 @@
<launch>
<node name="n" pkg="package" type="env_test_invalid_value">
<env name="env1" />
</node>
</launch>

View File

@@ -0,0 +1,6 @@
<launch>
<!-- should raise exception for node pkg being empty -->
<node name="n" pkg="" type="test_xmlparseexception" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node name="n" pkg="package" type="test_ns_invalid" machine="" />
</launch>

View File

@@ -0,0 +1,9 @@
<launch>
<!-- this test is currently disabled is this is legal right now -->
<!-- name attribute missing with param set -->
<node pkg="package" type="name_test_invalid_value">
<param name="foo" value="bar" />
</node>
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<node pkg="package" type="name_test_invalid_value" name="ns/foo" />
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<!-- names cannot have namespaces -->
<node pkg="package" type="test_cwd_invalid" name="ns/name" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node pkg="package" type="test_ns_invalid" ns="" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node pkg="package" type="test_ns_invalid" ns="/global" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node pkg="package" type="test_ns_invalid" ns="" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node pkg="package" type="type" output="foo" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node pkg="" type="type" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node type="type" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node name="n" pkg="package" type="type" required="" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node name="n" pkg="package" type="type" required="foo" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node name="n" pkg="package" type="type" respawn="true" required="true" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node name="n" pkg="package" type="type" respawn="foo" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node name="n" pkg="package" type="" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node name="n" pkg="package" />
</launch>

View File

@@ -0,0 +1,10 @@
<launch>
<group ns="ns1">
<node pkg="package" type="test_node_rosparam_delete" name="rosparam_delete">
<rosparam ns="ns2" param="param" command="delete" />
</node>
</group>
</launch>

View File

@@ -0,0 +1,8 @@
<launch>
<node pkg="package" type="test_node_rosparam_dump" name="rosparam_dump">
<rosparam file="dump.yaml" command="dump" />
</node>
</launch>

View File

@@ -0,0 +1,9 @@
<launch>
<!-- name attribute is required -->
<node pkg="package" type="test_node_rosparam_invalid_name" >
<rosparam file="$(find roslaunch)/test/params.yaml" command="load" />
</node>
</launch>

View File

@@ -0,0 +1,10 @@
<launch>
<node pkg="package" type="test_node_rosparam_multi" name="rosparam_multi">
<rosparam file="$(find roslaunch)/test/params.yaml" command="load" />
<rosparam file="mdump.yaml" command="dump" />
<rosparam ns="msubns" file="$(find roslaunch)/test/params.yaml" command="load" />
</node>
</launch>

View File

@@ -0,0 +1,8 @@
<launch>
<node pkg="package" type="test_node_rosparam_load_ns" name="load_ns">
<rosparam ns="subns" file="$(find roslaunch)/test/params.yaml" command="load" />
</node>
</launch>

View File

@@ -0,0 +1,8 @@
<launch>
<node pkg="package" type="test_node_rosparam_load_param" name="load_param">
<rosparam param="param" file="$(find roslaunch)/test/params.yaml" command="load" />
</node>
</launch>

View File

@@ -0,0 +1,8 @@
<launch>
<node pkg="package" type="test_node_rosparam_load" name="rosparam_load">
<rosparam file="$(find roslaunch)/test/params.yaml" command="load" />
</node>
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<node name="n1" pkg="$(env PACKAGE)" type="$(env TYPE)" output="$(env OUTPUT)" respawn="$(env RESPAWN)"/>
</launch>

View File

@@ -0,0 +1,82 @@
<launch>
<node name="n1" pkg="package" type="test_base" />
<node name="n2" pkg="package" type="test_args" args="args test" />
<node name="n3" pkg="package" type="test_args_empty" args="" />
<!-- TODO: more substitution args? -->
<node name="n4" pkg="package" type="test_output_screen" output="screen" />
<node name="n5" pkg="package" type="test_output_log" output="log" />
<node name="n6" pkg="package" type="test_machine" machine="machine_test" />
<node name="n7" pkg="package" type="test_ns1" ns="ns_test1" />
<node name="n8" pkg="package" type="test_ns2" ns="ns_test2/child2" />
<node name="n9" pkg="package" type="test_ns3" ns="ns_test3/child3/" />
<node name="n10" pkg="package" type="test_respawn_true" respawn="true" />
<node name="n11" pkg="package" type="test_respawn_TRUE" respawn="TRUE" />
<node name="n12" pkg="package" type="test_respawn_false" respawn="false" />
<node name="n13" pkg="package" type="test_respawn_FALSE" respawn="FALSE" />
<node name="n14" pkg="package" type="test_respawn_none" />
<node name="n15" pkg="package" type="test_env">
<env name="env1" value="env1 value1" />
<env name="env2" value="env2 value2" />
</node>
<node name="n16" pkg="package" type="test_fake">
<!-- unrecognized tags are ok, but will print warnings to screen -->
<fake name="env2" value="env2 value2" />
</node>
<node name="n17" pkg="package" type="test_env_empty">
<env name="env1" value="" />
</node>
<!-- base test of private parameter -->
<node name="test_private_param1" pkg="package" type="test_param">
<param name="foo1" value="bar1" />
</node>
<!-- test ns attribute -->
<node name="test_private_param2" ns="ns_test" pkg="package" type="test_param">
<param name="foo2" value="bar2" />
</node>
<!-- test with noop tilde syntax -->
<node name="test_private_param3" pkg="package" type="test_param">
<param name="~foo3" value="bar3" />
</node>
<node name="n21" pkg="package" type="test_cwd_2" cwd="node" />
<node name="n22" pkg="package" type="test_cwd_3" cwd="ROS_HOME" />
<node name="n23" pkg="package" type="test_cwd_3" cwd="ros_home" />
<node pkg="package" type="test_node_rosparam_load" name="rosparam_load">
<rosparam file="$(find roslaunch)/test/params.yaml" command="load" />
</node>
<node pkg="package" type="test_node_rosparam_dump" name="rosparam_dump">
<rosparam file="dump.yaml" command="dump" />
</node>
<node pkg="package" type="test_node_rosparam_load_ns" name="load_ns">
<rosparam ns="subns" file="$(find roslaunch)/test/params.yaml" command="load" />
</node>
<node pkg="package" type="test_node_rosparam_multi" name="rosparam_multi">
<rosparam file="$(find roslaunch)/test/params.yaml" command="load" />
<rosparam file="mdump.yaml" command="dump" />
<rosparam ns="msubns" file="$(find roslaunch)/test/params.yaml" command="load" />
</node>
<node name="n26" pkg="package" type="test_required_true_1" required="true" />
<node name="n27" pkg="package" type="test_required_true_2" required="True" />
<node name="n28" pkg="package" type="test_required_false_1" required="false" />
<node name="n29" pkg="package" type="test_required_false_2" required="FALSE" />
<!-- TODO remap args test -->
<node name="n30" pkg="package" type="test_launch_prefix" launch-prefix="xterm -e gdb --args" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<param name="somestring1" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<param value="someval" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<param name="name1" value="someval" textfile="$(find rosparam)/example.yaml" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<param name="~private" val="value" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<param name="name" command="not_a_command" />
</launch>

View File

@@ -0,0 +1,40 @@
<launch>
<!--
Parameter Server parameters. You can omit the 'type' attribute if
value is unambiguous. Supported types are str, int, double, bool.
You can also specify the contents of a file instead using the
'textfile' or 'binfile' attributes.
-->
<param name="somestring1" value="bar2" />
<!-- force to string instead of integer -->
<param name="somestring2" value="10" type="str" />
<param name="someinteger1" value="1" type="int" />
<param name="someinteger2" value="2" />
<param name="somefloat1" value="3.14159" type="double" />
<param name="somefloat2" value="5.0" />
<!-- you can set parameters in child namespaces -->
<param name="wg/wgchildparam" value="a child namespace parameter 1" />
<group ns="wg2">
<param name="wg2childparam1" value="a child namespace parameter 2" />
<param name="wg2childparam2" value="a child namespace parameter 3" />
</group>
<!-- upload the contents of a file as a param -->
<param name="configfile" textfile="$(find roslaunch)/resources/example.launch" />
<!-- upload the contents of a file as base64 binary as a param -->
<param name="binaryfile" binfile="$(find roslaunch)/resources/example.launch" />
<!-- upload the output of a command as a param. -->
<param name="commandoutput" command="cat &quot;$(find roslaunch)/resources/example.launch&quot;" />
<!-- test that we can override params -->
<param name="override" value="fail" />
<param name="override" value="pass" />
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<!-- missing to -->
<remap from="from" />
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<!-- missing from -->
<remap to="to" />
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<!-- to is empty-->
<remap from="from" to="" />
</launch>

View File

@@ -0,0 +1,4 @@
<launch>
<!-- from is empty -->
<remap from="" to="to" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<remap from="from something" to="to" />
</launch>

View File

@@ -0,0 +1,3 @@
<launch>
<remap from="from" to="to something" />
</launch>

Some files were not shown because too many files have changed in this diff Show More