From 591cdc179cd2c7de6862563e942295947021127d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Fri, 30 Oct 2020 14:33:34 -0400 Subject: [PATCH] connectionManager: add some tests Change-Id: I30883d1d43dd1c0c36be424b0937ecccb2100928 --- .../connectionManager/connectionManager.cpp | 283 ++++++++++++++---- 1 file changed, 231 insertions(+), 52 deletions(-) diff --git a/test/unitTest/connectionManager/connectionManager.cpp b/test/unitTest/connectionManager/connectionManager.cpp index 10b78b10ee..4c680fbc9a 100644 --- a/test/unitTest/connectionManager/connectionManager.cpp +++ b/test/unitTest/connectionManager/connectionManager.cpp @@ -66,6 +66,8 @@ private: void testChannelSenderShutdown(); void testCloseConnectionWithDevice(); void testShutdownCallbacks(); + void testFloodSocket(); + void testDestroyWhileSending(); CPPUNIT_TEST_SUITE(ConnectionManagerTest); CPPUNIT_TEST(testConnectDevice); @@ -80,6 +82,8 @@ private: CPPUNIT_TEST(testChannelSenderShutdown); CPPUNIT_TEST(testCloseConnectionWithDevice); CPPUNIT_TEST(testShutdownCallbacks); + CPPUNIT_TEST(testFloodSocket); + CPPUNIT_TEST(testDestroyWhileSending); CPPUNIT_TEST_SUITE_END(); }; @@ -142,12 +146,11 @@ ConnectionManagerTest::tearDown() std::unique_lock<std::mutex> lk {mtx}; std::condition_variable cv; auto currentAccSize = Manager::instance().getAccountList().size(); - confHandlers.insert( - DRing::exportable_callback<DRing::ConfigurationSignal::AccountsChanged>([&]() { - if (Manager::instance().getAccountList().size() <= currentAccSize - 2) { - cv.notify_one(); - } - })); + confHandlers.insert(DRing::exportable_callback<DRing::ConfigurationSignal::AccountsChanged>([&] { + if (Manager::instance().getAccountList().size() <= currentAccSize - 2) { + cv.notify_one(); + } + })); DRing::registerSignalHandlers(confHandlers); Manager::instance().removeAccount(aliceId, true); @@ -190,10 +193,9 @@ ConnectionManagerTest::testConnectDevice() } cv.notify_one(); }); - cvReceive.wait_for(lk, std::chrono::seconds(30)); - CPPUNIT_ASSERT(successfullyReceive); - cv.wait_for(lk, std::chrono::seconds(30)); - CPPUNIT_ASSERT(successfullyConnected); + CPPUNIT_ASSERT( + cvReceive.wait_for(lk, std::chrono::seconds(60), [&] { return successfullyReceive; })); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { return successfullyConnected; })); } void @@ -236,10 +238,9 @@ ConnectionManagerTest::testAcceptConnection() cv.notify_one(); }); - cv.wait_for(lk, std::chrono::seconds(30)); - CPPUNIT_ASSERT(successfullyReceive); - CPPUNIT_ASSERT(successfullyConnected); - CPPUNIT_ASSERT(receiverConnected); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { + return successfullyReceive && successfullyConnected && receiverConnected; + })); } void @@ -290,11 +291,9 @@ ConnectionManagerTest::testMultipleChannels() cv.notify_one(); }); - cv.wait_for(lk, std::chrono::seconds(30)); - cv.wait_for(lk, std::chrono::seconds(30)); - CPPUNIT_ASSERT(successfullyConnected); - CPPUNIT_ASSERT(successfullyConnected2); - CPPUNIT_ASSERT(receiverConnected == 2); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { + return successfullyConnected && successfullyConnected2 && receiverConnected == 2; + })); } void @@ -346,11 +345,9 @@ ConnectionManagerTest::testMultipleChannelsSameName() cv.notify_one(); }); - cv.wait_for(lk, std::chrono::seconds(30)); - cv.wait_for(lk, std::chrono::seconds(30)); - CPPUNIT_ASSERT(successfullyConnected); - CPPUNIT_ASSERT(successfullyConnected2); - CPPUNIT_ASSERT(receiverConnected == 2); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { + return successfullyConnected && successfullyConnected2 && receiverConnected == 2; + })); } void @@ -422,14 +419,10 @@ ConnectionManagerTest::testSendReceiveData() cv.notify_one(); }); - auto expiration = std::chrono::system_clock::now() + std::chrono::seconds(10); - cv.wait_until(lk, expiration, [&events]() { return events == 4; }); - CPPUNIT_ASSERT(successfullyReceive); - CPPUNIT_ASSERT(successfullyConnected); - CPPUNIT_ASSERT(successfullyConnected2); - CPPUNIT_ASSERT(receiverConnected); - CPPUNIT_ASSERT(dataOk); - CPPUNIT_ASSERT(dataOk2); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { + return events == 4 && successfullyReceive && successfullyConnected && successfullyConnected2 + && dataOk && dataOk2; + })); } void @@ -518,10 +511,9 @@ ConnectionManagerTest::testAcceptsICERequest() cv.notify_one(); }); - cv.wait_for(lk, std::chrono::seconds(30)); - CPPUNIT_ASSERT(successfullyReceive); - CPPUNIT_ASSERT(successfullyConnected); - CPPUNIT_ASSERT(receiverConnected); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { + return successfullyReceive && successfullyConnected && receiverConnected; + })); } void @@ -605,7 +597,7 @@ ConnectionManagerTest::testChannelRcvShutdown() "git://*", [&](std::shared_ptr<ChannelSocket> socket) { if (socket) { - socket->onShutdown([&]() { + socket->onShutdown([&] { shutdownReceived = true; scv.notify_one(); }); @@ -648,7 +640,7 @@ ConnectionManagerTest::testChannelSenderShutdown() bobAccount->connectionManager().onConnectionReady( [&](const DeviceId&, const std::string& name, std::shared_ptr<ChannelSocket> socket) { if (socket) { - socket->onShutdown([&]() { + socket->onShutdown([&] { shutdownReceived = true; scv.notify_one(); }); @@ -701,7 +693,7 @@ ConnectionManagerTest::testCloseConnectionWithDevice() bobAccount->connectionManager().onConnectionReady( [&](const DeviceId&, const std::string& name, std::shared_ptr<ChannelSocket> socket) { if (socket) { - socket->onShutdown([&]() { + socket->onShutdown([&] { events += 1; scv.notify_one(); }); @@ -713,7 +705,7 @@ ConnectionManagerTest::testCloseConnectionWithDevice() "git://*", [&](std::shared_ptr<ChannelSocket> socket) { if (socket) { - socket->onShutdown([&]() { + socket->onShutdown([&] { events += 1; scv.notify_one(); }); @@ -725,12 +717,9 @@ ConnectionManagerTest::testCloseConnectionWithDevice() rcv.wait_for(lk, std::chrono::seconds(30)); // This should trigger onShutdown aliceAccount->connectionManager().closeConnectionsWith(bobDeviceId); - auto expiration = std::chrono::system_clock::now() + std::chrono::seconds(10); - scv.wait_until(lk, expiration, [&events]() { return events == 2; }); - CPPUNIT_ASSERT(events == 2); - CPPUNIT_ASSERT(successfullyReceive); - CPPUNIT_ASSERT(successfullyConnected); - CPPUNIT_ASSERT(receiverConnected); + CPPUNIT_ASSERT(scv.wait_for(lk, std::chrono::seconds(60), [&] { + return events == 2 && successfullyReceive && successfullyConnected && receiverConnected; + })); } void @@ -777,10 +766,9 @@ ConnectionManagerTest::testShutdownCallbacks() } }); // Connect first channel. This will initiate a mx sock - rcv.wait_for(lk, std::chrono::seconds(30)); - CPPUNIT_ASSERT(successfullyReceive); - CPPUNIT_ASSERT(successfullyConnected); - CPPUNIT_ASSERT(receiverConnected); + CPPUNIT_ASSERT(rcv.wait_for(lk, std::chrono::seconds(30), [&] { + return successfullyReceive && successfullyConnected && receiverConnected; + })); // Connect another channel, but close the connection bool channel2NotConnected = false; @@ -794,8 +782,199 @@ ConnectionManagerTest::testShutdownCallbacks() // This should trigger onShutdown for second callback bobAccount->connectionManager().closeConnectionsWith(aliceDeviceId); - rcv.wait_for(lk, std::chrono::seconds(30)); - CPPUNIT_ASSERT(channel2NotConnected); + CPPUNIT_ASSERT(rcv.wait_for(lk, std::chrono::seconds(30), [&] { return channel2NotConnected; })); +} + +void +ConnectionManagerTest::testFloodSocket() +{ + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto bobDeviceId = DeviceId(bobAccount->getAccountDetails()[ConfProperties::RING_DEVICE_ID]); + bobAccount->connectionManager().onICERequest([](const DeviceId&) { return true; }); + aliceAccount->connectionManager().onICERequest([](const DeviceId&) { return true; }); + std::mutex mtx; + std::unique_lock<std::mutex> lk {mtx}; + std::condition_variable cv; + bool successfullyConnected = false; + bool successfullyReceive = false; + bool receiverConnected = false; + std::shared_ptr<ChannelSocket> rcvSock1, rcvSock2, rcvSock3, sendSock, sendSock2, sendSock3; + bobAccount->connectionManager().onChannelRequest( + [&successfullyReceive](const DeviceId&, const std::string& name) { + successfullyReceive = name == "1"; + return true; + }); + bobAccount->connectionManager().onConnectionReady( + [&](const DeviceId&, const std::string& name, std::shared_ptr<ChannelSocket> socket) { + receiverConnected = socket != nullptr; + if (name == "1") + rcvSock1 = socket; + else if (name == "2") + rcvSock2 = socket; + else if (name == "3") + rcvSock3 = socket; + }); + aliceAccount->connectionManager().connectDevice(bobDeviceId, + "1", + [&](std::shared_ptr<ChannelSocket> socket) { + if (socket) { + sendSock = socket; + successfullyConnected = true; + } + cv.notify_one(); + }); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { + return successfullyReceive && successfullyConnected && receiverConnected; + })); + CPPUNIT_ASSERT(receiverConnected); + successfullyConnected = false; + receiverConnected = false; + aliceAccount->connectionManager().connectDevice(bobDeviceId, + "2", + [&](std::shared_ptr<ChannelSocket> socket) { + if (socket) { + sendSock2 = socket; + successfullyConnected = true; + } + cv.notify_one(); + }); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { + return successfullyConnected && receiverConnected; + })); + successfullyConnected = false; + receiverConnected = false; + aliceAccount->connectionManager().connectDevice(bobDeviceId, + "3", + [&](std::shared_ptr<ChannelSocket> socket) { + if (socket) { + sendSock3 = socket; + successfullyConnected = true; + } + cv.notify_one(); + }); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { + return successfullyConnected && receiverConnected; + })); + std::mutex mtxRcv {}; + std::string alphabet, shouldRcv, rcv1, rcv2, rcv3; + for (int i = 0; i < 100; ++i) + alphabet += "QWERTYUIOPASDFGHJKLZXCVBNM"; + rcvSock1->setOnRecv([&](const uint8_t* buf, size_t len) { + rcv1 += std::string(buf, buf + len); + return len; + }); + rcvSock2->setOnRecv([&](const uint8_t* buf, size_t len) { + rcv2 += std::string(buf, buf + len); + return len; + }); + rcvSock3->setOnRecv([&](const uint8_t* buf, size_t len) { + rcv3 += std::string(buf, buf + len); + return len; + }); + for (uint64_t i = 0; i < alphabet.size(); ++i) { + auto send = std::string(8000, alphabet[i]); + shouldRcv += send; + std::error_code ec; + sendSock->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec); + sendSock2->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec); + sendSock3->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec); + CPPUNIT_ASSERT(!ec); + } + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { + return shouldRcv == rcv1 && shouldRcv == rcv2 && shouldRcv == rcv3; + })); +} + +void +ConnectionManagerTest::testDestroyWhileSending() +{ + // Same as test before, but destroy the accounts while sending. + // This test if a segfault occurs + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto bobDeviceId = DeviceId(bobAccount->getAccountDetails()[ConfProperties::RING_DEVICE_ID]); + bobAccount->connectionManager().onICERequest([](const DeviceId&) { return true; }); + aliceAccount->connectionManager().onICERequest([](const DeviceId&) { return true; }); + std::mutex mtx; + std::unique_lock<std::mutex> lk {mtx}; + std::condition_variable cv; + bool successfullyConnected = false; + bool successfullyReceive = false; + bool receiverConnected = false; + std::shared_ptr<ChannelSocket> rcvSock1, rcvSock2, rcvSock3, sendSock, sendSock2, sendSock3; + bobAccount->connectionManager().onChannelRequest( + [&successfullyReceive](const DeviceId&, const std::string& name) { + successfullyReceive = name == "1"; + return true; + }); + bobAccount->connectionManager().onConnectionReady( + [&](const DeviceId&, const std::string& name, std::shared_ptr<ChannelSocket> socket) { + receiverConnected = socket != nullptr; + if (name == "1") + rcvSock1 = socket; + else if (name == "2") + rcvSock2 = socket; + else if (name == "3") + rcvSock3 = socket; + }); + aliceAccount->connectionManager().connectDevice(bobDeviceId, + "1", + [&](std::shared_ptr<ChannelSocket> socket) { + if (socket) { + sendSock = socket; + successfullyConnected = true; + } + cv.notify_one(); + }); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { + return successfullyReceive && successfullyConnected && receiverConnected; + })); + successfullyConnected = false; + receiverConnected = false; + aliceAccount->connectionManager().connectDevice(bobDeviceId, + "2", + [&](std::shared_ptr<ChannelSocket> socket) { + if (socket) { + sendSock2 = socket; + successfullyConnected = true; + } + cv.notify_one(); + }); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { + return successfullyConnected && receiverConnected; + })); + successfullyConnected = false; + receiverConnected = false; + aliceAccount->connectionManager().connectDevice(bobDeviceId, + "3", + [&](std::shared_ptr<ChannelSocket> socket) { + if (socket) { + sendSock3 = socket; + successfullyConnected = true; + } + cv.notify_one(); + }); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { + return successfullyConnected && receiverConnected; + })); + std::mutex mtxRcv {}; + std::string alphabet; + for (int i = 0; i < 100; ++i) + alphabet += "QWERTYUIOPASDFGHJKLZXCVBNM"; + rcvSock1->setOnRecv([&](const uint8_t* buf, size_t len) { return len; }); + rcvSock2->setOnRecv([&](const uint8_t* buf, size_t len) { return len; }); + rcvSock3->setOnRecv([&](const uint8_t* buf, size_t len) { return len; }); + for (uint64_t i = 0; i < alphabet.size(); ++i) { + auto send = std::string(8000, alphabet[i]); + std::error_code ec; + sendSock->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec); + sendSock2->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec); + sendSock3->write(reinterpret_cast<unsigned char*>(send.data()), send.size(), ec); + CPPUNIT_ASSERT(!ec); + } + + // No need to wait, immediately destroy, no segfault must occurs } } // namespace test -- GitLab