Skip to content

Commit 250c228

Browse files
committed
Add basic ctrl_c_event_can_be_send_and_received test
Signed-off-by: Michael Orlov <[email protected]>
1 parent bffbd3f commit 250c228

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed

rosbag2_test_common/CMakeLists.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,26 @@ install(
4242
DESTINATION include/${PROJECT_NAME})
4343

4444
if(BUILD_TESTING)
45+
find_package(ament_cmake_gmock REQUIRED)
4546
find_package(ament_lint_auto REQUIRED)
47+
find_package(rcpputils REQUIRED)
4648
ament_lint_auto_find_test_dependencies()
49+
50+
add_executable(loop_with_ctrl_c_handler test/rosbag2_test_common/loop_with_ctrl_c_handler.cpp)
51+
install(
52+
TARGETS loop_with_ctrl_c_handler
53+
EXPORT export_loop_with_ctrl_c_handler
54+
ARCHIVE DESTINATION lib
55+
LIBRARY DESTINATION lib
56+
RUNTIME DESTINATION bin
57+
)
58+
59+
ament_add_gmock(test_process_execution_helpers
60+
test/rosbag2_test_common/test_process_execution_helpers.cpp
61+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
62+
if(TARGET test_process_execution_helpers)
63+
target_link_libraries(test_process_execution_helpers ${PROJECT_NAME})
64+
endif()
4765
endif()
4866

4967
ament_python_install_package(${PROJECT_NAME})

rosbag2_test_common/package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
<test_depend>ament_lint_auto</test_depend>
2525
<test_depend>ament_lint_common</test_depend>
26+
<test_depend>rcpputils</test_depend>
2627

2728
<export>
2829
<build_type>ament_cmake</build_type>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2023 Apex.AI, Inc. or its affiliates. All Rights Reserved.
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+
#include <cstdio>
16+
#include <iostream>
17+
#include <thread>
18+
19+
#ifdef _WIN32
20+
#include <windows.h>
21+
int main(void)
22+
{
23+
// Enable default CTRL+C handler first. This is workaround and needed for the cases when
24+
// process created with CREATE_NEW_PROCESS_GROUP flag. Without it, installing custom Ctrl+C
25+
// handler will not work.
26+
if (!SetConsoleCtrlHandler(nullptr, false)) {
27+
std::cerr << "Error: Failed to enable default CTL+C handler. \n";
28+
}
29+
30+
static std::atomic_bool running = true;
31+
// Installing our own control handler
32+
auto CtrlHandler = [](DWORD fdwCtrlType) -> BOOL {
33+
switch (fdwCtrlType) {
34+
case CTRL_C_EVENT:
35+
printf("Ctrl-C event\n");
36+
running = false;
37+
return TRUE;
38+
default:
39+
return FALSE;
40+
}
41+
};
42+
if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
43+
std::cerr << "\nError. Can't install SIGINT handler\n";
44+
return EXIT_FAILURE;
45+
} else {
46+
std::cout << "\nWaiting in a loop for CTRL+C event\n";
47+
std::cout.flush();
48+
while (running) {
49+
std::this_thread::sleep_for(std::chrono::milliseconds(30));
50+
}
51+
}
52+
return EXIT_SUCCESS;
53+
}
54+
#else
55+
#include <csignal>
56+
57+
int main()
58+
{
59+
auto old_sigint_handler = std::signal(
60+
SIGINT, [](int /* signal */) {
61+
printf("Ctrl-C event\n");
62+
exit(EXIT_SUCCESS);
63+
});
64+
65+
if (old_sigint_handler != SIG_ERR) {
66+
std::cout << "\nWaiting in a loop for CTRL+C event\n";
67+
std::cout.flush();
68+
while (1) {
69+
std::this_thread::sleep_for(std::chrono::milliseconds(30));
70+
}
71+
} else {
72+
std::cerr << "\nError. Can't install SIGINT handler\n";
73+
return EXIT_FAILURE;
74+
}
75+
return EXIT_SUCCESS;
76+
}
77+
78+
#endif
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2023 Apex.AI, Inc. or its affiliates. All Rights Reserved.
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+
#include <gmock/gmock.h>
16+
17+
#include "rosbag2_test_common/process_execution_helpers.hpp"
18+
#include "rcpputils/scope_exit.hpp"
19+
20+
class ProcessExecutionHelpersTest : public ::testing::Test
21+
{
22+
public:
23+
ProcessExecutionHelpersTest() = default;
24+
};
25+
26+
TEST_F(ProcessExecutionHelpersTest, ctrl_c_event_can_be_send_and_received) {
27+
testing::internal::CaptureStdout();
28+
auto process_id = start_execution("loop_with_ctrl_c_handler");
29+
auto cleanup_process_handle = rcpputils::make_scope_exit(
30+
[process_id]() {
31+
stop_execution(process_id);
32+
});
33+
34+
// Sleep for 1 second to yield CPU resources to the newly spawned process, to make sure that
35+
// signal handlers has been installed.
36+
std::this_thread::sleep_for(std::chrono::seconds(1));
37+
38+
std::string test_output = testing::internal::GetCapturedStdout();
39+
EXPECT_THAT(test_output, HasSubstr("Waiting in a loop for CTRL+C event"));
40+
41+
// Send SIGINT to child process and check exit code
42+
stop_execution(process_id, SIGINT);
43+
cleanup_process_handle.cancel();
44+
}

0 commit comments

Comments
 (0)