diff options
author | Serhii Niukalov (GitHub) <36993782+SNiukalov@users.noreply.github.com> | 2020-01-10 18:05:19 +0200 |
---|---|---|
committer | Collin <iCollin@users.noreply.github.com> | 2020-01-10 11:05:18 -0500 |
commit | f113bc7dfb651908cdd8b68db1a634c798f88e89 (patch) | |
tree | 535fc76846dc66cb655762f77b84a06253815ff4 | |
parent | 49c29364460faa527bc758d0fd6b108463f8d82d (diff) | |
download | sdl_core-f113bc7dfb651908cdd8b68db1a634c798f88e89.tar.gz |
Fix crash in WebsocketSession on start. (#3191)
A crash occurs because we use an overload of
boost::beast::websocket::stream::write without error_code.
After the error occurs we add an error message to the logger
and continue working.
In SendMessage_UnpreparedConnection_WithoutFall test we use sleep because we can't ability to catch processed event.
This issue is that LoopThreadDelegate requires a WebsocketSession to work.
WebsocketSession init LoopThreadDelegate with 'this', so we have no way to simulate it without additional installers.
In future, to avoid sleep, we can:
Create a wrapper class for the socket, then provide the socket layout for the WebsocketSession in unit tests and wrap the following interfaces:
async_read
write down
get_executor
async_accept
-rw-r--r-- | src/components/hmi_message_handler/src/websocket_session.cc | 14 | ||||
-rw-r--r-- | src/components/hmi_message_handler/test/hmi_message_handler_impl_test.cc | 40 |
2 files changed, 48 insertions, 6 deletions
diff --git a/src/components/hmi_message_handler/src/websocket_session.cc b/src/components/hmi_message_handler/src/websocket_session.cc index 3d18da19d2..ad9d5273e4 100644 --- a/src/components/hmi_message_handler/src/websocket_session.cc +++ b/src/components/hmi_message_handler/src/websocket_session.cc @@ -304,12 +304,14 @@ void WebsocketSession::LoopThreadDelegate::exitThreadMain() { } void WebsocketSession::LoopThreadDelegate::DrainQueue() { - while (!message_queue_.empty()) { - Message message_ptr; - message_queue_.pop(message_ptr); - if (!shutdown_) { - handler_.ws_.write(boost::asio::buffer(*message_ptr)); - }; + Message message_ptr; + while (!shutdown_ && message_queue_.pop(message_ptr)) { + boost::system::error_code ec; + handler_.ws_.write(boost::asio::buffer(*message_ptr), ec); + if (ec) { + LOG4CXX_ERROR(ws_logger_, + "A system error has occurred: " << ec.message()); + } } } diff --git a/src/components/hmi_message_handler/test/hmi_message_handler_impl_test.cc b/src/components/hmi_message_handler/test/hmi_message_handler_impl_test.cc index eaa274d0f4..f38eb019e2 100644 --- a/src/components/hmi_message_handler/test/hmi_message_handler_impl_test.cc +++ b/src/components/hmi_message_handler/test/hmi_message_handler_impl_test.cc @@ -189,6 +189,46 @@ TEST_F(HMIMessageHandlerImplTest, SendMessageToHMI_Success) { EXPECT_TRUE(waiter.WaitFor(1, 100)); } +TEST(WebsocketSessionTest, SendMessage_UnpreparedConnection_WithoutFall) { + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + + auto send_message = []() { + auto message = + "{\"id\" : 1,\"jsonrpc\" : \"2.0\",\"method\" : " + "\"BasicCommunication.GetSystemInfo\"}"; + + Json::Reader reader; + Json::Value json_value; + + ASSERT_TRUE(reader.parse(message, json_value, false)); + + // Make unprepared connection + boost::asio::io_context ioc{1}; + boost::asio::ip::tcp::acceptor acceptor{ + ioc, {boost::asio::ip::make_address("127.0.0.1"), 8087}}; + boost::asio::ip::tcp::socket socket{ioc}; + + std::unique_ptr<hmi_message_handler::WebsocketSession> session( + new hmi_message_handler::WebsocketSession(std::move(socket), nullptr)); + + // Send message to unprepared connection + session->sendJsonMessage(json_value); + + // Wait for the message to be processed + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Stopping connection thread + session->Shutdown(); + session = nullptr; + + exit(0); + }; + + // Expected exit code 0, if test terminate by other signal(SIGABRT or + // SIGSEGV), we will get failed test + EXPECT_EXIT(send_message(), ::testing::ExitedWithCode(0), ""); +} + } // namespace hmi_message_handler_test } // namespace components } // namespace test |