Skip to content
Snippets Groups Projects
Commit a835266f authored by Aline Gondim Santos's avatar Aline Gondim Santos
Browse files

unittest: add plugins

Create a minimal test for the plugins system.

GitLab: #745

Change-Id: I17d48860ce24cfdc5423d4dcc3cb44bb4d4531f6
parent 0b652eb7
Branches
No related tags found
No related merge requests found
...@@ -31,7 +31,9 @@ ...@@ -31,7 +31,9 @@
#include <mutex> #include <mutex>
#include <functional> #include <functional>
#include <ciso646> // fix windows compiler bug #include <ciso646> // fix windows compiler bug
#ifndef __DEBUG__ // this is only defined on plugins build for debugging
#include "logger.h" #include "logger.h"
#endif
namespace jami { namespace jami {
...@@ -127,7 +129,9 @@ protected: ...@@ -127,7 +129,9 @@ protected:
try { try {
so->update(this, data); so->update(this, data);
} catch (std::exception& e) { } catch (std::exception& e) {
#ifndef __DEBUG__
JAMI_ERR() << e.what(); JAMI_ERR() << e.what();
#endif
} }
} else { } else {
it = priority_observers_.erase(it); it = priority_observers_.erase(it);
......
...@@ -70,7 +70,7 @@ struct JamiMessage ...@@ -70,7 +70,7 @@ struct JamiMessage
/** /**
* @param accId AccountId * @param accId AccountId
* @param pId peerId * @param pId peerId
* @param isReceived False if local audio/video streams * @param isReceived True if received message, False if sent
* @param dataMap Message contents * @param dataMap Message contents
* @param pPlugin True if message is created/modified by plugin code * @param pPlugin True if message is created/modified by plugin code
*/ */
......
...@@ -452,4 +452,15 @@ if conf.get('ENABLE_VIDEO') ...@@ -452,4 +452,15 @@ if conf.get('ENABLE_VIDEO')
test('video_scaler', ut_video_scaler, test('video_scaler', ut_video_scaler,
workdir: ut_workdir, is_parallel: false, timeout: 1800 workdir: ut_workdir, is_parallel: false, timeout: 1800
) )
ut_plugins = executable('ut_plugins',
sources: files('unitTest/plugins/plugins.cpp'),
include_directories: ut_includedirs,
dependencies: ut_dependencies,
link_with: ut_library
)
test('plugins', ut_plugins,
workdir: ut_workdir, is_parallel: false, timeout: 1800
)
endif endif
...@@ -226,5 +226,10 @@ ut_sip_empty_offer_SOURCES = sip_account/sip_empty_offer.cpp ...@@ -226,5 +226,10 @@ ut_sip_empty_offer_SOURCES = sip_account/sip_empty_offer.cpp
check_PROGRAMS += ut_sip_srtp check_PROGRAMS += ut_sip_srtp
ut_sip_srtp_SOURCES = sip_account/sip_srtp.cpp ut_sip_srtp_SOURCES = sip_account/sip_srtp.cpp
#
# Plugins
#
check_PROGRAMS += ut_plugins
ut_plugins_SOURCES = plugins/plugins.cpp common.cpp
TESTS = $(check_PROGRAMS) TESTS = $(check_PROGRAMS)
COPYRIGHT NOTICE
Copyright (C) 2022 Savoir-faire Linux Inc.
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 <http://www.gnu.org/licenses/>.
plugin.yml
----------
The test configuration file can specify:
* jplDirectory - relative to the test executable or a full path;
* plugin - the plugin name;
* mediaHandlers - present media handlers names in the plugin;
* chatHandlers - present chat handlers names in the plugin;
The default test plugin is TestSuite.
Test plugin build
-----------------
For the CI tests, which uses a Ubuntu 20.04 docker, the test suite must be build with an appropriate glibc version, meaning a glib 3.31 or older.
Jami supports systems from Ubuntu 18.04, which uses glib 2.27.
If the plugin is build within a Ubuntu 18.04, it should work on all Jami supported platforms.
TO check your system glib version: `ldd --version`
File added
jplDirectory:
"plugins"
plugin:
"TestSuite"
mediaHandlers:
- "AudioHandlerTester"
- "VideoHandlerTester"
chatHandlers:
- "ChatHandlerTester"
/*
* Copyright (C) 2022 Savoir-faire Linux Inc.
* Author: Aline Gondim Santos <aline.gondimsantos@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 <filesystem>
#include <string>
#include "manager.h"
#include "plugin/jamipluginmanager.h"
#include "jamidht/jamiaccount.h"
#include "../../test_runner.h"
#include "jami.h"
#include "fileutils.h"
#include "jami/media_const.h"
#include "account_const.h"
#include "sip/sipcall.h"
#include "call_const.h"
#include "common.h"
using namespace DRing::Account;
namespace jami {
namespace test {
struct CallData
{
struct Signal
{
Signal(const std::string& name, const std::string& event = {})
: name_(std::move(name))
, event_(std::move(event)) {};
std::string name_ {};
std::string event_ {};
};
CallData() = default;
CallData(CallData&& other) = delete;
CallData(const CallData& other)
{
accountId_ = std::move(other.accountId_);
listeningPort_ = other.listeningPort_;
userName_ = std::move(other.userName_);
alias_ = std::move(other.alias_);
callId_ = std::move(other.callId_);
signals_ = std::move(other.signals_);
};
std::string accountId_ {};
std::string userName_ {};
std::string alias_ {};
uint16_t listeningPort_ {0};
std::string toUri_ {};
std::string callId_ {};
std::vector<Signal> signals_;
std::condition_variable cv_ {};
std::mutex mtx_;
};
class PluginsTest : public CppUnit::TestFixture
{
public:
PluginsTest()
{
// Init daemon
DRing::init(DRing::InitFlag(DRing::DRING_FLAG_DEBUG | DRing::DRING_FLAG_CONSOLE_LOG));
if (not Manager::instance().initialized)
CPPUNIT_ASSERT(DRing::start("jami-sample.yml"));
}
~PluginsTest() { DRing::fini(); }
static std::string name() { return "Plugins"; }
void setUp();
void tearDown();
CallData aliceData;
CallData bobData;
private:
static bool waitForSignal(CallData& callData,
const std::string& signal,
const std::string& expectedEvent = {});
// Event/Signal handlers
static void onCallStateChange(const std::string& accountId,
const std::string& callId,
const std::string& state,
CallData& callData);
static void onIncomingCallWithMedia(const std::string& accountId,
const std::string& callId,
const std::vector<DRing::MediaMap> mediaList,
CallData& callData);
std::string name_{};
std::string jplPath_{};
std::string installationPath_{};
std::vector<std::string> mediaHandlers_{};
std::vector<std::string> chatHandlers_{};
void testEnable();
void testInstallAndLoad();
void testHandlers();
void testDetailsAndPreferences();
void testCall();
void testMessage();
CPPUNIT_TEST_SUITE(PluginsTest);
CPPUNIT_TEST(testEnable);
CPPUNIT_TEST(testInstallAndLoad);
CPPUNIT_TEST(testHandlers);
CPPUNIT_TEST(testDetailsAndPreferences);
CPPUNIT_TEST(testCall);
CPPUNIT_TEST(testMessage);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(PluginsTest, PluginsTest::name());
void
PluginsTest::onIncomingCallWithMedia(const std::string& accountId,
const std::string& callId,
const std::vector<DRing::MediaMap> mediaList,
CallData& callData)
{
CPPUNIT_ASSERT_EQUAL(callData.accountId_, accountId);
JAMI_INFO("Signal [%s] - user [%s] - call [%s] - media count [%lu]",
DRing::CallSignal::IncomingCallWithMedia::name,
callData.alias_.c_str(),
callId.c_str(),
mediaList.size());
// NOTE.
// We shouldn't access shared_ptr<Call> as this event is supposed to mimic
// the client, and the client have no access to this type. But here, we only
// needed to check if the call exists. This is the most straightforward and
// reliable way to do it until we add a new API (like hasCall(id)).
if (not Manager::instance().getCallFromCallID(callId)) {
JAMI_WARN("Call with ID [%s] does not exist!", callId.c_str());
callData.callId_ = {};
return;
}
std::unique_lock<std::mutex> lock {callData.mtx_};
callData.callId_ = callId;
callData.signals_.emplace_back(CallData::Signal(DRing::CallSignal::IncomingCallWithMedia::name));
callData.cv_.notify_one();
}
void
PluginsTest::onCallStateChange(const std::string& accountId,
const std::string& callId,
const std::string& state,
CallData& callData)
{
JAMI_INFO("Signal [%s] - user [%s] - call [%s] - state [%s]",
DRing::CallSignal::StateChange::name,
callData.alias_.c_str(),
callId.c_str(),
state.c_str());
CPPUNIT_ASSERT(accountId == callData.accountId_);
{
std::unique_lock<std::mutex> lock {callData.mtx_};
callData.signals_.emplace_back(
CallData::Signal(DRing::CallSignal::StateChange::name, state));
}
// NOTE. Only states that we are interested in will notify the CV.
// If this unit test is modified to process other states, they must
// be added here.
if (state == "CURRENT" or state == "OVER" or state == "HUNGUP" or state == "RINGING") {
callData.cv_.notify_one();
}
}
void
PluginsTest::setUp()
{
auto actors = load_actors_and_wait_for_announcement("actors/alice-bob-no-upnp.yml");
aliceData.accountId_ = actors["alice"];
bobData.accountId_ = actors["bob"];
// Configure Alice
{
CPPUNIT_ASSERT(not aliceData.accountId_.empty());
auto const& account = Manager::instance().getAccount<Account>(
aliceData.accountId_);
aliceData.userName_ = account->getAccountDetails()[ConfProperties::USERNAME];
aliceData.alias_ = account->getAccountDetails()[ConfProperties::ALIAS];
account->enableIceForMedia(true);
}
// Configure Bob
{
CPPUNIT_ASSERT(not bobData.accountId_.empty());
auto const& account = Manager::instance().getAccount<Account>(
bobData.accountId_);
bobData.userName_ = account->getAccountDetails()[ConfProperties::USERNAME];
bobData.alias_ = account->getAccountDetails()[ConfProperties::ALIAS];
account->enableIceForMedia(true);
}
std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>> signalHandlers;
// Insert needed signal handlers.
signalHandlers.insert(DRing::exportable_callback<DRing::CallSignal::IncomingCallWithMedia>(
[&](const std::string& accountId,
const std::string& callId,
const std::string&,
const std::vector<DRing::MediaMap> mediaList) {
if (aliceData.accountId_ == accountId)
onIncomingCallWithMedia(accountId, callId, mediaList, aliceData);
else if (bobData.accountId_ == accountId)
onIncomingCallWithMedia(accountId, callId, mediaList, bobData);
}));
signalHandlers.insert(
DRing::exportable_callback<DRing::CallSignal::StateChange>([&](const std::string& accountId,
const std::string& callId,
const std::string& state,
signed) {
if (aliceData.accountId_ == accountId)
onCallStateChange(accountId, callId, state, aliceData);
else if (bobData.accountId_ == accountId)
onCallStateChange(accountId, callId, state, bobData);
}));
DRing::registerSignalHandlers(signalHandlers);
std::ifstream file = jami::fileutils::ifstream("plugins/plugin.yml");
assert(file.is_open());
YAML::Node node = YAML::Load(file);
assert(node.IsMap());
name_ = node["plugin"].as<std::string>();
jplPath_ = node["jplDirectory"].as<std::string>() + DIR_SEPARATOR_CH + name_ + ".jpl";
installationPath_ = fileutils::get_data_dir() + DIR_SEPARATOR_CH + "plugins" + DIR_SEPARATOR_CH + name_;
mediaHandlers_ = node["mediaHandlers"].as<std::vector<std::string>>();
chatHandlers_ = node["chatHandlers"].as<std::vector<std::string>>();
}
void
PluginsTest::tearDown()
{
DRing::unregisterSignalHandlers();
wait_for_removal_of({aliceData.accountId_, bobData.accountId_});
}
void
PluginsTest::testEnable()
{
Manager::instance().pluginPreferences.setPluginsEnabled(true);
CPPUNIT_ASSERT(Manager::instance().pluginPreferences.getPluginsEnabled());
Manager::instance().pluginPreferences.setPluginsEnabled(false);
CPPUNIT_ASSERT(!Manager::instance().pluginPreferences.getPluginsEnabled());
}
void
PluginsTest::testInstallAndLoad()
{
Manager::instance().pluginPreferences.setPluginsEnabled(true);
CPPUNIT_ASSERT(!Manager::instance().getJamiPluginManager().installPlugin(jplPath_, true));
auto installedPlugins = Manager::instance().getJamiPluginManager().getInstalledPlugins();
CPPUNIT_ASSERT(!installedPlugins.empty());
CPPUNIT_ASSERT(std::find(installedPlugins.begin(),
installedPlugins.end(),
installationPath_)
!= installedPlugins.end());
auto loadedPlugins = Manager::instance().getJamiPluginManager().getLoadedPlugins();
CPPUNIT_ASSERT(!loadedPlugins.empty());
CPPUNIT_ASSERT(std::find(loadedPlugins.begin(),
loadedPlugins.end(),
installationPath_)
!= loadedPlugins.end());
CPPUNIT_ASSERT(Manager::instance().getJamiPluginManager().unloadPlugin(installationPath_));
loadedPlugins = Manager::instance().getJamiPluginManager().getLoadedPlugins();
CPPUNIT_ASSERT(std::find(loadedPlugins.begin(),
loadedPlugins.end(),
installationPath_)
== loadedPlugins.end());
CPPUNIT_ASSERT(!Manager::instance().getJamiPluginManager().uninstallPlugin(installationPath_));
installedPlugins = Manager::instance().getJamiPluginManager().getInstalledPlugins();
CPPUNIT_ASSERT(std::find(installedPlugins.begin(),
installedPlugins.end(),
installationPath_)
== installedPlugins.end());
}
void
PluginsTest::testHandlers()
{
Manager::instance().pluginPreferences.setPluginsEnabled(true);
Manager::instance().getJamiPluginManager().installPlugin(jplPath_, true);
auto mediaHandlers = Manager::instance().getJamiPluginManager().getCallServicesManager().getCallMediaHandlers();
auto chatHandlers = Manager::instance().getJamiPluginManager().getChatServicesManager().getChatHandlers();
auto handlerLoaded = mediaHandlers_.size() + chatHandlers_.size(); // number of handlers expected
for (auto handler : mediaHandlers)
{
auto details = Manager::instance().getJamiPluginManager().getCallServicesManager().getCallMediaHandlerDetails(handler);
// check details expected for the test plugin
if(std::find(mediaHandlers_.begin(),
mediaHandlers_.end(),
details["name"])
!= mediaHandlers_.end()) {
handlerLoaded--;
}
}
for (auto handler : chatHandlers)
{
auto details = Manager::instance().getJamiPluginManager().getChatServicesManager().getChatHandlerDetails(handler);
// check details expected for the test plugin
if(std::find(chatHandlers_.begin(),
chatHandlers_.end(),
details["name"])
!= chatHandlers_.end()) {
handlerLoaded--;
}
}
CPPUNIT_ASSERT(!handlerLoaded); // All expected handlers were found
CPPUNIT_ASSERT(!Manager::instance().getJamiPluginManager().uninstallPlugin(installationPath_));
}
void
PluginsTest::testDetailsAndPreferences()
{
Manager::instance().pluginPreferences.setPluginsEnabled(true);
Manager::instance().getJamiPluginManager().installPlugin(jplPath_, true);
// Unload now to avoid reloads when changing the preferences
Manager::instance().getJamiPluginManager().unloadPlugin(installationPath_);
// Details
auto details = Manager::instance().getJamiPluginManager().getPluginDetails(installationPath_);
CPPUNIT_ASSERT(details["name"] == name_);
// Get-set-reset - no account
auto preferences = Manager::instance().getJamiPluginManager().getPluginPreferences(installationPath_, "");
CPPUNIT_ASSERT(!preferences.empty());
auto preferencesValuesOrig = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, "");
std::string preferenceNewValue = aliceData.accountId_;
auto key = preferences[0]["key"];
CPPUNIT_ASSERT(Manager::instance().getJamiPluginManager().setPluginPreference(installationPath_, "", key, preferenceNewValue));
// Test global preference change
auto preferencesValuesNew = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, "");
CPPUNIT_ASSERT(preferencesValuesOrig[key] != preferencesValuesNew[key]);
CPPUNIT_ASSERT(preferencesValuesNew[key] == preferenceNewValue);
// Test global preference change in an account
preferencesValuesNew = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, aliceData.accountId_);
CPPUNIT_ASSERT(preferencesValuesOrig[key] != preferencesValuesNew[key]);
CPPUNIT_ASSERT(preferencesValuesNew[key] == preferenceNewValue);
// Test reset global preference change
Manager::instance().getJamiPluginManager().resetPluginPreferencesValuesMap(installationPath_, "");
preferencesValuesNew = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, "");
CPPUNIT_ASSERT(preferencesValuesOrig[key] == preferencesValuesNew[key]);
CPPUNIT_ASSERT(preferencesValuesNew[key] != preferenceNewValue);
// Get-set-reset - alice account
preferences = Manager::instance().getJamiPluginManager().getPluginPreferences(installationPath_, aliceData.accountId_);
CPPUNIT_ASSERT(!preferences.empty());
preferencesValuesOrig = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, aliceData.accountId_);
auto preferencesValuesBobOrig = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, bobData.accountId_);
key = preferences[0]["key"];
CPPUNIT_ASSERT(Manager::instance().getJamiPluginManager().setPluginPreference(installationPath_, aliceData.accountId_, key, preferenceNewValue));
// Test account preference change
preferencesValuesNew = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, aliceData.accountId_);
auto preferencesValuesBobNew = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, bobData.accountId_);
CPPUNIT_ASSERT(preferencesValuesBobNew[key] == preferencesValuesBobOrig[key]);
CPPUNIT_ASSERT(preferencesValuesOrig[key] != preferencesValuesNew[key]);
CPPUNIT_ASSERT(preferencesValuesOrig[key] == preferencesValuesBobOrig[key]);
CPPUNIT_ASSERT(preferencesValuesNew[key] != preferencesValuesBobOrig[key]);
CPPUNIT_ASSERT(preferencesValuesNew[key] == preferenceNewValue);
// Test account preference change with global preference reset
Manager::instance().getJamiPluginManager().resetPluginPreferencesValuesMap(installationPath_, "");
preferencesValuesNew = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, aliceData.accountId_);
preferencesValuesBobNew = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, bobData.accountId_);
CPPUNIT_ASSERT(preferencesValuesBobNew[key] == preferencesValuesBobOrig[key]);
CPPUNIT_ASSERT(preferencesValuesOrig[key] != preferencesValuesNew[key]);
CPPUNIT_ASSERT(preferencesValuesOrig[key] == preferencesValuesBobOrig[key]);
CPPUNIT_ASSERT(preferencesValuesNew[key] != preferencesValuesBobOrig[key]);
CPPUNIT_ASSERT(preferencesValuesNew[key] == preferenceNewValue);
// Test account preference reset
Manager::instance().getJamiPluginManager().resetPluginPreferencesValuesMap(installationPath_, aliceData.accountId_);
preferencesValuesNew = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, aliceData.accountId_);
preferencesValuesBobNew = Manager::instance().getJamiPluginManager().getPluginPreferencesValuesMap(installationPath_, bobData.accountId_);
CPPUNIT_ASSERT(preferencesValuesBobNew[key] == preferencesValuesBobOrig[key]);
CPPUNIT_ASSERT(preferencesValuesOrig[key] == preferencesValuesNew[key]);
CPPUNIT_ASSERT(preferencesValuesOrig[key] == preferencesValuesBobOrig[key]);
CPPUNIT_ASSERT(preferencesValuesNew[key] == preferencesValuesBobOrig[key]);
CPPUNIT_ASSERT(preferencesValuesNew[key] != preferenceNewValue);
// Test translations
CPPUNIT_ASSERT(!Manager::instance().getJamiPluginManager().uninstallPlugin(installationPath_));
}
bool
PluginsTest::waitForSignal(CallData& callData,
const std::string& expectedSignal,
const std::string& expectedEvent)
{
const std::chrono::seconds TIME_OUT {30};
std::unique_lock<std::mutex> lock {callData.mtx_};
// Combined signal + event (if any).
std::string sigEvent(expectedSignal);
if (not expectedEvent.empty())
sigEvent += "::" + expectedEvent;
JAMI_INFO("[%s] is waiting for [%s] signal/event", callData.alias_.c_str(), sigEvent.c_str());
auto res = callData.cv_.wait_for(lock, TIME_OUT, [&] {
// Search for the expected signal in list of received signals.
bool pred = false;
for (auto it = callData.signals_.begin(); it != callData.signals_.end(); it++) {
// The predicate is true if the signal names match, and if the
// expectedEvent is not empty, the events must also match.
if (it->name_ == expectedSignal
and (expectedEvent.empty() or it->event_ == expectedEvent)) {
pred = true;
// Done with this signal.
callData.signals_.erase(it);
break;
}
}
return pred;
});
if (not res) {
JAMI_ERR("[%s] waiting for signal/event [%s] timed-out!",
callData.alias_.c_str(),
sigEvent.c_str());
JAMI_INFO("[%s] currently has the following signals:", callData.alias_.c_str());
for (auto const& sig : callData.signals_) {
JAMI_INFO() << "\tSignal [" << sig.name_
<< (sig.event_.empty() ? "" : ("::" + sig.event_)) << "]";
}
}
return res;
}
void
PluginsTest::testCall()
{
Manager::instance().pluginPreferences.setPluginsEnabled(true);
Manager::instance().getJamiPluginManager().installPlugin(jplPath_, true);
// alice calls bob
// for handler available, toggle - check status - untoggle - checkstatus
// end call
MediaAttribute defaultAudio(MediaType::MEDIA_AUDIO);
defaultAudio.label_ = "audio_0";
defaultAudio.enabled_ = true;
MediaAttribute defaultVideo(MediaType::MEDIA_VIDEO);
defaultVideo.label_ = "video_0";
defaultVideo.enabled_ = true;
std::vector<MediaAttribute> request;
std::vector<MediaAttribute> answer;
// First offer/answer
request.emplace_back(MediaAttribute(defaultAudio));
request.emplace_back(MediaAttribute(defaultVideo));
answer.emplace_back(MediaAttribute(defaultAudio));
answer.emplace_back(MediaAttribute(defaultVideo));
JAMI_INFO("Start call between alice and Bob");
aliceData.callId_ = DRing::placeCallWithMedia(aliceData.accountId_, bobData.userName_, MediaAttribute::mediaAttributesToMediaMaps(request));
CPPUNIT_ASSERT(not aliceData.callId_.empty());
auto aliceCall = std::static_pointer_cast<SIPCall>(
Manager::instance().getCallFromCallID(aliceData.callId_));
CPPUNIT_ASSERT(aliceCall);
aliceData.callId_ = aliceCall->getCallId();
JAMI_INFO("ALICE [%s] started a call with BOB [%s] and wait for answer",
aliceData.accountId_.c_str(),
bobData.accountId_.c_str());
// Wait for incoming call signal.
CPPUNIT_ASSERT(waitForSignal(bobData, DRing::CallSignal::IncomingCallWithMedia::name));
// Answer the call.
{
DRing::acceptWithMedia(bobData.accountId_, bobData.callId_, MediaAttribute::mediaAttributesToMediaMaps(answer));
}
CPPUNIT_ASSERT_EQUAL(true,
waitForSignal(bobData,
DRing::CallSignal::StateChange::name,
DRing::Call::StateEvent::CURRENT));
JAMI_INFO("BOB answered the call [%s]", bobData.callId_.c_str());
std::this_thread::sleep_for(std::chrono::seconds(3));
auto mediaHandlers = Manager::instance().getJamiPluginManager().getCallServicesManager().getCallMediaHandlers();
for (auto handler : mediaHandlers)
{
auto details = Manager::instance().getJamiPluginManager().getCallServicesManager().getCallMediaHandlerDetails(handler);
// check details expected for the test plugin
if(std::find(mediaHandlers_.begin(),
mediaHandlers_.end(),
details["name"])
!= mediaHandlers_.end()) {
Manager::instance().getJamiPluginManager().getCallServicesManager().toggleCallMediaHandler(handler, aliceData.callId_, true);
auto statusMap = Manager::instance().getJamiPluginManager().getCallServicesManager().getCallMediaHandlerStatus(aliceData.callId_);
CPPUNIT_ASSERT(std::find(statusMap.begin(), statusMap.end(), handler) != statusMap.end());
Manager::instance().getJamiPluginManager().getCallServicesManager().toggleCallMediaHandler(handler, aliceData.callId_, false);
statusMap = Manager::instance().getJamiPluginManager().getCallServicesManager().getCallMediaHandlerStatus(aliceData.callId_);
CPPUNIT_ASSERT(std::find(statusMap.begin(), statusMap.end(), handler) == statusMap.end());
}
}
std::this_thread::sleep_for(std::chrono::seconds(3));
// Bob hang-up.
JAMI_INFO("Hang up BOB's call and wait for ALICE to hang up");
DRing::hangUp(bobData.accountId_, bobData.callId_);
CPPUNIT_ASSERT_EQUAL(true,
waitForSignal(aliceData,
DRing::CallSignal::StateChange::name,
DRing::Call::StateEvent::HUNGUP));
JAMI_INFO("Call terminated on both sides");
CPPUNIT_ASSERT(!Manager::instance().getJamiPluginManager().uninstallPlugin(installationPath_));
}
void
PluginsTest::testMessage()
{
Manager::instance().pluginPreferences.setPluginsEnabled(true);
Manager::instance().getJamiPluginManager().installPlugin(jplPath_, true);
// alice and bob chat
// for handler available, toggle - check status - untoggle - checkstatus
// end call
std::mutex mtx;
std::unique_lock<std::mutex> lk {mtx};
std::condition_variable cv;
std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>> confHandlers;
auto messageBobReceived = 0, messageAliceReceived = 0;
bool requestReceived = false;
bool conversationReady = false;
confHandlers.insert(DRing::exportable_callback<DRing::ConversationSignal::MessageReceived>(
[&](const std::string& accountId,
const std::string& /* conversationId */,
std::map<std::string, std::string> /*message*/) {
if (accountId == bobData.accountId_) {
messageBobReceived += 1;
} else {
messageAliceReceived += 1;
}
cv.notify_one();
}));
confHandlers.insert(
DRing::exportable_callback<DRing::ConversationSignal::ConversationRequestReceived>(
[&](const std::string& /*accountId*/,
const std::string& /* conversationId */,
std::map<std::string, std::string> /*metadatas*/) {
requestReceived = true;
cv.notify_one();
}));
confHandlers.insert(DRing::exportable_callback<DRing::ConversationSignal::ConversationReady>(
[&](const std::string& accountId, const std::string& /* conversationId */) {
if (accountId == bobData.accountId_) {
conversationReady = true;
cv.notify_one();
}
}));
DRing::registerSignalHandlers(confHandlers);
auto convId = DRing::startConversation(aliceData.accountId_);
DRing::addConversationMember(aliceData.accountId_, convId, bobData.userName_);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
DRing::acceptConversationRequest(bobData.accountId_, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; }));
// Assert that repository exists
auto repoPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + bobData.accountId_
+ DIR_SEPARATOR_STR + "conversations" + DIR_SEPARATOR_STR + convId;
CPPUNIT_ASSERT(fileutils::isDirectory(repoPath));
// Wait that alice sees Bob
cv.wait_for(lk, 30s, [&]() { return messageAliceReceived == 2; });
auto chatHandlers = Manager::instance().getJamiPluginManager().getChatServicesManager().getChatHandlers();
for (auto handler : chatHandlers)
{
auto details = Manager::instance().getJamiPluginManager().getChatServicesManager().getChatHandlerDetails(handler);
// check details expected for the test plugin
if(std::find(chatHandlers_.begin(),
chatHandlers_.end(),
details["name"])
!= chatHandlers_.end()) {
Manager::instance().getJamiPluginManager().getChatServicesManager().toggleChatHandler(handler, aliceData.accountId_, convId, true);
auto statusMap = Manager::instance().getJamiPluginManager().getChatServicesManager().getChatHandlerStatus(aliceData.accountId_, convId);
CPPUNIT_ASSERT(std::find(statusMap.begin(), statusMap.end(), handler) != statusMap.end());
DRing::sendMessage(aliceData.accountId_, convId, "hi"s, "");
cv.wait_for(lk, 30s, [&]() { return messageBobReceived == 1; });
Manager::instance().getJamiPluginManager().getChatServicesManager().toggleChatHandler(handler, aliceData.accountId_, convId, false);
statusMap = Manager::instance().getJamiPluginManager().getChatServicesManager().getChatHandlerStatus(aliceData.accountId_, convId);
CPPUNIT_ASSERT(std::find(statusMap.begin(), statusMap.end(), handler) == statusMap.end());
}
}
CPPUNIT_ASSERT(!Manager::instance().getJamiPluginManager().uninstallPlugin(installationPath_));
}
} // namespace test
} // namespace jami
RING_TEST_RUNNER(jami::test::PluginsTest::name())
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment