Skip to content

Commit

Permalink
Ensure load_composable_nodes respects condition (#339)
Browse files Browse the repository at this point in the history
  • Loading branch information
methylDragon authored Dec 8, 2022
1 parent af784b2 commit e2c2025
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 9 deletions.
26 changes: 17 additions & 9 deletions launch_ros/launch_ros/actions/load_composable_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,23 +229,31 @@ def execute(

# Generate load requests before execute() exits to avoid race with context changing
# due to scope change (e.g. if loading nodes from within a GroupAction).
load_node_requests = [
get_composable_node_load_request(node_description, context)
for node_description in self.__composable_node_descriptions
]

context.add_completion_future(
context.asyncio_loop.run_in_executor(
None, self._load_in_sequence, load_node_requests, context
load_node_requests = []
for node_description in self.__composable_node_descriptions:
request = get_composable_node_load_request(node_description, context)
# The request can be None if the node description's condition evaluates to False
if request is not None:
load_node_requests.append(request)

if load_node_requests:
context.add_completion_future(
context.asyncio_loop.run_in_executor(
None, self._load_in_sequence, load_node_requests, context
)
)
)


def get_composable_node_load_request(
composable_node_description: ComposableNode,
context: LaunchContext
):
"""Get the request that will be sent to the composable node container."""
if composable_node_description.condition() is not None:
if not composable_node_description.condition().evaluate(context):
# Return no request if the node description's condition evaluates to False
return None

request = composition_interfaces.srv.LoadNode.Request()
request.package_name = perform_substitutions(
context, composable_node_description.package
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from launch import LaunchDescription
from launch import LaunchService
from launch.actions import GroupAction
from launch.conditions import IfCondition
from launch_ros.actions import LoadComposableNodes
from launch_ros.actions import PushROSNamespace
from launch_ros.actions import SetRemap
Expand Down Expand Up @@ -99,6 +100,7 @@ def _load_composable_node(
plugin,
name,
namespace='',
condition=None,
parameters=None,
remappings=None,
target_container=f'/{TEST_CONTAINER_NAME}'
Expand All @@ -107,6 +109,7 @@ def _load_composable_node(
target_container=target_container,
composable_node_descriptions=[
ComposableNode(
condition=condition,
package=package,
plugin=plugin,
name=name,
Expand Down Expand Up @@ -150,6 +153,41 @@ def test_load_node(mock_component_container):
assert len(request.extra_arguments) == 0


def test_load_node_with_conditions(mock_component_container):
"""Test loading nodes with conditions scoped to a group."""
context = _assert_launch_no_errors([
_load_composable_node(
package='foo_package',
plugin='bar_plugin',
name='test_node_name_true',
namespace='test_node_namespace',
condition=IfCondition('True')
),
_load_composable_node(
package='foo_package',
plugin='bar_plugin',
name='test_node_name_false',
namespace='test_node_namespace',
condition=IfCondition('False')
)
])

# Check that launch is aware of loaded component
assert get_node_name_count(context, '/test_node_namespace/test_node_name_true') == 1
assert get_node_name_count(context, '/test_node_namespace/test_node_name_false') == 0

# Check that container recieved correct request
assert len(mock_component_container.requests) == 1
request = mock_component_container.requests[0]
assert request.package_name == 'foo_package'
assert request.plugin_name == 'bar_plugin'
assert request.node_name == 'test_node_name_true'
assert request.node_namespace == '/test_node_namespace'
assert len(request.remap_rules) == 0
assert len(request.parameters) == 0
assert len(request.extra_arguments) == 0


def test_load_node_with_remaps(mock_component_container):
"""Test loading a node with remappings."""
context = _assert_launch_no_errors([
Expand Down Expand Up @@ -515,3 +553,44 @@ def test_load_node_with_namespace_in_group(mock_component_container):
assert len(request.remap_rules) == 0
assert len(request.parameters) == 0
assert len(request.extra_arguments) == 0


def test_load_node_with_condition_in_group(mock_component_container):
"""Test loading nodes with conditions scoped to a group."""
context = _assert_launch_no_errors([
GroupAction(
[
PushROSNamespace('foo'),
_load_composable_node(
package='foo_package',
plugin='bar_plugin',
name='test_node_name_true',
namespace='test_node_namespace',
condition=IfCondition('True')
),
_load_composable_node(
package='foo_package',
plugin='bar_plugin',
name='test_node_name_false',
namespace='test_node_namespace',
condition=IfCondition('False')
),
],
scoped=True,
),
])

# Check that launch is aware of loaded component
assert get_node_name_count(context, '/foo/test_node_namespace/test_node_name_true') == 1
assert get_node_name_count(context, '/foo/test_node_namespace/test_node_name_false') == 0

# Check that container recieved correct request
assert len(mock_component_container.requests) == 1
request = mock_component_container.requests[0]
assert request.package_name == 'foo_package'
assert request.plugin_name == 'bar_plugin'
assert request.node_name == 'test_node_name_true'
assert request.node_namespace == '/foo/test_node_namespace'
assert len(request.remap_rules) == 0
assert len(request.parameters) == 0
assert len(request.extra_arguments) == 0

0 comments on commit e2c2025

Please sign in to comment.