@@ -1738,9 +1738,9 @@ TEST(config, can_replace_scheduler)
17381738
17391739 mre.get ();
17401740
1741- // http_client->send (negotiate), websocket_client->start, handshake timeout timer, websocket_client->send, websocket_client->send, websocket_client->stop
1741+ // http_client->send (negotiate), websocket_client->start, handshake timeout timer, websocket_client->send, websocket_client->send, keep alive timer, websocket_client->send ping, websocket_client->stop
17421742 // handshake timeout timer can trigger more than once if test takes more than 1 second
1743- ASSERT_GE (6 , scheduler->schedule_count );
1743+ ASSERT_GE (scheduler->schedule_count , 8 );
17441744}
17451745
17461746class throw_hub_protocol : public hub_protocol
@@ -1814,3 +1814,135 @@ TEST(send, throws_if_protocol_fails)
18141814
18151815 ASSERT_EQ (connection_state::connected, hub_connection->get_connection_state ());
18161816}
1817+
1818+ TEST (keepalive, sends_ping_messages)
1819+ {
1820+ signalr_client_config config;
1821+ config.set_keepalive_interval (std::chrono::seconds (1 ));
1822+ config.set_server_timeout (std::chrono::seconds (3 ));
1823+ auto ping_mre = manual_reset_event<void >();
1824+ auto messages = std::make_shared<std::deque<std::string>>();
1825+ auto websocket_client = create_test_websocket_client (
1826+ /* send function */ [messages, &ping_mre](const std::string& msg, std::function<void (std::exception_ptr)> callback)
1827+ {
1828+ if (messages->size () < 3 )
1829+ {
1830+ messages->push_back (msg);
1831+ }
1832+ if (messages->size () == 3 )
1833+ {
1834+ ping_mre.set ();
1835+ }
1836+ callback (nullptr );
1837+ },
1838+ [](const std::string&, std::function<void (std::exception_ptr)> callback) { callback (nullptr ); },
1839+ [](std::function<void (std::exception_ptr)> callback) { callback (nullptr ); },
1840+ false );
1841+ auto hub_connection = create_hub_connection (websocket_client);
1842+ hub_connection.set_client_config (config);
1843+
1844+ auto mre = manual_reset_event<void >();
1845+ hub_connection.start ([&mre](std::exception_ptr exception)
1846+ {
1847+ mre.set (exception);
1848+ });
1849+
1850+ ASSERT_FALSE (websocket_client->receive_loop_started .wait (5000 ));
1851+ ASSERT_FALSE (websocket_client->handshake_sent .wait (5000 ));
1852+ websocket_client->receive_message (" {}\x1e " );
1853+
1854+ mre.get ();
1855+
1856+ ping_mre.get ();
1857+
1858+ ASSERT_EQ (3 , messages->size ());
1859+ ASSERT_EQ (" {\" protocol\" :\" json\" ,\" version\" :1}\x1e " , (*messages)[0 ]);
1860+ ASSERT_EQ (" {\" type\" :6}\x1e " , (*messages)[1 ]);
1861+ ASSERT_EQ (" {\" type\" :6}\x1e " , (*messages)[2 ]);
1862+ ASSERT_EQ (connection_state::connected, hub_connection.get_connection_state ());
1863+ }
1864+
1865+ TEST (keepalive, server_timeout_on_no_ping_from_server)
1866+ {
1867+ signalr_client_config config;
1868+ config.set_keepalive_interval (std::chrono::seconds (1 ));
1869+ config.set_server_timeout (std::chrono::seconds (1 ));
1870+ auto websocket_client = create_test_websocket_client ();
1871+ auto hub_connection = create_hub_connection (websocket_client);
1872+ hub_connection.set_client_config (config);
1873+
1874+ auto disconnected_called = false ;
1875+
1876+ auto disconnect_mre = manual_reset_event<void >();
1877+ hub_connection.set_disconnected ([&disconnected_called, &disconnect_mre](std::exception_ptr ex)
1878+ {
1879+ disconnect_mre.set (ex);
1880+ });
1881+
1882+ auto mre = manual_reset_event<void >();
1883+ hub_connection.start ([&mre](std::exception_ptr exception)
1884+ {
1885+ mre.set (exception);
1886+ });
1887+
1888+ ASSERT_FALSE (websocket_client->receive_loop_started .wait (5000 ));
1889+ ASSERT_FALSE (websocket_client->handshake_sent .wait (5000 ));
1890+ websocket_client->receive_message (" {}\x1e " );
1891+
1892+ mre.get ();
1893+
1894+ try
1895+ {
1896+ disconnect_mre.get ();
1897+ ASSERT_TRUE (false );
1898+ }
1899+ catch (const std::exception& ex)
1900+ {
1901+ ASSERT_STREQ (" server timeout (1000 ms) elapsed without receiving a message from the server." , ex.what ());
1902+ }
1903+ ASSERT_EQ (connection_state::disconnected, hub_connection.get_connection_state ());
1904+ }
1905+
1906+ TEST (keepalive, resets_server_timeout_timer_on_any_message_from_server)
1907+ {
1908+ signalr_client_config config;
1909+ config.set_keepalive_interval (std::chrono::seconds (1 ));
1910+ config.set_server_timeout (std::chrono::seconds (1 ));
1911+ auto websocket_client = create_test_websocket_client ();
1912+ auto hub_connection = create_hub_connection (websocket_client);
1913+ hub_connection.set_client_config (config);
1914+
1915+ auto disconnect_mre = manual_reset_event<void >();
1916+ hub_connection.set_disconnected ([&disconnect_mre](std::exception_ptr ex)
1917+ {
1918+ disconnect_mre.set (ex);
1919+ });
1920+
1921+ auto mre = manual_reset_event<void >();
1922+ hub_connection.start ([&mre](std::exception_ptr exception)
1923+ {
1924+ mre.set (exception);
1925+ });
1926+
1927+ ASSERT_FALSE (websocket_client->receive_loop_started .wait (5000 ));
1928+ ASSERT_FALSE (websocket_client->handshake_sent .wait (5000 ));
1929+ websocket_client->receive_message (" {}\x1e " );
1930+
1931+ mre.get ();
1932+
1933+ std::this_thread::sleep_for (config.get_server_timeout () - std::chrono::milliseconds (500 ));
1934+ websocket_client->receive_message (" {\" type\" :6}\x1e " );
1935+ std::this_thread::sleep_for (std::chrono::seconds (1 ));
1936+ ASSERT_EQ (connection_state::connected, hub_connection.get_connection_state ());
1937+
1938+ try
1939+ {
1940+ disconnect_mre.get ();
1941+ ASSERT_TRUE (false );
1942+ }
1943+ catch (const std::exception& ex)
1944+ {
1945+ ASSERT_STREQ (" server timeout (1000 ms) elapsed without receiving a message from the server." , ex.what ());
1946+ }
1947+ ASSERT_EQ (connection_state::disconnected, hub_connection.get_connection_state ());
1948+ }
0 commit comments