Skip to content

Commit 719ced8

Browse files
committed
Add regression tests for LoadComposableNode
Signed-off-by: Jacob Perron <[email protected]>
1 parent 8d82979 commit 719ced8

File tree

2 files changed

+152
-2
lines changed

2 files changed

+152
-2
lines changed

launch_ros/launch_ros/actions/load_composable_nodes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ def __init__(
7979
self.__target_container = target_container
8080
self.__final_target_container_name = None # type: Optional[Text]
8181
self.__logger = launch.logging.get_logger(__name__)
82+
# Useful for regression testing
83+
self.__load_node_requests = None
8284

8385
def _load_node(
8486
self,
@@ -170,14 +172,14 @@ def execute(
170172

171173
# Generate load requests before execute() exits to avoid race with context changing
172174
# due to scope change (e.g. if loading nodes from within a GroupAction).
173-
load_node_requests = [
175+
self.__load_node_requests = [
174176
get_composable_node_load_request(node_description, context)
175177
for node_description in self.__composable_node_descriptions
176178
]
177179

178180
context.add_completion_future(
179181
context.asyncio_loop.run_in_executor(
180-
None, self._load_in_sequence, load_node_requests, context
182+
None, self._load_in_sequence, self.__load_node_requests, context
181183
)
182184
)
183185

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Copyright 2020 Open Source Robotics Foundation, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Tests for the LoadComposableNodes Action."""
16+
17+
import asyncio
18+
19+
from launch import LaunchDescription
20+
from launch import LaunchService
21+
from launch.actions import GroupAction
22+
from launch_ros.actions import ComposableNodeContainer
23+
from launch_ros.actions import LoadComposableNodes
24+
from launch_ros.actions import PushRosNamespace
25+
from launch_ros.actions import SetRemap
26+
from launch_ros.descriptions import ComposableNode
27+
from launch_ros.utilities import get_node_name_count
28+
29+
import osrf_pycommon.process_utils
30+
31+
TEST_CONTAINER_NAME = 'test_load_composable_nodes_container'
32+
TEST_NODE_NAME = 'test_load_composable_nodes_node'
33+
34+
35+
def _assert_launch_no_errors(actions, *, timeout_sec=1):
36+
ld = LaunchDescription(actions)
37+
ls = LaunchService(debug=True)
38+
ls.include_launch_description(ld)
39+
40+
loop = osrf_pycommon.process_utils.get_loop()
41+
launch_task = loop.create_task(ls.run_async())
42+
loop.run_until_complete(asyncio.sleep(timeout_sec))
43+
if not launch_task.done():
44+
loop.create_task(ls.shutdown())
45+
loop.run_until_complete(launch_task)
46+
assert 0 == launch_task.result()
47+
return ls.context
48+
49+
50+
def _create_node_container(*, parameters=None, remappings=None, namespace=''):
51+
return ComposableNodeContainer(
52+
package='rclcpp_components',
53+
executable='component_container',
54+
name=TEST_CONTAINER_NAME,
55+
namespace=namespace,
56+
output='screen',
57+
parameters=parameters,
58+
remappings=remappings,
59+
)
60+
61+
62+
def _load_composable_node(*, parameters=None, remappings=None):
63+
return LoadComposableNodes(
64+
target_container=TEST_CONTAINER_NAME,
65+
composable_node_descriptions=[
66+
ComposableNode(
67+
package='composition',
68+
plugin='composition::Listener',
69+
name=TEST_NODE_NAME,
70+
parameters=parameters,
71+
remappings=remappings,
72+
)
73+
])
74+
75+
76+
def test_load_invalid_node():
77+
"""Test loading an invalid node."""
78+
load_composable_nodes = LoadComposableNodes(
79+
target_container=TEST_CONTAINER_NAME,
80+
composable_node_descriptions=[
81+
ComposableNode(
82+
package='nonexistent_package',
83+
plugin='this_plugin_should_not_exist',
84+
name=TEST_NODE_NAME,
85+
)
86+
])
87+
context = _assert_launch_no_errors([_create_node_container(), load_composable_nodes])
88+
89+
assert get_node_name_count(context, f'/{TEST_NODE_NAME}') == 0
90+
assert get_node_name_count(context, f'/{TEST_CONTAINER_NAME}') == 1
91+
92+
93+
def test_load_node():
94+
"""Test loading a node."""
95+
context = _assert_launch_no_errors([
96+
_create_node_container(), _load_composable_node()
97+
])
98+
99+
assert get_node_name_count(context, f'/{TEST_NODE_NAME}') == 1
100+
assert get_node_name_count(context, f'/{TEST_CONTAINER_NAME}') == 1
101+
102+
103+
def test_load_node_with_global_remaps_in_group():
104+
"""Test loading a node with global remaps scoped to a group."""
105+
load_composable_nodes_action = _load_composable_node()
106+
context = _assert_launch_no_errors([
107+
_create_node_container(),
108+
GroupAction(
109+
[
110+
SetRemap('chatter', 'new_topic_name'),
111+
load_composable_nodes_action,
112+
],
113+
scoped=True,
114+
),
115+
])
116+
117+
assert get_node_name_count(context, f'/{TEST_NODE_NAME}') == 1
118+
assert get_node_name_count(context, f'/{TEST_CONTAINER_NAME}') == 1
119+
120+
# Check the remaps in load service request
121+
assert len(load_composable_nodes_action._LoadComposableNodes__load_node_requests) == 1
122+
request = load_composable_nodes_action._LoadComposableNodes__load_node_requests[0]
123+
assert len(request.remap_rules) == 1
124+
assert request.remap_rules[0] == 'chatter:=new_topic_name'
125+
126+
127+
def test_load_node_with_namespace_in_group():
128+
"""Test loading a node with namespace scoped to a group."""
129+
namespace = '/foo'
130+
load_composable_nodes_action = _load_composable_node()
131+
context = _assert_launch_no_errors([
132+
_create_node_container(),
133+
GroupAction(
134+
[
135+
PushRosNamespace(namespace),
136+
load_composable_nodes_action,
137+
],
138+
scoped=True,
139+
),
140+
])
141+
142+
assert get_node_name_count(context, f'{namespace}/{TEST_NODE_NAME}') == 1
143+
assert get_node_name_count(context, f'/{TEST_CONTAINER_NAME}') == 1
144+
145+
# Check the namespace in load service request
146+
assert len(load_composable_nodes_action._LoadComposableNodes__load_node_requests) == 1
147+
request = load_composable_nodes_action._LoadComposableNodes__load_node_requests[0]
148+
assert request.node_namespace == f'{namespace}'

0 commit comments

Comments
 (0)