[ros2] Test is not finishing its execution
I am writing integration test cases for my ROS service. Please see the sample code snippet below:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from threading import Thread
import unittest
from example_interfaces.srv import AddTwoInts
import launch
import launch_ros
import launch_ros.actions
import launch_testing.actions
import pytest
import rclpy
@pytest.mark.rostest
def generate_test_description():
minimal_service_node = launch_ros.actions.Node(
package='examples_rclpy_minimal_service',
namespace='',
executable='service_member_function',
)
return (
launch.LaunchDescription(
[
minimal_service_node,
launch_testing.actions.ReadyToTest(),
]
),
{
'minimal_service': minimal_service_node,
},
)
class TestMinimalService(unittest.TestCase):
@classmethod
def setUpClass(cls):
rclpy.init()
@classmethod
def tearDownClass(cls):
rclpy.shutdown()
def setUp(self):
self.node = rclpy.create_node('test_minimal_service')
self.client_add_two_ints = self.node.create_client(AddTwoInts, '/add_two_ints')
# test cases work when the following line is uncommented
# self.assertTrue(self.client_add_two_ints.wait_for_service(timeout_sec=5.0))
self.spin_thread = Thread(target=rclpy.spin, args=(self.node,))
self.spin_thread.start()
def tearDown(self):
self.node.destroy_node()
def test_add_two_ints_exists(self):
self.assertTrue(self.client_add_two_ints.wait_for_service(timeout_sec=5.0))
def test_add_two_ints(self):
req = AddTwoInts.Request(a=10, b=20)
res = self.client_add_two_ints.call(req)
self.assertEqual(res.sum, 30)
Testing
$ launch_test src/minimal_service/test/test_service_member_function.py
[INFO] [launch]: All log files can be found below /home/ravi/.ros/log/2022-07-28-15-22-23-845507-dell-148344
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [service_member_function-1]: process started with pid [148347]
test_add_two_ints (test_service_member_function.TestMinimalService) ... ^C[WARNING] [launch]: user interrupted with ctrl-c (SIGINT)
[INFO] [service_member_function-1]: process has finished cleanly [pid 148347]
Processes under test stopped before tests completed
The test test_add_two_ints
stays as it is and does not return. Later, I pressed Ctrl + C to terminate the process forcefully.
Weird Behavior
The setUp
method contains an assertion statement. Surprisingly, both the test cases work if I uncomment the assertion. See below, please.
$ launch_test src/minimal_service/test/test_service_member_function.py
[INFO] [launch]: All log files can be found below /home/ravi/.ros/log/2022-07-28-15-28-44-770728-dell-149020
[INFO] [launch]: Default logging verbosity is set to INFO
test_add_two_ints (test_service_member_function.TestMinimalService) ... [INFO] [service_member_function-1]: process started with pid [149023]
[service_member_function-1] [INFO] [1658989725.064503034] [minimal_service]: Incoming request
[service_member_function-1] a: 10 b: 20
ok
test_add_two_ints_exists (test_service_member_function.TestMinimalService) ... Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
self.run()
File "/usr/lib/python3.8/threading.py", line 870, in run
ok
self._target(*self._args, **self._kwargs)
----------------------------------------------------------------------
File "/opt/ros/foxy/lib/python3.8/site-packages/rclpy/__init__.py", line 191, in spin
Ran 2 tests in 0.555s
OK
executor.spin_once()
File "/opt/ros/foxy/lib/python3.8/site-packages/rclpy/executors.py", line 706, in spin_once
[INFO] [service_member_function-1]: sending signal 'SIGINT' to process[service_member_function-1]
handler, entity, node = self.wait_for_ready_callbacks(timeout_sec=timeout_sec)
File "/opt/ros/foxy/lib/python3.8/site-packages/rclpy/executors.py", line 692, in wait_for_ready_callbacks
return next(self._cb_iter)
ValueError: generator already executing
[INFO] [service_member_function-1]: process has finished cleanly [pid 149023]
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
Additional Info
Below is the workspace structure:
.
├── build
├── install
├── log
└── src
└── minimal_service
├── CHANGELOG.rst
├── examples_rclpy_minimal_service
│ ├── __init__.py
│ └── service_member_function.py
├── package.xml
├── README.md
├── resource
│ └── examples_rclpy_minimal_service
├── setup.cfg
├── setup.py
└── test
├── test_copyright.py
├── test_flake8.py
├── test_pep257.py
└── test_service_member_function.py ...