Skip to content

Commit e52f2cf

Browse files
authored
Migrate launch tests to new launch_testing features & API (#140)
* Update after launch_testing features becoming legacy. Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com> * Migrate rcutils tests to new launch_testing API. Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com> * Stop using injected attributes in launch tests. Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
1 parent dcb2733 commit e52f2cf

4 files changed

+71
-54
lines changed

CMakeLists.txt

+10-4
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ if(BUILD_TESTING)
118118
find_package(ament_lint_auto REQUIRED)
119119
ament_lint_auto_find_test_dependencies()
120120

121+
find_package(launch_testing_ament_cmake REQUIRED)
122+
121123
if(ament_cmake_cppcheck_FOUND)
122124
ament_cppcheck(
123125
TESTNAME "cppcheck_logging_macros"
@@ -150,15 +152,19 @@ if(BUILD_TESTING)
150152

151153
add_executable(test_logging_long_messages test/test_logging_long_messages.cpp)
152154
target_link_libraries(test_logging_long_messages ${PROJECT_NAME})
153-
ament_add_pytest_test(test_logging_long_messages
155+
add_launch_test(
154156
"test/test_logging_long_messages.py"
157+
TARGET test_logging_long_messages
155158
WORKING_DIRECTORY "$<TARGET_FILE_DIR:test_logging_long_messages>"
156-
TIMEOUT 10)
159+
TIMEOUT 10
160+
)
157161

158-
ament_add_pytest_test(test_logging_output_format
162+
add_launch_test(
159163
"test/test_logging_output_format.py"
164+
TARGET test_logging_output_format
160165
WORKING_DIRECTORY "$<TARGET_FILE_DIR:test_logging_long_messages>"
161-
TIMEOUT 10)
166+
TIMEOUT 10
167+
)
162168

163169
ament_add_gmock(test_logging_macros test/test_logging_macros.cpp)
164170
target_link_libraries(test_logging_macros ${PROJECT_NAME})

package.xml

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<test_depend>ament_lint_auto</test_depend>
1818
<test_depend>launch</test_depend>
1919
<test_depend>launch_testing</test_depend>
20+
<test_depend>launch_testing_ament_cmake</test_depend>
2021
<test_depend>osrf_testing_tools_cpp</test_depend>
2122

2223
<export>

test/test_logging_long_messages.py

+22-19
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,41 @@
1313
# limitations under the License.
1414

1515
import os
16+
import unittest
1617

1718
from launch import LaunchDescription
18-
from launch import LaunchService
1919
from launch.actions import ExecuteProcess
20-
from launch_testing import LaunchTestService
21-
from launch_testing.output import create_output_test_from_file
20+
from launch.actions import OpaqueFunction
2221

22+
import launch_testing
23+
import launch_testing.asserts
2324

24-
def test_logging_long_messages():
25+
26+
def generate_test_description(ready_fn):
27+
launch_description = LaunchDescription()
2528
# Set the output format to a "verbose" format that is expected by the executable output
2629
os.environ['RCUTILS_CONSOLE_OUTPUT_FORMAT'] = \
2730
'[{severity}] [{name}]: {message} ({function_name}() at {file_name}:{line_number})'
2831
executable = os.path.join(os.getcwd(), 'test_logging_long_messages')
2932
if os.name == 'nt':
3033
executable += '.exe'
31-
ld = LaunchDescription()
32-
launch_test = LaunchTestService()
33-
action = launch_test.add_fixture_action(ld, ExecuteProcess(
34-
cmd=[executable], name='test_logging_long_messages', output='screen'
34+
process_name = 'test_logging_long_messages'
35+
launch_description.add_action(ExecuteProcess(
36+
cmd=[executable], name=process_name, output='screen'
3537
))
36-
output_file = os.path.join(
37-
os.path.dirname(__file__), 'test_logging_long_messages'
38-
)
39-
launch_test.add_output_test(
40-
ld, action, create_output_test_from_file(output_file)
38+
39+
launch_description.add_action(
40+
OpaqueFunction(function=lambda context: ready_fn())
4141
)
42+
return launch_description, {'process_name': process_name}
4243

43-
launch_service = LaunchService()
44-
launch_service.include_launch_description(ld)
45-
return_code = launch_test.run(launch_service)
46-
assert return_code == 0, 'Launch failed with exit code %r' % (return_code,)
4744

45+
class TestLoggingLongMessages(unittest.TestCase):
4846

49-
if __name__ == '__main__':
50-
test_logging_long_messages()
47+
def test_logging_output(self, proc_output, process_name):
48+
"""Test executable output against expectation."""
49+
proc_output.assertWaitFor(
50+
expected_output=launch_testing.tools.expected_output_from_file(
51+
path=os.path.join(os.path.dirname(__file__), process_name)
52+
), process=process_name, timeout=10
53+
)

test/test_logging_output_format.py

+38-31
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,20 @@
1313
# limitations under the License.
1414

1515
import os
16+
import unittest
1617

1718
from launch import LaunchDescription
18-
from launch import LaunchService
1919
from launch.actions import ExecuteProcess
20-
from launch_testing import LaunchTestService
21-
from launch_testing.output import create_output_test_from_file
20+
from launch.actions import OpaqueFunction
2221

22+
import launch_testing
23+
import launch_testing.asserts
2324

24-
def test_logging_output_format():
25-
ld = LaunchDescription()
26-
launch_test = LaunchTestService()
25+
26+
def generate_test_description(ready_fn):
27+
processes_to_test = []
28+
29+
launch_description = LaunchDescription()
2730
# Re-use the test_logging_long_messages test binary and modify the output format from an
2831
# environment variable.
2932
executable = os.path.join(os.getcwd(), 'test_logging_long_messages')
@@ -35,55 +38,59 @@ def test_logging_output_format():
3538
env_long['RCUTILS_CONSOLE_OUTPUT_FORMAT'] = \
3639
'[{{name}}].({severity}) output: {file_name}:{line_number} {message}, again: {message} ({function_name}()){' # noqa
3740
name = 'test_logging_output_format_long'
38-
action = launch_test.add_fixture_action(ld, ExecuteProcess(
41+
launch_description.add_action(ExecuteProcess(
3942
cmd=[executable], env=env_long, name=name, output='screen'
4043
))
41-
output_file = os.path.join(os.path.dirname(__file__), name)
42-
launch_test.add_output_test(
43-
ld, action, create_output_test_from_file(output_file)
44-
)
44+
processes_to_test.append(name)
4545

4646
env_edge_cases = dict(os.environ)
4747
# This custom output is to check different edge cases of the output format string parsing.
4848
env_edge_cases['RCUTILS_CONSOLE_OUTPUT_FORMAT'] = '{}}].({unknown_token}) {{{{'
4949
name = 'test_logging_output_format_edge_cases'
50-
action = launch_test.add_fixture_action(ld, ExecuteProcess(
50+
launch_description.add_action(ExecuteProcess(
5151
cmd=[executable], env=env_edge_cases, name=name, output='screen'
5252
))
53-
output_file = os.path.join(os.path.dirname(__file__), name)
54-
launch_test.add_output_test(
55-
ld, action, create_output_test_from_file(output_file)
56-
)
53+
processes_to_test.append(name)
5754

5855
env_no_tokens = dict(os.environ)
5956
# This custom output is to check that there are no issues when no tokens are used.
6057
env_no_tokens['RCUTILS_CONSOLE_OUTPUT_FORMAT'] = 'no_tokens'
6158
name = 'test_logging_output_format_no_tokens'
62-
action = launch_test.add_fixture_action(ld, ExecuteProcess(
59+
launch_description.add_action(ExecuteProcess(
6360
cmd=[executable], env=env_no_tokens, name=name, output='screen'
6461
))
65-
output_file = os.path.join(os.path.dirname(__file__), name)
66-
launch_test.add_output_test(
67-
ld, action, create_output_test_from_file(output_file)
68-
)
62+
processes_to_test.append(name)
6963

7064
env_time_tokens = dict(os.environ)
7165
# This custom output is to check that time stamps work correctly
7266
env_time_tokens['RCUTILS_CONSOLE_OUTPUT_FORMAT'] = "'{time}' '{time_as_nanoseconds}'"
7367
name = 'test_logging_output_timestamps'
74-
action = launch_test.add_fixture_action(ld, ExecuteProcess(
68+
launch_description.add_action(ExecuteProcess(
7569
cmd=[executable], env=env_time_tokens, name=name, output='screen'
7670
))
77-
output_file = os.path.join(os.path.dirname(__file__), name)
78-
launch_test.add_output_test(
79-
ld, action, create_output_test_from_file(output_file)
71+
processes_to_test.append(name)
72+
73+
launch_description.add_action(
74+
OpaqueFunction(function=lambda context: ready_fn())
8075
)
8176

82-
launch_service = LaunchService()
83-
launch_service.include_launch_description(ld)
84-
return_code = launch_test.run(launch_service)
85-
assert return_code == 0, 'Launch failed with exit code %r' % (return_code,)
77+
return launch_description, {'processes_to_test': processes_to_test}
78+
79+
80+
@launch_testing.post_shutdown_test()
81+
class TestLoggingOutputFormatAfterShutdown(unittest.TestCase):
8682

83+
def test_logging_output(self, proc_output, processes_to_test):
84+
"""Test all executables output against expectations."""
85+
for process_name in processes_to_test:
86+
launch_testing.asserts.assertInStdout(
87+
proc_output,
88+
expected_output=launch_testing.tools.expected_output_from_file(
89+
path=os.path.join(os.path.dirname(__file__), process_name)
90+
),
91+
process=process_name
92+
)
8793

88-
if __name__ == '__main__':
89-
test_logging_output_format()
94+
def test_processes_exit_codes(self, proc_info):
95+
"""Test that all executables finished cleanly."""
96+
launch_testing.asserts.assertExitCodes(proc_info)

0 commit comments

Comments
 (0)