From 5277f84208c112d2821d85c43271e11399efea4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Thu, 7 May 2020 14:57:26 -0400 Subject: [PATCH] tests: add some unit tests for calls Two tests are currently added. Just making a call (same device) via the old way and the new way (via the ConnectionManager). Change-Id: I109f79d2af0c4653fe83884171007a9d10d84a1f --- test/unitTest/Makefile.am | 8 +- test/unitTest/call/call.cpp | 246 ++++++++++++++++++ .../connectionManager/connectionManager.cpp | 1 + 3 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 test/unitTest/call/call.cpp diff --git a/test/unitTest/Makefile.am b/test/unitTest/Makefile.am index a5acff7bb1..579f29ff85 100644 --- a/test/unitTest/Makefile.am +++ b/test/unitTest/Makefile.am @@ -110,12 +110,16 @@ ut_video_scaler_SOURCES = media/video/test_video_scaler.cpp check_PROGRAMS += ut_audio_frame_resizer ut_audio_frame_resizer_SOURCES = media/audio/test_audio_frame_resizer.cpp +# +# call +# +check_PROGRAMS += ut_call +ut_call_SOURCES = call/call.cpp # # connectionManager # -#check_PROGRAMS += ut_connectionManager -check_PROGRAMS = ut_connectionManager +check_PROGRAMS += ut_connectionManager ut_connectionManager_SOURCES = connectionManager/connectionManager.cpp TESTS = $(check_PROGRAMS) \ No newline at end of file diff --git a/test/unitTest/call/call.cpp b/test/unitTest/call/call.cpp new file mode 100644 index 0000000000..6b86b98d3b --- /dev/null +++ b/test/unitTest/call/call.cpp @@ -0,0 +1,246 @@ + /* + * Copyright (C) 2020 Savoir-faire Linux Inc. + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <condition_variable> +#include <string> + +#include "manager.h" +#include "jamidht/connectionmanager.h" +#include "jamidht/jamiaccount.h" +#include "../../test_runner.h" +#include "dring.h" +#include "account_const.h" + +using namespace DRing::Account; + +namespace jami { namespace test { + +class CallTest : public CppUnit::TestFixture { +public: + CallTest() { + // Init daemon + DRing::init(DRing::InitFlag(DRing::DRING_FLAG_DEBUG | DRing::DRING_FLAG_CONSOLE_LOG)); + if (not Manager::instance().initialized) + CPPUNIT_ASSERT(DRing::start("dring-sample.yml")); + } + ~CallTest() { + DRing::fini(); + } + static std::string name() { return "Call"; } + void setUp(); + void tearDown(); + + std::string aliceId; + std::string bobId; + +private: + void testCall(); + void testCachedCall(); + + CPPUNIT_TEST_SUITE(CallTest); + CPPUNIT_TEST(testCall); + CPPUNIT_TEST(testCachedCall); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CallTest, CallTest::name()); + +void +CallTest::setUp() +{ + std::map<std::string, std::string> details = DRing::getAccountTemplate("RING"); + details[ConfProperties::TYPE] = "RING"; + details[ConfProperties::DISPLAYNAME] = "ALICE"; + details[ConfProperties::ALIAS] = "ALICE"; + details[ConfProperties::UPNP_ENABLED] = "true"; + details[ConfProperties::ARCHIVE_PASSWORD] = ""; + details[ConfProperties::ARCHIVE_PIN] = ""; + details[ConfProperties::ARCHIVE_PATH] = ""; + aliceId = Manager::instance().addAccount(details); + + details = DRing::getAccountTemplate("RING"); + details[ConfProperties::TYPE] = "RING"; + details[ConfProperties::DISPLAYNAME] = "BOB"; + details[ConfProperties::ALIAS] = "BOB"; + details[ConfProperties::UPNP_ENABLED] = "true"; + details[ConfProperties::ARCHIVE_PASSWORD] = ""; + details[ConfProperties::ARCHIVE_PIN] = ""; + details[ConfProperties::ARCHIVE_PATH] = ""; + bobId = Manager::instance().addAccount(details); + + JAMI_INFO("Initialize account..."); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>> confHandlers; + std::mutex mtx; + std::unique_lock<std::mutex> lk{ mtx }; + std::condition_variable cv; + std::atomic_bool accountsReady {false}; + confHandlers.insert(DRing::exportable_callback<DRing::ConfigurationSignal::VolatileDetailsChanged>( + [&](const std::string&, const std::map<std::string, std::string>&) { + bool ready = false; + auto details = aliceAccount->getVolatileAccountDetails(); + auto daemonStatus = details[DRing::Account::ConfProperties::Registration::STATUS]; + ready = (daemonStatus == "REGISTERED"); + details = bobAccount->getVolatileAccountDetails(); + daemonStatus = details[DRing::Account::ConfProperties::Registration::STATUS]; + ready &= (daemonStatus == "REGISTERED"); + if (ready) { + accountsReady = true; + cv.notify_one(); + } + })); + DRing::registerSignalHandlers(confHandlers); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]{ return accountsReady.load(); })); + DRing::unregisterSignalHandlers(); +} + +void +CallTest::tearDown() +{ + JAMI_INFO("Remove created accounts..."); + + std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>> confHandlers; + std::mutex mtx; + std::unique_lock<std::mutex> lk{ mtx }; + std::condition_variable cv; + auto currentAccSize = Manager::instance().getAccountList().size(); + std::atomic_bool accountsRemoved {false}; + confHandlers.insert(DRing::exportable_callback<DRing::ConfigurationSignal::AccountsChanged>( + [&]() { + if (Manager::instance().getAccountList().size() <= currentAccSize - 2) { + accountsRemoved = true; + cv.notify_one(); + } + })); + DRing::registerSignalHandlers(confHandlers); + + Manager::instance().removeAccount(aliceId, true); + Manager::instance().removeAccount(bobId, true); + // Because cppunit is not linked with dbus, just poll if removed + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]{ return accountsRemoved.load(); })); + + DRing::unregisterSignalHandlers(); +} + +void +CallTest::testCall() +{ + // TODO remove. This sleeps is because it take some time for the DHT to be connected + // and account announced + JAMI_INFO("Waiting...."); + std::this_thread::sleep_for(std::chrono::seconds(5)); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto bobUri = bobAccount->getAccountDetails()[ConfProperties::USERNAME]; + auto aliceUri = aliceAccount->getAccountDetails()[ConfProperties::USERNAME]; + + std::mutex mtx; + std::unique_lock<std::mutex> lk{ mtx }; + std::condition_variable cv; + std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>> confHandlers; + std::atomic_bool callReceived {false}; + std::atomic<int> callStopped {0}; + // Watch signals + confHandlers.insert(DRing::exportable_callback<DRing::CallSignal::IncomingCall>( + [&](const std::string&, const std::string&, const std::string&) { + callReceived = true; + cv.notify_one(); + })); + confHandlers.insert(DRing::exportable_callback<DRing::CallSignal::StateChange>( + [&](const std::string&, const std::string& state, signed) { + if (state == "OVER") { + callStopped += 1; + if (callStopped == 2) + cv.notify_one(); + } + })); + DRing::registerSignalHandlers(confHandlers); + + JAMI_INFO("Start call between alice and Bob"); + auto call = aliceAccount->newOutgoingCall(bobUri, {}); + + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]{ return callReceived.load(); })); + + JAMI_INFO("Stop call between alice and Bob"); + callStopped = 0; + Manager::instance().hangupCall(call->getCallId()); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]{ return callStopped == 2; })); +} + +void +CallTest::testCachedCall() +{ + std::this_thread::sleep_for(std::chrono::seconds(5)); + // TODO remove. This sleeps is because it take some time for the DHT to be connected + // and account announced + JAMI_INFO("Waiting...."); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto bobUri = bobAccount->getAccountDetails()[ConfProperties::USERNAME]; + auto bobDeviceId = bobAccount->getAccountDetails()[ConfProperties::RING_DEVICE_ID]; + auto aliceUri = aliceAccount->getAccountDetails()[ConfProperties::USERNAME]; + + std::mutex mtx; + std::unique_lock<std::mutex> lk{ mtx }; + std::condition_variable cv; + std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>> confHandlers; + std::atomic_bool callReceived {false}, successfullyConnected {false}; + std::atomic<int> callStopped {0}; + // Watch signals + confHandlers.insert(DRing::exportable_callback<DRing::CallSignal::IncomingCall>( + [&](const std::string&, const std::string&, const std::string&) { + callReceived = true; + cv.notify_one(); + })); + confHandlers.insert(DRing::exportable_callback<DRing::CallSignal::StateChange>( + [&](const std::string&, const std::string& state, signed) { + if (state == "OVER") { + callStopped += 1; + if (callStopped == 2) + cv.notify_one(); + } + })); + DRing::registerSignalHandlers(confHandlers); + + JAMI_INFO("Connect Alice's device and Bob's device"); + aliceAccount->connectionManager().connectDevice(bobDeviceId, "sip", + [&cv, &successfullyConnected](std::shared_ptr<ChannelSocket> socket) { + if (socket) + successfullyConnected = true; + cv.notify_one(); + }); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]{ return successfullyConnected.load(); })); + + JAMI_INFO("Start call between alice and Bob"); + auto call = aliceAccount->newOutgoingCall(bobUri, {}); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]{ return callReceived.load(); })); + + callStopped = 0; + JAMI_INFO("Stop call between alice and Bob"); + Manager::instance().hangupCall(call->getCallId()); + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]{ return callStopped == 2; })); +} + +}} // namespace test + +RING_TEST_RUNNER(jami::test::CallTest::name()) \ No newline at end of file diff --git a/test/unitTest/connectionManager/connectionManager.cpp b/test/unitTest/connectionManager/connectionManager.cpp index e6a4a02156..39bfba91ba 100644 --- a/test/unitTest/connectionManager/connectionManager.cpp +++ b/test/unitTest/connectionManager/connectionManager.cpp @@ -24,6 +24,7 @@ #include "manager.h" #include "jamidht/connectionmanager.h" +#include "jamidht/multiplexed_socket.h" #include "jamidht/jamiaccount.h" #include "../../test_runner.h" #include "dring.h" -- GitLab